mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-03-09 23:14:46 +01:00
gl: Clean up the awful image copy API
- Wrap everything in rsx::io_buffer and gl::buffer to avoid out of bounds issues. - Also abstracts away nasty things like OpenGL offset pointer casts.
This commit is contained in:
parent
ac30feeddb
commit
14789b536f
|
|
@ -9,7 +9,7 @@ namespace rsx
|
|||
template <typename T>
|
||||
concept SpanLike = requires(T t)
|
||||
{
|
||||
{ t.data() } -> std::convertible_to<void*>;
|
||||
{ t.data() } -> std::convertible_to<const void*>;
|
||||
{ t.size_bytes() } -> std::convertible_to<usz>;
|
||||
};
|
||||
|
||||
|
|
@ -71,9 +71,10 @@ namespace rsx
|
|||
return static_cast<T*>(m_ptr);
|
||||
}
|
||||
|
||||
usz size() const
|
||||
template <Integral T = usz>
|
||||
T size() const
|
||||
{
|
||||
return m_size;
|
||||
return static_cast<T>(m_size);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
|
|
|||
|
|
@ -249,22 +249,23 @@ void GLGSRender::on_init_thread()
|
|||
// Fallback null texture instead of relying on texture0
|
||||
{
|
||||
std::array<u32, 8> pixeldata = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
const rsx::io_buffer src_buf = std::span<u32>(pixeldata);
|
||||
|
||||
// 1D
|
||||
auto tex1D = std::make_unique<gl::texture>(GL_TEXTURE_1D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
|
||||
tex1D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
tex1D->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
|
||||
// 2D
|
||||
auto tex2D = std::make_unique<gl::texture>(GL_TEXTURE_2D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
|
||||
tex2D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
tex2D->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
|
||||
// 3D
|
||||
auto tex3D = std::make_unique<gl::texture>(GL_TEXTURE_3D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
|
||||
tex3D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
tex3D->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
|
||||
// CUBE
|
||||
auto texCUBE = std::make_unique<gl::texture>(GL_TEXTURE_CUBE_MAP, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
|
||||
texCUBE->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
texCUBE->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
|
||||
m_null_textures[GL_TEXTURE_1D] = std::move(tex1D);
|
||||
m_null_textures[GL_TEXTURE_2D] = std::move(tex2D);
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ namespace gl
|
|||
gl::texture_view* ui_overlay_renderer::load_simple_image(rsx::overlays::image_info_base* desc, bool temp_resource, u32 owner_uid)
|
||||
{
|
||||
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D, desc->w, desc->h, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
|
||||
tex->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
tex->copy_from(desc->as_span(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
|
||||
const GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN };
|
||||
auto view = std::make_unique<gl::texture_view>(tex.get(), remap);
|
||||
|
|
@ -308,7 +308,7 @@ namespace gl
|
|||
const std::vector<u8>& glyph_data = font->get_glyph_data();
|
||||
|
||||
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D_ARRAY, font_size.width, font_size.height, font_size.depth, 1, 1, GL_R8, RSX_FORMAT_CLASS_COLOR);
|
||||
tex->copy_from(glyph_data.data(), gl::texture::format::r, gl::texture::type::ubyte, {});
|
||||
tex->copy_from(std::span<const u8>(glyph_data), gl::texture::format::r, gl::texture::type::ubyte, {});
|
||||
|
||||
GLenum remap[] = { GL_RED, GL_RED, GL_RED, GL_RED };
|
||||
auto view = std::make_unique<gl::texture_view>(tex.get(), remap);
|
||||
|
|
@ -332,7 +332,7 @@ namespace gl
|
|||
|
||||
if (dirty)
|
||||
{
|
||||
view->image()->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
view->image()->copy_from(desc->as_span(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||
}
|
||||
|
||||
return view;
|
||||
|
|
|
|||
|
|
@ -132,7 +132,8 @@ gl::texture* GLGSRender::get_present_source(gl::present_surface_info* info, cons
|
|||
const auto range = utils::address_range32::start_length(info->address, info->pitch * info->height);
|
||||
m_gl_texture_cache.invalidate_range(cmd, range, rsx::invalidation_cause::read);
|
||||
|
||||
flip_image->copy_from(vm::base(info->address), static_cast<gl::texture::format>(expected_format), gl::texture::type::uint_8_8_8_8, unpack_settings);
|
||||
const rsx::io_buffer read_buf = { vm::base(info->address), range.length() };
|
||||
flip_image->copy_from(read_buf, static_cast<gl::texture::format>(expected_format), gl::texture::type::uint_8_8_8_8, unpack_settings);
|
||||
image = flip_image.get();
|
||||
}
|
||||
else if (image->get_internal_format() != static_cast<gl::texture::internal_format>(expected_format))
|
||||
|
|
@ -368,7 +369,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
|
|||
std::vector<u8> sshot_frame(buffer_height * buffer_width * 4);
|
||||
glGetError();
|
||||
|
||||
tex->copy_to(sshot_frame.data(), gl::texture::format::rgba, gl::texture::type::ubyte, pack_settings);
|
||||
tex->copy_to(std::span<const u8>(sshot_frame), gl::texture::format::rgba, gl::texture::type::ubyte, pack_settings);
|
||||
|
||||
m_sshot_tex.reset();
|
||||
|
||||
|
|
|
|||
|
|
@ -363,8 +363,7 @@ namespace gl
|
|||
}
|
||||
}
|
||||
|
||||
dst->bind(buffer::target::pixel_pack);
|
||||
src->copy_to(reinterpret_cast<void*>(static_cast<uintptr_t>(dst_offset)), static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), src_level, src_region, {});
|
||||
src->copy_to(*dst, dst_offset, static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), src_level, src_region, {});
|
||||
return false;
|
||||
};
|
||||
|
||||
|
|
@ -611,9 +610,8 @@ namespace gl
|
|||
}
|
||||
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, GL_NONE);
|
||||
transfer_buf->bind(buffer::target::pixel_unpack);
|
||||
|
||||
dst->copy_from(reinterpret_cast<void*>(u64(out_offset)), static_cast<texture::format>(unpack_info.format),
|
||||
dst->copy_from(*transfer_buf, out_offset, static_cast<texture::format>(unpack_info.format),
|
||||
static_cast<texture::type>(unpack_info.type), dst_level, dst_region, {});
|
||||
}
|
||||
}
|
||||
|
|
@ -712,7 +710,6 @@ namespace gl
|
|||
pixel_buffer_layout mem_layout;
|
||||
|
||||
std::span<std::byte> dst_buffer = staging_buffer;
|
||||
void* out_pointer = staging_buffer.data();
|
||||
u8 block_size_in_bytes = rsx::get_format_block_size_in_bytes(format);
|
||||
u64 image_linear_size = staging_buffer.size();
|
||||
|
||||
|
|
@ -731,8 +728,6 @@ namespace gl
|
|||
g_compute_decode_buffer.remove();
|
||||
g_compute_decode_buffer.create(gl::buffer::target::ssbo, min_required_buffer_size);
|
||||
}
|
||||
|
||||
out_pointer = nullptr;
|
||||
}
|
||||
|
||||
for (const rsx::subresource_layout& layout : input_layouts)
|
||||
|
|
@ -867,7 +862,7 @@ namespace gl
|
|||
else
|
||||
{
|
||||
unpack_settings.swap_bytes(op.require_swap);
|
||||
dst->copy_from(out_pointer, static_cast<texture::format>(gl_format), static_cast<texture::type>(gl_type), layout.level, region, unpack_settings);
|
||||
dst->copy_from(staging_buffer, static_cast<texture::format>(gl_format), static_cast<texture::type>(gl_type), layout.level, region, unpack_settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1156,9 +1151,7 @@ namespace gl
|
|||
// Start pack operation
|
||||
pixel_pack_settings pack_settings{};
|
||||
pack_settings.swap_bytes(pack_info.swap_bytes);
|
||||
|
||||
g_typeless_transfer_buffer.get().bind(buffer::target::pixel_pack);
|
||||
src->copy_to(nullptr, static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), 0, src_region, pack_settings);
|
||||
src->copy_to(g_typeless_transfer_buffer.get(), 0, static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), 0, src_region, pack_settings);
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);
|
||||
|
||||
|
|
@ -1166,8 +1159,7 @@ namespace gl
|
|||
pixel_unpack_settings unpack_settings{};
|
||||
unpack_settings.swap_bytes(unpack_info.swap_bytes);
|
||||
|
||||
g_typeless_transfer_buffer.get().bind(buffer::target::pixel_unpack);
|
||||
dst->copy_from(nullptr, static_cast<texture::format>(unpack_info.format), static_cast<texture::type>(unpack_info.type), 0, dst_region, unpack_settings);
|
||||
dst->copy_from(g_typeless_transfer_buffer.get(), 0, static_cast<texture::format>(unpack_info.format), static_cast<texture::type>(unpack_info.type), 0, dst_region, unpack_settings);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, GL_NONE);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,13 +233,11 @@ namespace gl
|
|||
pack_unpack_swap_bytes = false;
|
||||
}
|
||||
|
||||
pbo.bind(buffer::target::pixel_pack);
|
||||
|
||||
pixel_pack_settings pack_settings;
|
||||
pack_settings.alignment(1);
|
||||
pack_settings.swap_bytes(pack_unpack_swap_bytes);
|
||||
|
||||
src->copy_to(reinterpret_cast<void*>(pbo_offset), format, type, 0, src_rgn, pack_settings);
|
||||
src->copy_to(pbo, pbo_offset, format, type, 0, src_rgn, pack_settings);
|
||||
}
|
||||
|
||||
if (auto error = glGetError())
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ namespace gl
|
|||
m_id = GL_NONE;
|
||||
}
|
||||
|
||||
void texture::copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
|
||||
void texture::copy_from(const rsx::io_buffer& src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
|
||||
{
|
||||
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
|
||||
|
||||
|
|
@ -185,30 +185,30 @@ namespace gl
|
|||
{
|
||||
case GL_TEXTURE_1D:
|
||||
{
|
||||
DSA_CALL(TextureSubImage1D, m_id, GL_TEXTURE_1D, level, region.x, region.width, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
DSA_CALL(TextureSubImage1D, m_id, GL_TEXTURE_1D, level, region.x, region.width, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_2D:
|
||||
{
|
||||
DSA_CALL(TextureSubImage2D, m_id, GL_TEXTURE_2D, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
DSA_CALL(TextureSubImage2D, m_id, GL_TEXTURE_2D, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_3D:
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
{
|
||||
DSA_CALL(TextureSubImage3D, m_id, target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
DSA_CALL(TextureSubImage3D, m_id, target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
{
|
||||
if (get_driver_caps().ARB_direct_state_access_supported)
|
||||
{
|
||||
glTextureSubImage3D(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
glTextureSubImage3D(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
rsx_log.warning("Cubemap upload via texture::copy_from is halfplemented!");
|
||||
auto ptr = static_cast<const u8*>(src);
|
||||
auto ptr = static_cast<const u8*>(src.data());
|
||||
const auto end = std::min(6u, region.z + region.depth);
|
||||
for (unsigned face = region.z; face < end; ++face)
|
||||
{
|
||||
|
|
@ -221,22 +221,25 @@ namespace gl
|
|||
}
|
||||
}
|
||||
|
||||
void texture::copy_from(buffer& buf, u32 gl_format_type, u32 offset, u32 length)
|
||||
void texture::copy_from(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
|
||||
{
|
||||
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
|
||||
|
||||
if (get_target() != target::textureBuffer)
|
||||
fmt::throw_exception("OpenGL error: texture cannot copy from buffer");
|
||||
buf.bind(buffer::target::pixel_unpack);
|
||||
|
||||
DSA_CALL(TextureBufferRange, m_id, GL_TEXTURE_BUFFER, gl_format_type, buf.id(), offset, length);
|
||||
const rsx::io_buffer src{ reinterpret_cast<void*>(static_cast<uintptr_t>(offset)), buf.size() - offset };
|
||||
copy_from(src, format, type, level, region, pixel_settings);
|
||||
}
|
||||
|
||||
void texture::copy_from(buffer_view& view)
|
||||
{
|
||||
copy_from(*view.value(), view.format(), view.offset(), view.range());
|
||||
if (get_target() != target::textureBuffer)
|
||||
fmt::throw_exception("OpenGL error: texture cannot copy from buffer");
|
||||
|
||||
DSA_CALL(TextureBufferRange, m_id, GL_TEXTURE_BUFFER, view.format(), view.value()->id(), view.offset(), view.range());
|
||||
}
|
||||
|
||||
void texture::copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
|
||||
void texture::copy_to(const rsx::io_buffer& dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
|
||||
{
|
||||
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
|
||||
|
||||
|
|
@ -247,14 +250,14 @@ namespace gl
|
|||
region.width == m_width && region.height == m_height && region.depth == m_depth)
|
||||
{
|
||||
if (caps.ARB_direct_state_access_supported)
|
||||
glGetTextureImage(m_id, level, static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst);
|
||||
glGetTextureImage(m_id, level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst.size<GLsizei>(), dst.data());
|
||||
else
|
||||
glGetTextureImageEXT(m_id, static_cast<GLenum>(m_target), level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst);
|
||||
glGetTextureImageEXT(m_id, static_cast<GLenum>(m_target), level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst.data());
|
||||
}
|
||||
else if (caps.ARB_direct_state_access_supported)
|
||||
{
|
||||
glGetTextureSubImage(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth,
|
||||
static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst);
|
||||
static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -269,6 +272,16 @@ namespace gl
|
|||
}
|
||||
}
|
||||
|
||||
void texture::copy_to(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
|
||||
{
|
||||
ensure(offset < buf.size(), "PBO write is out of range");
|
||||
|
||||
buf.bind(buffer::target::pixel_pack);
|
||||
|
||||
const rsx::io_buffer dst{ reinterpret_cast<void*>(static_cast<uintptr_t>(offset)), buf.size() - offset };
|
||||
copy_to(dst, format, type, level, region, pixel_settings);
|
||||
}
|
||||
|
||||
void texture_view::create(texture* data, GLenum target, GLenum sized_format, const subresource_range& range, const GLenum* argb_swizzle)
|
||||
{
|
||||
m_target = target;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "Utilities/geometry.h"
|
||||
#include "Emu/RSX/Common/TextureUtils.h"
|
||||
#include "Emu/RSX/Common/io_buffer.h"
|
||||
|
||||
//using enum rsx::format_class;
|
||||
using namespace ::rsx::format_class_;
|
||||
|
|
@ -321,22 +322,24 @@ namespace gl
|
|||
}
|
||||
|
||||
// Data management
|
||||
void copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings);
|
||||
void copy_from(const rsx::io_buffer& src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings);
|
||||
|
||||
void copy_from(buffer& buf, u32 gl_format_type, u32 offset, u32 length);
|
||||
void copy_from(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings);
|
||||
|
||||
void copy_from(buffer_view& view);
|
||||
|
||||
void copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const;
|
||||
void copy_to(const rsx::io_buffer& dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const;
|
||||
|
||||
void copy_to(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const;
|
||||
|
||||
// Convenience wrappers
|
||||
void copy_from(const void* src, texture::format format, texture::type type, const pixel_unpack_settings& pixel_settings)
|
||||
void copy_from(const rsx::io_buffer& src, texture::format format, texture::type type, const pixel_unpack_settings& pixel_settings)
|
||||
{
|
||||
const coord3u region = { {}, size3D() };
|
||||
copy_from(src, format, type, 0, region, pixel_settings);
|
||||
}
|
||||
|
||||
void copy_to(void* dst, texture::format format, texture::type type, const pixel_pack_settings& pixel_settings) const
|
||||
void copy_to(const rsx::io_buffer& dst, texture::format format, texture::type type, const pixel_pack_settings& pixel_settings) const
|
||||
{
|
||||
const coord3u region = { {}, size3D() };
|
||||
copy_to(dst, format, type, 0, region, pixel_settings);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "Emu/localized_string.h"
|
||||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
|
||||
// Definitions for common UI controls and their routines
|
||||
namespace rsx
|
||||
|
|
@ -39,6 +40,9 @@ namespace rsx
|
|||
image_info_base() {}
|
||||
virtual ~image_info_base() {}
|
||||
virtual const u8* get_data() const = 0;
|
||||
virtual usz size_bytes() const { return static_cast<usz>(w * h * bpp); }
|
||||
|
||||
std::span<const u8> as_span() const { return { get_data(), size_bytes() }; }
|
||||
};
|
||||
|
||||
struct image_info : public image_info_base
|
||||
|
|
@ -56,6 +60,7 @@ namespace rsx
|
|||
|
||||
void load_data(const std::vector<u8>& bytes, bool grayscaled = false);
|
||||
const u8* get_data() const override { return channels == 4 ? data : data_grey.empty() ? nullptr : data_grey.data(); }
|
||||
usz size_bytes() const override { return data_grey.size(); }
|
||||
};
|
||||
|
||||
struct resource_config
|
||||
|
|
|
|||
Loading…
Reference in a new issue