1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-23 03:02:53 +01:00

gl: Handle corner cases for CopyBufferToImage

- Handle 3D textures and cubemaps
- Handle writing to mip > 0
This commit is contained in:
kd-11 2022-06-20 23:03:23 +03:00 committed by kd-11
parent f948ce399e
commit bb5ce67d57
7 changed files with 179 additions and 47 deletions

View File

@ -1,5 +1,7 @@
#include "GLOverlays.h"
#include "../rsx_utils.h"
namespace gl
{
// Lame
@ -615,20 +617,29 @@ namespace gl
}
void rp_ssbo_to_texture::run(gl::command_context& cmd,
const buffer* src, const texture* dst,
const buffer* src, const texture_view* dst,
const u32 src_offset, const coordu& dst_region,
const pixel_buffer_layout& layout)
{
const u32 row_length = static_cast<u32>(dst_region.width);
const u32 bpp = dst->pitch() / dst->width();
const u32 bpp = dst->image()->pitch() / dst->image()->width();
program_handle.uniforms["src_pitch"] = row_length;
program_handle.uniforms["swap_bytes"] = layout.swap_bytes;
program_handle.uniforms["format"] = static_cast<GLenum>(dst->get_internal_format());
program_handle.uniforms["format"] = static_cast<GLenum>(dst->image()->get_internal_format());
src->bind_range(gl::buffer::target::ssbo, GL_COMPUTE_BUFFER_SLOT(0), src_offset, row_length * bpp * dst_region.height);
cmd->stencil_mask(0xFF);
overlay_pass::run(cmd, dst_region, dst->id(), dst->aspect());
}
void rp_ssbo_to_texture::run(gl::command_context& cmd,
const buffer* src, texture* dst,
const u32 src_offset, const coordu& dst_region,
const pixel_buffer_layout& layout)
{
gl::nil_texture_view view(dst);
run(cmd, src, &view, src_offset, dst_region, layout);
}
}

View File

@ -117,7 +117,8 @@ namespace gl
struct rp_ssbo_to_texture : public overlay_pass
{
rp_ssbo_to_texture();
void run(gl::command_context& cmd, const buffer* src, const texture* dst, const u32 src_offset, const coordu& dst_region, const pixel_buffer_layout& layout);
void run(gl::command_context& cmd, const buffer* src, texture* dst, const u32 src_offset, const coordu& dst_region, const pixel_buffer_layout& layout);
void run(gl::command_context& cmd, const buffer* src, const texture_view* dst, const u32 src_offset, const coordu& dst_region, const pixel_buffer_layout& layout);
};
// TODO: Replace with a proper manager

View File

@ -4,6 +4,7 @@
#include "GLRenderTargets.h"
#include "GLOverlays.h"
#include "glutils/blitter.h"
#include "glutils/ring_buffer.h"
#include "../GCM.h"
@ -581,11 +582,67 @@ namespace gl
};
const auto caps = gl::get_driver_caps();
if (!(dst->aspect() & image_aspect::stencil) || caps.ARB_shader_stencil_export_supported)
if (dst->get_target() != gl::texture::target::texture1D &&
(!(dst->aspect() & image_aspect::stencil) || caps.ARB_shader_stencil_export_supported))
{
// We do not need to use the driver's builtin transport mechanism
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
gl::get_overlay_pass<gl::rp_ssbo_to_texture>()->run(cmd, transfer_buf, dst, out_offset, { {dst_region.x, dst_region.y}, {dst_region.width, dst_region.height} }, unpack_info);
std::unique_ptr<gl::texture> scratch;
std::unique_ptr<gl::texture_view> scratch_view;
coordu image_region = { {dst_region.x, dst_region.y}, {dst_region.width, dst_region.height} };
switch (dst->get_target())
{
case texture::target::texture3D:
{
// Upload to splatted image and do the final copy GPU-side
image_region.height *= dst_region.depth;
scratch = std::make_unique<gl::texture>(
GL_TEXTURE_2D,
image_region.x + image_region.width, image_region.y + image_region.height, 1, 1,
static_cast<GLenum>(dst->get_internal_format()), dst->format_class());
scratch_view = std::make_unique<gl::nil_texture_view>(scratch.get());
break;
}
case texture::target::textureCUBE:
{
const subresource_range range = { image_aspect::depth | image_aspect::color, dst_level, 1, dst_region.z , 1 };
scratch_view = std::make_unique<gl::texture_view>(dst, GL_TEXTURE_2D, range);
break;
}
default:
{
ensure(dst->layers() == 1);
if (dst->levels() > 1) [[ likely ]]
{
const subresource_range range = { image_aspect::depth | image_aspect::color, dst_level, 1, 0 , 1 };
scratch_view = std::make_unique<gl::texture_view>(dst, GL_TEXTURE_2D, range);
}
else
{
scratch_view = std::make_unique<gl::nil_texture_view>(dst);
}
break;
}
}
gl::get_overlay_pass<gl::rp_ssbo_to_texture>()->run(cmd, transfer_buf, scratch_view.get(), out_offset, image_region, unpack_info);
if (dst->get_target() == texture::target::texture3D)
{
// Memcpy
for (u32 layer = dst_region.z, i = 0; i < dst_region.depth; ++i, ++layer)
{
const position3u src_offset = { dst_region.position.x, dst_region.position.y, 0 };
const position3u dst_offset = { dst_region.position.x, dst_region.position.y, layer };
g_hw_blitter->copy_image(cmd, scratch.get(), dst, 0, dst_level, src_offset, dst_offset, {dst_region.width, dst_region.height, 1});
}
}
}
else
{

View File

@ -13,10 +13,6 @@ class GLGSRender;
namespace gl
{
class blitter;
extern blitter* g_hw_blitter;
class cached_texture_section;
class texture_cache;

View File

@ -55,4 +55,6 @@ namespace gl
copy_image(cmd, src, dst, src_level, dst_level, static_cast<position3i>(src_offset), static_cast<position3i>(dst_offset), static_cast<size3i>(size));
}
};
extern blitter* g_hw_blitter;
}

View File

@ -232,26 +232,17 @@ namespace gl
}
}
void texture_view::create(texture* data, GLenum target, GLenum sized_format, GLuint min_level, GLuint num_levels, GLenum aspect_flags, const GLenum* argb_swizzle)
void texture_view::create(texture* data, GLenum target, GLenum sized_format, const subresource_range& range, const GLenum* argb_swizzle)
{
m_target = target;
m_format = sizedfmt_to_ifmt(sized_format);
m_image_data = data;
m_aspect_flags = aspect_flags;
m_aspect_flags = range.aspect_mask & data->aspect();
u32 num_layers;
switch (target)
{
default:
num_layers = 1; break;
case GL_TEXTURE_CUBE_MAP:
num_layers = 6; break;
case GL_TEXTURE_2D_ARRAY:
num_layers = data->depth(); break;
}
ensure(m_aspect_flags);
glGenTextures(1, &m_id);
glTextureView(m_id, target, data->id(), m_format, min_level, num_levels, 0, num_layers);
glTextureView(m_id, target, data->id(), m_format, range.min_level, range.num_levels, range.min_layer, range.num_layers);
if (argb_swizzle)
{
@ -271,10 +262,10 @@ namespace gl
component_swizzle[3] = GL_ALPHA;
}
if (aspect_flags & image_aspect::stencil)
if (range.aspect_mask & image_aspect::stencil)
{
constexpr u32 depth_stencil_mask = (image_aspect::depth | image_aspect::stencil);
ensure((aspect_flags & depth_stencil_mask) != depth_stencil_mask); // "Invalid aspect mask combination"
ensure((range.aspect_mask & depth_stencil_mask) != depth_stencil_mask); // "Invalid aspect mask combination"
gl::get_command_context()->bind_texture(GL_TEMP_IMAGE_SLOT, m_target, m_id);
glTexParameteri(m_target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
@ -283,9 +274,12 @@ namespace gl
texture_view::~texture_view()
{
gl::get_command_context()->unbind_texture(static_cast<GLenum>(m_target), m_id);
glDeleteTextures(1, &m_id);
m_id = GL_NONE;
if (m_id)
{
gl::get_command_context()->unbind_texture(static_cast<GLenum>(m_target), m_id);
glDeleteTextures(1, &m_id);
m_id = GL_NONE;
}
}
void texture_view::bind(gl::command_context& cmd, GLuint layer) const
@ -295,20 +289,29 @@ namespace gl
texture_view* viewable_image::get_view(u32 remap_encoding, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap, GLenum aspect_flags)
{
auto found = views.equal_range(remap_encoding);
for (auto It = found.first; It != found.second; ++It)
const u64 view_aspect = static_cast<u64>(aspect_flags) & aspect();
ensure(view_aspect);
const u64 key = static_cast<u64>(remap_encoding) | (view_aspect << 32);
if (auto found = views.find(key);
found != views.end())
{
if (It->second->aspect() & aspect_flags)
{
return It->second.get();
}
ensure(found->second.get() != nullptr);
return found->second.get();
}
ensure(aspect() & aspect_flags);
auto mapping = apply_swizzle_remap(get_native_component_layout(), remap);
auto view = std::make_unique<texture_view>(this, mapping.data(), aspect_flags);
std::array<GLenum, 4> mapping;
GLenum* swizzle = nullptr;
if (remap_encoding != GL_REMAP_IDENTITY)
{
mapping = apply_swizzle_remap(get_native_component_layout(), remap);
swizzle = mapping.data();
}
auto view = std::make_unique<texture_view>(this, swizzle, aspect_flags);
auto result = view.get();
views.emplace(remap_encoding, std::move(view));
views.emplace(key, std::move(view));
return result;
}

View File

@ -42,6 +42,20 @@ namespace gl
linear_mipmap_linear = GL_LINEAR_MIPMAP_LINEAR
};
enum remap_constants : u32
{
GL_REMAP_IDENTITY = 0xCAFEBABE
};
struct subresource_range
{
GLenum aspect_mask;
GLuint min_level;
GLuint num_levels;
GLuint min_layer;
GLuint num_layers;
};
class texture
{
friend class texture_view;
@ -158,7 +172,8 @@ namespace gl
texture2D = GL_TEXTURE_2D,
texture3D = GL_TEXTURE_3D,
textureCUBE = GL_TEXTURE_CUBE_MAP,
textureBuffer = GL_TEXTURE_BUFFER
textureBuffer = GL_TEXTURE_BUFFER,
texture2DArray = GL_TEXTURE_2D_ARRAY
};
protected:
@ -242,6 +257,19 @@ namespace gl
return m_mipmaps;
}
GLuint layers() const
{
switch (m_target)
{
case target::textureCUBE:
return 6;
case target::texture2DArray:
return m_depth;
default:
return 1;
}
}
GLuint pitch() const
{
return m_pitch;
@ -313,6 +341,7 @@ namespace gl
class texture_view
{
protected:
GLuint m_id = GL_NONE;
GLenum m_target = 0;
GLenum m_format = 0;
@ -321,7 +350,9 @@ namespace gl
GLenum component_swizzle[4];
void create(texture* data, GLenum target, GLenum sized_format, GLuint min_level, GLuint num_levels, GLenum aspect_flags, const GLenum* argb_swizzle = nullptr);
texture_view() = default;
void create(texture* data, GLenum target, GLenum sized_format, const subresource_range& range, const GLenum* argb_swizzle = nullptr);
public:
texture_view(const texture_view&) = delete;
@ -331,7 +362,7 @@ namespace gl
const GLenum* argb_swizzle = nullptr,
GLenum aspect_flags = image_aspect::color | image_aspect::depth)
{
create(data, target, sized_format, 0, data->levels(), aspect_flags, argb_swizzle);
create(data, target, sized_format, { aspect_flags, 0, data->levels(), 0, data->layers() }, argb_swizzle);
}
texture_view(texture* data, const GLenum* argb_swizzle = nullptr,
@ -339,16 +370,22 @@ namespace gl
{
GLenum target = static_cast<GLenum>(data->get_target());
GLenum sized_format = static_cast<GLenum>(data->get_internal_format());
create(data, target, sized_format, 0, data->levels(), aspect_flags, argb_swizzle);
create(data, target, sized_format, { aspect_flags, 0, data->levels(), 0, data->layers() }, argb_swizzle);
}
texture_view(texture* data, GLuint mip_level,
const GLenum* argb_swizzle = nullptr,
GLenum aspect_flags = image_aspect::color | image_aspect::depth)
texture_view(texture* data, const subresource_range& range,
const GLenum* argb_swizzle = nullptr)
{
GLenum target = static_cast<GLenum>(data->get_target());
GLenum sized_format = static_cast<GLenum>(data->get_internal_format());
create(data, target, sized_format, mip_level, 1, aspect_flags, argb_swizzle);
create(data, target, sized_format, range, argb_swizzle);
}
texture_view(texture* data, GLenum target, const subresource_range& range,
const GLenum* argb_swizzle = nullptr)
{
GLenum sized_format = static_cast<GLenum>(data->get_internal_format());
create(data, target, sized_format, range, argb_swizzle);
}
virtual ~texture_view();
@ -400,9 +437,34 @@ namespace gl
void bind(gl::command_context& cmd, GLuint layer) const;
};
// Passthrough texture view that simply wraps the original texture in a texture_view interface
class nil_texture_view : public texture_view
{
public:
nil_texture_view(texture* data)
: texture_view()
{
m_id = data->id();
m_target = static_cast<GLenum>(data->get_target());
m_format = static_cast<GLenum>(data->get_internal_format());
m_aspect_flags = data->aspect();
m_image_data = data;
component_swizzle[0] = GL_RED;
component_swizzle[1] = GL_GREEN;
component_swizzle[2] = GL_BLUE;
component_swizzle[3] = GL_ALPHA;
}
~nil_texture_view()
{
m_id = GL_NONE;
}
};
class viewable_image : public texture
{
std::unordered_multimap<u32, std::unique_ptr<texture_view>> views;
std::unordered_map<u64, std::unique_ptr<texture_view>> views;
public:
using texture::texture;