mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-22 03:40:30 +00: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 "GLOverlays.h"
|
||||||
|
|
||||||
|
#include "../rsx_utils.h"
|
||||||
|
|
||||||
namespace gl
|
namespace gl
|
||||||
{
|
{
|
||||||
// Lame
|
// Lame
|
||||||
@ -615,20 +617,29 @@ namespace gl
|
|||||||
}
|
}
|
||||||
|
|
||||||
void rp_ssbo_to_texture::run(gl::command_context& cmd,
|
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 u32 src_offset, const coordu& dst_region,
|
||||||
const pixel_buffer_layout& layout)
|
const pixel_buffer_layout& layout)
|
||||||
{
|
{
|
||||||
const u32 row_length = static_cast<u32>(dst_region.width);
|
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["src_pitch"] = row_length;
|
||||||
program_handle.uniforms["swap_bytes"] = layout.swap_bytes;
|
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);
|
src->bind_range(gl::buffer::target::ssbo, GL_COMPUTE_BUFFER_SLOT(0), src_offset, row_length * bpp * dst_region.height);
|
||||||
|
|
||||||
cmd->stencil_mask(0xFF);
|
cmd->stencil_mask(0xFF);
|
||||||
|
|
||||||
overlay_pass::run(cmd, dst_region, dst->id(), dst->aspect());
|
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
|
struct rp_ssbo_to_texture : public overlay_pass
|
||||||
{
|
{
|
||||||
rp_ssbo_to_texture();
|
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
|
// TODO: Replace with a proper manager
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "GLRenderTargets.h"
|
#include "GLRenderTargets.h"
|
||||||
#include "GLOverlays.h"
|
#include "GLOverlays.h"
|
||||||
|
|
||||||
|
#include "glutils/blitter.h"
|
||||||
#include "glutils/ring_buffer.h"
|
#include "glutils/ring_buffer.h"
|
||||||
|
|
||||||
#include "../GCM.h"
|
#include "../GCM.h"
|
||||||
@ -581,11 +582,67 @@ namespace gl
|
|||||||
};
|
};
|
||||||
|
|
||||||
const auto caps = gl::get_driver_caps();
|
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
|
// We do not need to use the driver's builtin transport mechanism
|
||||||
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -13,10 +13,6 @@ class GLGSRender;
|
|||||||
|
|
||||||
namespace gl
|
namespace gl
|
||||||
{
|
{
|
||||||
class blitter;
|
|
||||||
|
|
||||||
extern blitter* g_hw_blitter;
|
|
||||||
|
|
||||||
class cached_texture_section;
|
class cached_texture_section;
|
||||||
class texture_cache;
|
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));
|
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_target = target;
|
||||||
m_format = sizedfmt_to_ifmt(sized_format);
|
m_format = sizedfmt_to_ifmt(sized_format);
|
||||||
m_image_data = data;
|
m_image_data = data;
|
||||||
m_aspect_flags = aspect_flags;
|
m_aspect_flags = range.aspect_mask & data->aspect();
|
||||||
|
|
||||||
u32 num_layers;
|
ensure(m_aspect_flags);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
glGenTextures(1, &m_id);
|
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)
|
if (argb_swizzle)
|
||||||
{
|
{
|
||||||
@ -271,10 +262,10 @@ namespace gl
|
|||||||
component_swizzle[3] = GL_ALPHA;
|
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);
|
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);
|
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);
|
glTexParameteri(m_target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
|
||||||
@ -283,9 +274,12 @@ namespace gl
|
|||||||
|
|
||||||
texture_view::~texture_view()
|
texture_view::~texture_view()
|
||||||
{
|
{
|
||||||
gl::get_command_context()->unbind_texture(static_cast<GLenum>(m_target), m_id);
|
if (m_id)
|
||||||
glDeleteTextures(1, &m_id);
|
{
|
||||||
m_id = GL_NONE;
|
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
|
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)
|
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);
|
const u64 view_aspect = static_cast<u64>(aspect_flags) & aspect();
|
||||||
for (auto It = found.first; It != found.second; ++It)
|
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)
|
ensure(found->second.get() != nullptr);
|
||||||
{
|
return found->second.get();
|
||||||
return It->second.get();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure(aspect() & aspect_flags);
|
std::array<GLenum, 4> mapping;
|
||||||
auto mapping = apply_swizzle_remap(get_native_component_layout(), remap);
|
GLenum* swizzle = nullptr;
|
||||||
auto view = std::make_unique<texture_view>(this, mapping.data(), aspect_flags);
|
|
||||||
|
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();
|
auto result = view.get();
|
||||||
views.emplace(remap_encoding, std::move(view));
|
views.emplace(key, std::move(view));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,20 @@ namespace gl
|
|||||||
linear_mipmap_linear = GL_LINEAR_MIPMAP_LINEAR
|
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
|
class texture
|
||||||
{
|
{
|
||||||
friend class texture_view;
|
friend class texture_view;
|
||||||
@ -158,7 +172,8 @@ namespace gl
|
|||||||
texture2D = GL_TEXTURE_2D,
|
texture2D = GL_TEXTURE_2D,
|
||||||
texture3D = GL_TEXTURE_3D,
|
texture3D = GL_TEXTURE_3D,
|
||||||
textureCUBE = GL_TEXTURE_CUBE_MAP,
|
textureCUBE = GL_TEXTURE_CUBE_MAP,
|
||||||
textureBuffer = GL_TEXTURE_BUFFER
|
textureBuffer = GL_TEXTURE_BUFFER,
|
||||||
|
texture2DArray = GL_TEXTURE_2D_ARRAY
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -242,6 +257,19 @@ namespace gl
|
|||||||
return m_mipmaps;
|
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
|
GLuint pitch() const
|
||||||
{
|
{
|
||||||
return m_pitch;
|
return m_pitch;
|
||||||
@ -313,6 +341,7 @@ namespace gl
|
|||||||
|
|
||||||
class texture_view
|
class texture_view
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
GLuint m_id = GL_NONE;
|
GLuint m_id = GL_NONE;
|
||||||
GLenum m_target = 0;
|
GLenum m_target = 0;
|
||||||
GLenum m_format = 0;
|
GLenum m_format = 0;
|
||||||
@ -321,7 +350,9 @@ namespace gl
|
|||||||
|
|
||||||
GLenum component_swizzle[4];
|
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:
|
public:
|
||||||
texture_view(const texture_view&) = delete;
|
texture_view(const texture_view&) = delete;
|
||||||
@ -331,7 +362,7 @@ namespace gl
|
|||||||
const GLenum* argb_swizzle = nullptr,
|
const GLenum* argb_swizzle = nullptr,
|
||||||
GLenum aspect_flags = image_aspect::color | image_aspect::depth)
|
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,
|
texture_view(texture* data, const GLenum* argb_swizzle = nullptr,
|
||||||
@ -339,16 +370,22 @@ namespace gl
|
|||||||
{
|
{
|
||||||
GLenum target = static_cast<GLenum>(data->get_target());
|
GLenum target = static_cast<GLenum>(data->get_target());
|
||||||
GLenum sized_format = static_cast<GLenum>(data->get_internal_format());
|
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,
|
texture_view(texture* data, const subresource_range& range,
|
||||||
const GLenum* argb_swizzle = nullptr,
|
const GLenum* argb_swizzle = nullptr)
|
||||||
GLenum aspect_flags = image_aspect::color | image_aspect::depth)
|
|
||||||
{
|
{
|
||||||
GLenum target = static_cast<GLenum>(data->get_target());
|
GLenum target = static_cast<GLenum>(data->get_target());
|
||||||
GLenum sized_format = static_cast<GLenum>(data->get_internal_format());
|
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();
|
virtual ~texture_view();
|
||||||
@ -400,9 +437,34 @@ namespace gl
|
|||||||
void bind(gl::command_context& cmd, GLuint layer) const;
|
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
|
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:
|
public:
|
||||||
using texture::texture;
|
using texture::texture;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user