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:
parent
f948ce399e
commit
bb5ce67d57
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -13,10 +13,6 @@ class GLGSRender;
|
||||
|
||||
namespace gl
|
||||
{
|
||||
class blitter;
|
||||
|
||||
extern blitter* g_hw_blitter;
|
||||
|
||||
class cached_texture_section;
|
||||
class texture_cache;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
@ -282,11 +273,14 @@ namespace gl
|
||||
}
|
||||
|
||||
texture_view::~texture_view()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user