mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 11:36:13 +00:00
Implemented color texture reading/writing
Fixed region protection
This commit is contained in:
parent
18caf477c9
commit
c365004776
7 changed files with 468 additions and 153 deletions
|
@ -662,6 +662,8 @@ void GLGSRender::end()
|
|||
invalidate_buffers();
|
||||
|
||||
rsx::thread::end();
|
||||
|
||||
m_texture_cache.update_protection();
|
||||
}
|
||||
|
||||
void GLGSRender::set_viewport()
|
||||
|
@ -799,7 +801,15 @@ void nv4097_clear_surface(u32 arg, GLGSRender* renderer)
|
|||
{
|
||||
//LOG_NOTICE(Log::RSX, "nv4097_clear_surface(0x%x)", arg);
|
||||
|
||||
if ((arg & 0xf3) == 0)
|
||||
enum
|
||||
{
|
||||
depth = 1 << 0,
|
||||
stencil = 1 << 1,
|
||||
depth_stencil = depth | stencil,
|
||||
color_mask = 0xf0,
|
||||
};
|
||||
|
||||
if ((arg & (depth_stencil | color_mask)) == 0)
|
||||
{
|
||||
//do nothing
|
||||
return;
|
||||
|
@ -818,29 +828,45 @@ void nv4097_clear_surface(u32 arg, GLGSRender* renderer)
|
|||
|
||||
GLbitfield mask = 0;
|
||||
|
||||
if (arg & 0x1)
|
||||
if (arg & depth_stencil)
|
||||
{
|
||||
rsx::surface_depth_format surface_depth_format = rsx::to_surface_depth_format((rsx::method_registers[NV4097_SET_SURFACE_FORMAT] >> 5) & 0x7);
|
||||
u32 max_depth_value = get_max_depth_value(surface_depth_format);
|
||||
if (arg & depth)
|
||||
{
|
||||
rsx::surface_depth_format surface_depth_format = rsx::to_surface_depth_format((rsx::method_registers[NV4097_SET_SURFACE_FORMAT] >> 5) & 0x7);
|
||||
u32 max_depth_value = get_max_depth_value(surface_depth_format);
|
||||
|
||||
u32 clear_depth = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] >> 8;
|
||||
u32 clear_depth = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] >> 8;
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
glClearDepth(double(clear_depth) / max_depth_value);
|
||||
mask |= GLenum(gl::buffers::depth);
|
||||
glDepthMask(GL_TRUE);
|
||||
glClearDepth(double(clear_depth) / max_depth_value);
|
||||
mask |= GLenum(gl::buffers::depth);
|
||||
}
|
||||
|
||||
if (arg & stencil)
|
||||
{
|
||||
u8 clear_stencil = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] & 0xff;
|
||||
|
||||
__glcheck glStencilMask(rsx::method_registers[NV4097_SET_STENCIL_MASK]);
|
||||
glClearStencil(clear_stencil);
|
||||
|
||||
mask |= GLenum(gl::buffers::stencil);
|
||||
}
|
||||
|
||||
if (gl::cached_texture* texture = renderer->cached_depth_buffer)
|
||||
{
|
||||
if ((arg & depth_stencil) == depth_stencil)
|
||||
{
|
||||
texture->ignore(gl::cache_buffers::local);
|
||||
texture->invalidate(gl::cache_buffers::host);
|
||||
}
|
||||
else
|
||||
{
|
||||
texture->sync(gl::cache_buffers::local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (arg & 0x2)
|
||||
{
|
||||
u8 clear_stencil = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] & 0xff;
|
||||
|
||||
__glcheck glStencilMask(rsx::method_registers[NV4097_SET_STENCIL_MASK]);
|
||||
glClearStencil(clear_stencil);
|
||||
|
||||
mask |= GLenum(gl::buffers::stencil);
|
||||
}
|
||||
|
||||
if (arg & 0xf0)
|
||||
if (arg & color_mask)
|
||||
{
|
||||
u32 clear_color = rsx::method_registers[NV4097_SET_COLOR_CLEAR_VALUE];
|
||||
u8 clear_a = clear_color >> 24;
|
||||
|
@ -852,10 +878,27 @@ void nv4097_clear_surface(u32 arg, GLGSRender* renderer)
|
|||
glClearColor(clear_r / 255.f, clear_g / 255.f, clear_b / 255.f, clear_a / 255.f);
|
||||
|
||||
mask |= GLenum(gl::buffers::color);
|
||||
|
||||
rsx::for_each_active_color_surface([&](int index)
|
||||
{
|
||||
gl::cached_texture* texture = renderer->cached_color_buffers[index];
|
||||
|
||||
if (texture)
|
||||
{
|
||||
if ((arg & color_mask) == color_mask)
|
||||
{
|
||||
texture->ignore(gl::cache_buffers::local);
|
||||
texture->invalidate(gl::cache_buffers::host);
|
||||
}
|
||||
else
|
||||
{
|
||||
texture->sync(gl::cache_buffers::local);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
glClear(mask);
|
||||
renderer->invalidate_buffers();
|
||||
}
|
||||
|
||||
using rsx_method_impl_t = void(*)(u32, GLGSRender*);
|
||||
|
@ -1021,6 +1064,52 @@ std::pair<gl::texture::type, gl::texture::format> surface_depth_format_to_gl(rsx
|
|||
}
|
||||
}
|
||||
|
||||
[[noreturn]] void unimplemented()
|
||||
{
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
u32 surface_format_to_texture_format(rsx::surface_color_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5: unimplemented();
|
||||
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5: unimplemented();
|
||||
case rsx::surface_color_format::r5g6b5: return CELL_GCM_TEXTURE_R5G6B5;
|
||||
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8: unimplemented();
|
||||
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8: unimplemented();
|
||||
case rsx::surface_color_format::a8r8g8b8: return CELL_GCM_TEXTURE_A8R8G8B8;
|
||||
case rsx::surface_color_format::b8: return CELL_GCM_TEXTURE_B8;
|
||||
case rsx::surface_color_format::g8b8: return CELL_GCM_TEXTURE_G8B8;
|
||||
case rsx::surface_color_format::w16z16y16x16: return CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT;
|
||||
case rsx::surface_color_format::w32z32y32x32: return CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT;
|
||||
case rsx::surface_color_format::x32: return CELL_GCM_TEXTURE_X32_FLOAT;
|
||||
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8: unimplemented();
|
||||
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8: unimplemented();
|
||||
case rsx::surface_color_format::a8b8g8r8: unimplemented();
|
||||
}
|
||||
|
||||
return CELL_GCM_TEXTURE_A8R8G8B8;
|
||||
}
|
||||
|
||||
gl::texture_info surface_info(rsx::surface_color_format format, u32 offset, u32 location, u32 width, u32 height, u32 pitch)
|
||||
{
|
||||
gl::texture_info info;
|
||||
|
||||
info.width = width;
|
||||
info.height = height;
|
||||
info.depth = 1;
|
||||
info.pitch = pitch;
|
||||
info.compressed_size = 0;
|
||||
info.target = gl::texture::target::texture2D;
|
||||
info.dimension = 2;
|
||||
info.start_address = rsx::get_address(offset, location);
|
||||
|
||||
info.format = gl::get_texture_format(surface_format_to_texture_format(format));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void GLGSRender::init_buffers(bool skip_reading)
|
||||
{
|
||||
static const u32 mr_color_offset[rsx::limits::color_buffers_count] =
|
||||
|
@ -1049,44 +1138,99 @@ void GLGSRender::init_buffers(bool skip_reading)
|
|||
|
||||
static const gl::texture_view null_texture{ gl::texture::target::texture2D, 0 };
|
||||
|
||||
u32 surface_format = rsx::method_registers[NV4097_SET_SURFACE_FORMAT];
|
||||
|
||||
u32 clip_horizontal = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL];
|
||||
u32 clip_vertical = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL];
|
||||
|
||||
u32 clip_width = clip_horizontal >> 16;
|
||||
u32 clip_height = clip_vertical >> 16;
|
||||
u32 clip_x = clip_horizontal & 0xffff;
|
||||
u32 clip_y = clip_vertical & 0xffff;
|
||||
|
||||
m_surface.unpack(surface_format);
|
||||
m_surface.width = clip_width + clip_x;
|
||||
m_surface.height = clip_height + clip_y;
|
||||
|
||||
rsx::for_each_active_color_surface([&](int index)
|
||||
{
|
||||
//TODO
|
||||
u32 offset = rsx::method_registers[mr_color_offset[index]];
|
||||
u32 location = rsx::method_registers[mr_color_dma[index]];
|
||||
u32 pitch = rsx::method_registers[mr_color_pitch[index]];
|
||||
|
||||
if (true)
|
||||
if (!location)
|
||||
{
|
||||
m_cached_color_buffers[index] = nullptr;
|
||||
cached_color_buffers[index] = nullptr;
|
||||
draw_fbo.color[index] = null_texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl::texture_info info{};
|
||||
|
||||
//TODO
|
||||
|
||||
m_cached_color_buffers[index] = &m_texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local);
|
||||
|
||||
draw_fbo.color[index] = m_cached_color_buffers[index]->view();
|
||||
gl::texture_info info = surface_info(m_surface.color_format, offset, location, m_surface.width, m_surface.height, pitch);
|
||||
cached_color_buffers[index] = &m_texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local);
|
||||
draw_fbo.color[index] = cached_color_buffers[index]->view();
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
//TODO
|
||||
u32 offset = rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET];
|
||||
u32 location = rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA];
|
||||
u32 pitch = rsx::method_registers[NV4097_SET_SURFACE_PITCH_Z];
|
||||
|
||||
if (true)
|
||||
if (!location)
|
||||
{
|
||||
m_cached_depth_buffer = nullptr;
|
||||
cached_depth_buffer = nullptr;
|
||||
draw_fbo.depth_stencil = null_texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl::texture_info info{};
|
||||
gl::texture_info info;
|
||||
|
||||
//TODO
|
||||
info.width = m_surface.width;
|
||||
info.height = m_surface.height;
|
||||
info.depth = 1;
|
||||
info.pitch = pitch;
|
||||
info.dimension = 2;
|
||||
info.compressed_size = 0;
|
||||
info.start_address = rsx::get_address(offset, location);
|
||||
info.target = gl::texture::target::texture2D;
|
||||
|
||||
m_cached_depth_buffer = &m_texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local);
|
||||
switch (m_surface.depth_format)
|
||||
{
|
||||
case rsx::surface_depth_format::z16:
|
||||
info.format.bpp = 2;
|
||||
info.format.flags = gl::texture_flags::swap_bytes;
|
||||
info.format.type = gl::texture::type::ushort;
|
||||
info.format.internal_format = gl::texture::internal_format::depth16;
|
||||
info.format.format = gl::texture::format::depth;
|
||||
break;
|
||||
|
||||
draw_fbo.depth_stencil = m_cached_depth_buffer->view();
|
||||
case rsx::surface_depth_format::z24s8:
|
||||
info.format.bpp = 4;
|
||||
info.format.flags = gl::texture_flags::swap_bytes;
|
||||
info.format.type = gl::texture::type::uint_24_8;
|
||||
info.format.internal_format = gl::texture::internal_format::depth24_stencil8;
|
||||
info.format.format = gl::texture::format::depth_stencil;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
info.format.remap = { GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO };
|
||||
|
||||
cached_depth_buffer = &m_texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local);
|
||||
|
||||
|
||||
switch (m_surface.depth_format)
|
||||
{
|
||||
case rsx::surface_depth_format::z16:
|
||||
draw_fbo.depth = cached_depth_buffer->view();
|
||||
break;
|
||||
|
||||
case rsx::surface_depth_format::z24s8:
|
||||
draw_fbo.depth_stencil = cached_depth_buffer->view();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1126,15 +1270,10 @@ void GLGSRender::invalidate_buffers()
|
|||
|
||||
void GLGSRender::flip(int buffer)
|
||||
{
|
||||
//LOG_NOTICE(Log::RSX, "flip(%d)", buffer);
|
||||
u32 buffer_width = gcm_buffers[buffer].width;
|
||||
u32 buffer_height = gcm_buffers[buffer].height;
|
||||
u32 buffer_pitch = gcm_buffers[buffer].pitch;
|
||||
|
||||
//rsx::tiled_region buffer_region = get_tiled_address(gcm_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
||||
|
||||
//TODO
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
@ -1142,11 +1281,8 @@ void GLGSRender::flip(int buffer)
|
|||
glDisable(GL_LOGIC_OP);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
gl::texture_info info{};
|
||||
|
||||
//TODO
|
||||
|
||||
gl::cached_texture& texture = m_texture_cache.entry(info);
|
||||
gl::cached_texture& texture = m_texture_cache.entry(surface_info(rsx::surface_color_format::a8r8g8b8, gcm_buffers[buffer].offset,
|
||||
CELL_GCM_LOCATION_LOCAL, buffer_width, buffer_height, buffer_pitch), gl::cache_buffers::local);
|
||||
|
||||
m_flip_fbo.bind();
|
||||
m_flip_fbo.color = texture.view();
|
||||
|
@ -1203,7 +1339,7 @@ bool GLGSRender::on_access_violation(u32 address, bool is_writing)
|
|||
{
|
||||
if (is_writing)
|
||||
{
|
||||
const bool accurate_cache = false;
|
||||
const bool accurate_cache = true;
|
||||
|
||||
if (accurate_cache)
|
||||
{
|
||||
|
@ -1249,14 +1385,16 @@ void GLGSRender::for_each_active_surface(std::function<void(gl::cached_texture&
|
|||
{
|
||||
rsx::for_each_active_color_surface([&](int index)
|
||||
{
|
||||
if (gl::cached_texture *texture = m_cached_color_buffers[index])
|
||||
gl::cached_texture *texture = cached_color_buffers[index];
|
||||
|
||||
if (texture)
|
||||
{
|
||||
callback(*texture);
|
||||
}
|
||||
});
|
||||
|
||||
if (gl::cached_texture *texture = m_cached_depth_buffer)
|
||||
if (cached_depth_buffer)
|
||||
{
|
||||
callback(*texture);
|
||||
callback(*cached_depth_buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,9 +38,11 @@ private:
|
|||
gl::texture m_draw_tex_color[rsx::limits::color_buffers_count];
|
||||
gl::texture m_draw_tex_depth_stencil;
|
||||
|
||||
gl::cached_texture *m_cached_color_buffers[rsx::limits::color_buffers_count];
|
||||
gl::cached_texture *m_cached_depth_buffer;
|
||||
public:
|
||||
gl::cached_texture *cached_color_buffers[rsx::limits::color_buffers_count];
|
||||
gl::cached_texture *cached_depth_buffer;
|
||||
|
||||
private:
|
||||
//buffer
|
||||
gl::fbo m_flip_fbo;
|
||||
gl::texture m_flip_tex_color;
|
||||
|
@ -78,5 +80,6 @@ protected:
|
|||
|
||||
bool on_access_violation(u32 address, bool is_writing) override;
|
||||
|
||||
public:
|
||||
void for_each_active_surface(std::function<void(gl::cached_texture& texture)> callback);
|
||||
};
|
||||
|
|
|
@ -16,19 +16,20 @@ namespace gl
|
|||
{
|
||||
void cached_texture::read()
|
||||
{
|
||||
LOG_WARNING(RSX, "cached_texture at 0x%x reading from host buffer", info.start_address);
|
||||
|
||||
cached_texture* found_texture = nullptr;
|
||||
u32 texture_size = info.size();
|
||||
u32 texture_size = info->size();
|
||||
|
||||
m_parent_region->for_each(info.start_address, texture_size, [&](cached_texture& texture)
|
||||
m_parent_region->for_each(info->start_address, texture_size, [&](cached_texture& texture)
|
||||
{
|
||||
if ((texture.m_state & cache_entry_state::local_synchronized) == cache_entry_state::invalid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (texture.info.start_address > info.start_address || texture.info.pitch != info.pitch || texture.info.height < info.height)
|
||||
if (texture.info->start_address != info->start_address ||
|
||||
texture.info->pitch != info->pitch ||
|
||||
texture.info->height < info->height ||
|
||||
texture.info->width < info->width)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -39,20 +40,53 @@ namespace gl
|
|||
if (found_texture)
|
||||
{
|
||||
//read from local
|
||||
LOG_WARNING(RSX, "cached_texture at 0x%x reading from local buffer", info->start_address);
|
||||
|
||||
//TODO
|
||||
glCopyImageSubData(
|
||||
found_texture->gl_name, (GLenum)found_texture->info->target, 0, 0, 0, 0,
|
||||
gl_name, (GLenum)info->target, 0, 0, 0, 0,
|
||||
info->width, info->height, info->depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
//read from host
|
||||
|
||||
//flush all local textures at region
|
||||
m_parent_region->for_each(info.start_address, texture_size, [](cached_texture& texture)
|
||||
m_parent_region->for_each(info->start_address, texture_size, [](cached_texture& texture)
|
||||
{
|
||||
texture.sync(gl::cache_buffers::host);
|
||||
});
|
||||
|
||||
//TODO
|
||||
bind();
|
||||
|
||||
if (info->format.format == gl::texture::format::depth || info->format.format == gl::texture::format::depth_stencil)
|
||||
{
|
||||
LOG_ERROR(RSX, "cached_texture at 0x%x: unimplemented reading depth(stencil) from host buffer", info->start_address);
|
||||
|
||||
//TODO
|
||||
}
|
||||
else if (info->compressed_size)
|
||||
{
|
||||
LOG_WARNING(RSX, "cached_texture at 0x%x: reading compressed texture from host buffer", info->start_address);
|
||||
|
||||
glCompressedTexImage2D((GLenum)info->target, 0,
|
||||
(GLenum)info->format.internal_format,
|
||||
info->width, info->height,
|
||||
0,
|
||||
info->compressed_size, vm::base_priv(info->start_address));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARNING(RSX, "cached_texture at 0x%x reading from host buffer", info->start_address);
|
||||
|
||||
gl::pixel_unpack_settings{}
|
||||
.row_length(info->pitch / info->format.bpp)
|
||||
.aligment(1)
|
||||
.swap_bytes((info->format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none)
|
||||
.apply();
|
||||
|
||||
glTexImage2D((GLenum)info->target, 0, (GLenum)info->format.internal_format, info->width, info->height, 0,
|
||||
(GLenum)info->format.format, (GLenum)info->format.type, vm::base_priv(info->start_address));
|
||||
}
|
||||
}
|
||||
|
||||
ignore(gl::cache_buffers::all);
|
||||
|
@ -60,9 +94,30 @@ namespace gl
|
|||
|
||||
void cached_texture::write()
|
||||
{
|
||||
LOG_WARNING(RSX, "cached_texture at 0x%x writing to host buffer", info.start_address);
|
||||
LOG_WARNING(RSX, "cached_texture at 0x%x writing to host buffer", info->start_address);
|
||||
|
||||
//TODO
|
||||
bind();
|
||||
|
||||
if (info->format.format == gl::texture::format::depth || info->format.format == gl::texture::format::depth_stencil)
|
||||
{
|
||||
LOG_ERROR(RSX, "cached_texture at 0x%x: unimplemented writing depth(stencil) to host buffer", info->start_address);
|
||||
|
||||
//TODO
|
||||
}
|
||||
else if (info->compressed_size)
|
||||
{
|
||||
LOG_ERROR(RSX, "writing compressed texture[0x%x] to host buffer", info->start_address);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl::pixel_pack_settings{}
|
||||
.row_length(info->pitch / info->format.bpp)
|
||||
.aligment(1)
|
||||
.swap_bytes((info->format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none)
|
||||
.apply();
|
||||
|
||||
glGetTexImage((GLenum)info->target, 0, (GLenum)info->format.format, (GLenum)info->format.type, vm::base_priv(info->start_address));
|
||||
}
|
||||
|
||||
ignore(gl::cache_buffers::all);
|
||||
}
|
||||
|
@ -101,17 +156,14 @@ namespace gl
|
|||
{
|
||||
if ((buffers & cache_buffers::host) != cache_buffers::none)
|
||||
{
|
||||
if ((m_state & cache_entry_state::host_synchronized) != cache_entry_state::invalid)
|
||||
{
|
||||
m_state &= ~cache_entry_state::host_synchronized;
|
||||
|
||||
m_parent_region->m_write_protected++;
|
||||
}
|
||||
|
||||
m_parent_region->for_each(info.start_address, info.size(), [this](cached_texture& texture)
|
||||
m_state &= ~cache_entry_state::host_synchronized;
|
||||
m_parent_region->for_each(info->start_address, info->size(), [this](cached_texture& texture)
|
||||
{
|
||||
if (std::addressof(texture) != this)
|
||||
{
|
||||
//LOG_WARNING(RSX, "cached_texture[0x%x,0x%x) invalidate cached_texture[0x%x, 0x%x)",
|
||||
// info->start_address, info->start_address + info->size(),
|
||||
// texture.info->start_address, texture.info->start_address + texture.info->size());
|
||||
texture.invalidate(cache_buffers::local);
|
||||
}
|
||||
});
|
||||
|
@ -119,12 +171,7 @@ namespace gl
|
|||
|
||||
if ((buffers & cache_buffers::local) != cache_buffers::none)
|
||||
{
|
||||
if ((m_state & cache_entry_state::local_synchronized) != cache_entry_state::invalid)
|
||||
{
|
||||
m_state &= ~cache_entry_state::local_synchronized;
|
||||
|
||||
m_parent_region->m_read_protected++;
|
||||
}
|
||||
m_state &= ~cache_entry_state::local_synchronized;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,22 +179,12 @@ namespace gl
|
|||
{
|
||||
if ((buffers & cache_buffers::host) != cache_buffers::none)
|
||||
{
|
||||
if ((m_state & cache_entry_state::host_synchronized) == cache_entry_state::invalid)
|
||||
{
|
||||
m_state |= cache_entry_state::host_synchronized;
|
||||
|
||||
m_parent_region->m_write_protected--;
|
||||
}
|
||||
m_state |= cache_entry_state::host_synchronized;
|
||||
}
|
||||
|
||||
if ((buffers & cache_buffers::local) != cache_buffers::none)
|
||||
{
|
||||
if ((m_state & cache_entry_state::local_synchronized) == cache_entry_state::invalid)
|
||||
{
|
||||
m_state |= cache_entry_state::local_synchronized;
|
||||
|
||||
m_parent_region->m_read_protected--;
|
||||
}
|
||||
m_state |= cache_entry_state::local_synchronized;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,6 +214,20 @@ namespace gl
|
|||
return true;
|
||||
}
|
||||
|
||||
cache_access cached_texture::requires_protection() const
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case cache_entry_state::local_synchronized:
|
||||
return cache_access::read_write;
|
||||
|
||||
case cache_entry_state::synchronized:
|
||||
return cache_access::write;
|
||||
}
|
||||
|
||||
return cache_access::none;
|
||||
}
|
||||
|
||||
void cached_texture::bind(uint index) const
|
||||
{
|
||||
if (index != ~0u)
|
||||
|
@ -184,7 +235,7 @@ namespace gl
|
|||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
}
|
||||
|
||||
glBindTexture((GLenum)info.target, gl_name);
|
||||
glBindTexture((GLenum)info->target, gl_name);
|
||||
}
|
||||
|
||||
void cached_texture::create()
|
||||
|
@ -192,6 +243,9 @@ namespace gl
|
|||
assert(!created());
|
||||
|
||||
glGenTextures(1, &gl_name);
|
||||
bind();
|
||||
glTexImage2D((GLenum)info->target, 0, (GLenum)info->format.internal_format, info->width, info->height, 0,
|
||||
(GLenum)info->format.format, (GLenum)info->format.type, nullptr);
|
||||
}
|
||||
|
||||
void cached_texture::remove()
|
||||
|
@ -208,6 +262,19 @@ namespace gl
|
|||
return gl_name != 0;
|
||||
}
|
||||
|
||||
cache_access protected_region::requires_protection() const
|
||||
{
|
||||
//TODO
|
||||
cache_access result = cache_access::none;
|
||||
|
||||
for (auto &entry : m_textures)
|
||||
{
|
||||
result |= entry.second.requires_protection();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void protected_region::for_each(std::function<void(cached_texture& texture)> callback)
|
||||
{
|
||||
for (auto &entry : m_textures)
|
||||
|
@ -220,38 +287,39 @@ namespace gl
|
|||
{
|
||||
for (auto &entry : m_textures)
|
||||
{
|
||||
u32 entry_address = entry.first;
|
||||
cached_texture &entry_texture = entry.second;
|
||||
|
||||
if (entry_address > start_address)
|
||||
if (entry.first.start_address >= start_address + size)
|
||||
{
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 entry_size = entry_texture.info.size();
|
||||
//TODO
|
||||
if (entry.first.start_address + entry.first.size() <= start_address)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
callback(entry_texture);
|
||||
callback(entry.second);
|
||||
}
|
||||
}
|
||||
|
||||
void protected_region::protect()
|
||||
{
|
||||
u32 flags = 0;
|
||||
cache_access required_protection = requires_protection();
|
||||
|
||||
if (m_read_protected)
|
||||
u32 flags = 0;
|
||||
if ((required_protection & cache_access::read) != cache_access::none)
|
||||
{
|
||||
flags |= vm::page_readable;
|
||||
}
|
||||
|
||||
if (m_write_protected)
|
||||
if ((required_protection & cache_access::write) != cache_access::none)
|
||||
{
|
||||
flags |= vm::page_writable;
|
||||
}
|
||||
|
||||
if (m_current_protection != flags)
|
||||
{
|
||||
vm::page_protect(start_address, size(), 0, flags, m_current_protection & ~flags);
|
||||
LOG_WARNING(RSX, "protection region [0x%x, 0x%x)", start_address, start_address + size());
|
||||
vm::page_protect(start_address, size(), 0, m_current_protection & ~flags, flags);
|
||||
m_current_protection = flags;
|
||||
}
|
||||
}
|
||||
|
@ -262,7 +330,7 @@ namespace gl
|
|||
|
||||
if ((access & cache_access::read) != cache_access::none)
|
||||
{
|
||||
if (m_read_protected)
|
||||
if (m_current_protection & vm::page_readable)
|
||||
{
|
||||
flags |= vm::page_readable;
|
||||
}
|
||||
|
@ -270,13 +338,14 @@ namespace gl
|
|||
|
||||
if ((access & cache_access::write) != cache_access::none)
|
||||
{
|
||||
if (m_write_protected)
|
||||
if (m_current_protection & vm::page_writable)
|
||||
{
|
||||
flags |= vm::page_writable;
|
||||
}
|
||||
}
|
||||
|
||||
vm::page_protect(start_address, size(), 0, 0, flags);
|
||||
LOG_WARNING(RSX, "unprotected region [0x%x, 0x%x)", start_address, start_address + size());
|
||||
vm::page_protect(start_address, size(), 0, flags, 0);
|
||||
m_current_protection &= ~flags;
|
||||
}
|
||||
|
||||
|
@ -290,9 +359,57 @@ namespace gl
|
|||
//TODO
|
||||
}
|
||||
|
||||
void protected_region::combine(const protected_region& region)
|
||||
void protected_region::combine(protected_region& region)
|
||||
{
|
||||
//TODO
|
||||
region.unprotect();
|
||||
unprotect();
|
||||
|
||||
for (auto &texture : region.m_textures)
|
||||
{
|
||||
texture.second.parent(this);
|
||||
}
|
||||
|
||||
m_textures.insert(region.m_textures.begin(), region.m_textures.end());
|
||||
|
||||
if (region.start_address < start_address)
|
||||
{
|
||||
pages_count += (start_address - region.start_address) / vm::page_size;
|
||||
start_address = region.start_address;
|
||||
}
|
||||
else
|
||||
{
|
||||
pages_count = (region.start_address + region.pages_count - start_address) / vm::page_size;
|
||||
}
|
||||
}
|
||||
|
||||
cached_texture& protected_region::add(const texture_info& info)
|
||||
{
|
||||
LOG_WARNING(RSX, "new texture in cache at 0x%x", info.start_address);
|
||||
auto &result = m_textures.emplace(info, cached_texture{});
|
||||
|
||||
if (!result.second)
|
||||
{
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
auto& texture_info = *result.first;
|
||||
|
||||
texture_info.second.info = &texture_info.first;
|
||||
texture_info.second.parent(this);
|
||||
|
||||
return texture_info.second;
|
||||
}
|
||||
|
||||
cached_texture* protected_region::find(const texture_info& info)
|
||||
{
|
||||
auto it = m_textures.find(info);
|
||||
|
||||
if (it == m_textures.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
void protected_region::clear()
|
||||
|
@ -305,32 +422,58 @@ namespace gl
|
|||
}
|
||||
|
||||
m_textures.clear();
|
||||
|
||||
m_read_protected = 0;
|
||||
m_write_protected = 0;
|
||||
}
|
||||
|
||||
cached_texture &texture_cache::entry(texture_info &info, cache_buffers sync_buffers)
|
||||
cached_texture &texture_cache::entry(texture_info &info, cache_buffers sync)
|
||||
{
|
||||
auto region = find_region(info.start_address, info.size());
|
||||
u32 aligned_address = info.start_address & ~(vm::page_size - 1);
|
||||
u32 aligned_size = align(info.size(), vm::page_size);
|
||||
|
||||
if (!region)
|
||||
std::vector<protected_region*> regions = find_regions(aligned_address, aligned_size);
|
||||
protected_region *region;
|
||||
|
||||
if (regions.empty())
|
||||
{
|
||||
region = &m_protected_regions[info.start_address & ~(vm::page_size - 1)];
|
||||
region->pages_count = (info.size() + vm::page_size - 1) / vm::page_size;
|
||||
region = &m_protected_regions[aligned_address];
|
||||
region->pages_count = aligned_size / vm::page_size;
|
||||
region->start_address = aligned_address;
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO
|
||||
region = regions[0];
|
||||
|
||||
std::vector<u32> remove_addresses;
|
||||
|
||||
for (std::size_t index = 1; index < regions.size(); ++index)
|
||||
{
|
||||
region->combine(*regions[index]);
|
||||
remove_addresses.push_back(regions[index]->start_address);
|
||||
}
|
||||
|
||||
for (u32 address : remove_addresses)
|
||||
{
|
||||
m_protected_regions.erase(address);
|
||||
}
|
||||
|
||||
if (region->start_address > aligned_address)
|
||||
{
|
||||
region->pages_count += (region->start_address - aligned_address) / vm::page_size;
|
||||
region->start_address = aligned_address;
|
||||
}
|
||||
|
||||
u32 new_pages_count = (aligned_address + aligned_size - region->start_address) / vm::page_size;
|
||||
region->pages_count = std::max(region->pages_count, new_pages_count);
|
||||
}
|
||||
|
||||
cached_texture *result = nullptr;
|
||||
cached_texture *result = region->find(info);
|
||||
|
||||
//TODO
|
||||
if (!result)
|
||||
{
|
||||
result = ®ion->add(info);
|
||||
}
|
||||
|
||||
result->sync(sync_buffers);
|
||||
|
||||
region->protect();
|
||||
result->sync(sync);
|
||||
//region->protect();
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
@ -353,24 +496,34 @@ namespace gl
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
protected_region *texture_cache::find_region(u32 address, u32 size)
|
||||
std::vector<protected_region*> texture_cache::find_regions(u32 address, u32 size)
|
||||
{
|
||||
std::vector<protected_region *> result;
|
||||
|
||||
for (auto& entry : m_protected_regions)
|
||||
{
|
||||
if (entry.first > address + size)
|
||||
if (entry.first >= address + size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (entry.first + entry.second.size() < address)
|
||||
if (entry.first + entry.second.size() <= address)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return &entry.second;
|
||||
result.push_back(&entry.second);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
void texture_cache::update_protection()
|
||||
{
|
||||
for (auto& entry : m_protected_regions)
|
||||
{
|
||||
entry.second.protect();
|
||||
}
|
||||
}
|
||||
|
||||
void texture_cache::clear()
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace gl
|
|||
struct texture_format
|
||||
{
|
||||
u8 bpp;
|
||||
const GLint *remap;
|
||||
std::array<GLint, 4> remap;
|
||||
texture::internal_format internal_format;
|
||||
texture::format format;
|
||||
texture::type type;
|
||||
|
@ -68,7 +68,7 @@ namespace gl
|
|||
|
||||
u32 size() const
|
||||
{
|
||||
return height * pitch * depth;
|
||||
return compressed_size ? compressed_size : height * pitch * depth;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -76,7 +76,7 @@ namespace gl
|
|||
|
||||
struct cached_texture
|
||||
{
|
||||
texture_info info;
|
||||
const texture_info *info;
|
||||
GLuint gl_name = 0;
|
||||
|
||||
private:
|
||||
|
@ -99,9 +99,11 @@ namespace gl
|
|||
|
||||
gl::texture_view view() const
|
||||
{
|
||||
return{ info.target, gl_name };
|
||||
return{ info->target, gl_name };
|
||||
}
|
||||
|
||||
cache_access requires_protection() const;
|
||||
|
||||
protected:
|
||||
void create();
|
||||
void remove();
|
||||
|
@ -116,10 +118,8 @@ namespace gl
|
|||
u32 pages_count;
|
||||
|
||||
private:
|
||||
std::map<u32, cached_texture> m_textures;
|
||||
std::unordered_map<texture_info, cached_texture, fnv_1a_hasher, bitwise_equals> m_textures;
|
||||
|
||||
u32 m_read_protected = 0;
|
||||
u32 m_write_protected = 0;
|
||||
u32 m_current_protection = 0;
|
||||
|
||||
public:
|
||||
|
@ -128,6 +128,7 @@ namespace gl
|
|||
return pages_count * vm::page_size;
|
||||
}
|
||||
|
||||
cache_access requires_protection() const;
|
||||
void for_each(std::function<void(cached_texture& texture)> callback);
|
||||
void for_each(u32 start_address, u32 size, std::function<void(cached_texture& texture)> callback);
|
||||
void protect();
|
||||
|
@ -135,11 +136,12 @@ namespace gl
|
|||
bool empty() const;
|
||||
|
||||
void separate(protected_region& dst);
|
||||
void combine(const protected_region& region);
|
||||
void combine(protected_region& region);
|
||||
|
||||
cached_texture* find(const texture_info& info);
|
||||
cached_texture& add(const texture_info& info);
|
||||
|
||||
void clear();
|
||||
|
||||
friend cached_texture;
|
||||
};
|
||||
|
||||
class texture_cache
|
||||
|
@ -147,9 +149,10 @@ namespace gl
|
|||
std::map<u32, protected_region> m_protected_regions;
|
||||
|
||||
public:
|
||||
cached_texture &entry(texture_info &info, cache_buffers sync_buffers = cache_buffers::none);
|
||||
cached_texture &entry(texture_info &info, cache_buffers sync = cache_buffers::none);
|
||||
protected_region *find_region(u32 address);
|
||||
protected_region *find_region(u32 address, u32 size);
|
||||
std::vector<protected_region*> find_regions(u32 address, u32 size);
|
||||
void update_protection();
|
||||
void clear();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
#include "../Common/TextureUtils.h"
|
||||
#include "gl_texture_cache.h"
|
||||
|
||||
const GLint default_remap[4]{ GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE };
|
||||
const GLint remap_B8[4]{ GL_BLUE, GL_BLUE, GL_BLUE, GL_BLUE };
|
||||
const GLint remap_G8B8[4]{ GL_RED, GL_GREEN, GL_RED, GL_GREEN };
|
||||
const GLint remap_R6G5B5[4]{ GL_ALPHA, GL_GREEN, GL_RED, GL_BLUE };
|
||||
const GLint remap_X16[4]{ GL_RED, GL_ONE, GL_RED, GL_ONE };
|
||||
const GLint remap_Y16_X16[4]{ GL_GREEN, GL_RED, GL_GREEN, GL_RED };
|
||||
const GLint remap_FLOAT[4]{ GL_RED, GL_ONE, GL_ONE, GL_ONE };
|
||||
const GLint remap_X32_FLOAT[4]{ GL_RED, GL_ONE, GL_ONE, GL_ONE };
|
||||
const GLint remap_D1R5G5B5[4]{ GL_ONE, GL_RED, GL_GREEN, GL_BLUE };
|
||||
const GLint remap_D8R8G8B8[4]{ GL_ONE, GL_RED, GL_GREEN, GL_BLUE };
|
||||
const GLint remap_Y16_X16_FLOAT[4]{ GL_RED, GL_GREEN, GL_RED, GL_GREEN };
|
||||
const std::array<GLint, 4> default_remap{ GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE };
|
||||
const std::array<GLint, 4> remap_B8{ GL_BLUE, GL_BLUE, GL_BLUE, GL_BLUE };
|
||||
const std::array<GLint, 4> remap_G8B8{ GL_RED, GL_GREEN, GL_RED, GL_GREEN };
|
||||
const std::array<GLint, 4> remap_R6G5B5{ GL_ALPHA, GL_GREEN, GL_RED, GL_BLUE };
|
||||
const std::array<GLint, 4> remap_X16{ GL_RED, GL_ONE, GL_RED, GL_ONE };
|
||||
const std::array<GLint, 4> remap_Y16_X16{ GL_GREEN, GL_RED, GL_GREEN, GL_RED };
|
||||
const std::array<GLint, 4> remap_FLOAT{ GL_RED, GL_ONE, GL_ONE, GL_ONE };
|
||||
const std::array<GLint, 4> remap_X32_FLOAT{ GL_RED, GL_ONE, GL_ONE, GL_ONE };
|
||||
const std::array<GLint, 4> remap_D1R5G5B5{ GL_ONE, GL_RED, GL_GREEN, GL_BLUE };
|
||||
const std::array<GLint, 4> remap_D8R8G8B8{ GL_ONE, GL_RED, GL_GREEN, GL_BLUE };
|
||||
const std::array<GLint, 4> remap_Y16_X16_FLOAT{ GL_RED, GL_GREEN, GL_RED, GL_GREEN };
|
||||
|
||||
const std::unordered_map<u32, gl::texture_format> textures_fromats
|
||||
{
|
||||
|
@ -44,6 +44,14 @@ const std::unordered_map<u32, gl::texture_format> textures_fromats
|
|||
{ CELL_GCM_TEXTURE_Y16_X16_FLOAT,{ 4, remap_Y16_X16_FLOAT, gl::texture::internal_format::rgba, gl::texture::format::rg, gl::texture::type::f16, gl::texture_flags::allow_remap | gl::texture_flags::swap_bytes } },
|
||||
};
|
||||
|
||||
namespace gl
|
||||
{
|
||||
const texture_format& get_texture_format(u32 texture_id)
|
||||
{
|
||||
return textures_fromats.at(texture_id);
|
||||
}
|
||||
}
|
||||
|
||||
static const int gl_tex_min_filter[] =
|
||||
{
|
||||
GL_NEAREST, // unused
|
||||
|
@ -147,7 +155,7 @@ void rsx::gl_texture::bind(gl::texture_cache& cache, int index, rsx::texture& te
|
|||
|
||||
bool is_compressed = compressed_format(full_format);
|
||||
|
||||
const GLint *remap = default_remap;
|
||||
const GLint *remap = default_remap.data();
|
||||
|
||||
//TODO
|
||||
gl::texture_info info{};
|
||||
|
@ -156,6 +164,8 @@ void rsx::gl_texture::bind(gl::texture_cache& cache, int index, rsx::texture& te
|
|||
info.height = std::max<u16>(tex.height(), 1);
|
||||
info.depth = std::max<u16>(tex.depth(), 1);
|
||||
info.dimension = tex.dimension();
|
||||
info.start_address = rsx::get_address(tex.offset(), tex.location());
|
||||
info.target = target;
|
||||
|
||||
if (is_compressed)
|
||||
{
|
||||
|
@ -183,6 +193,10 @@ void rsx::gl_texture::bind(gl::texture_cache& cache, int index, rsx::texture& te
|
|||
default:
|
||||
throw EXCEPTION("bad compressed format");
|
||||
}
|
||||
|
||||
info.format.bpp = 1;
|
||||
info.format.format = gl::texture::format::rgba;
|
||||
info.format.flags = gl::texture_flags::none;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -201,7 +215,7 @@ void rsx::gl_texture::bind(gl::texture_cache& cache, int index, rsx::texture& te
|
|||
info.pitch = info.width * info.format.bpp;
|
||||
}
|
||||
|
||||
remap = info.format.remap;
|
||||
remap = info.format.remap.data();
|
||||
}
|
||||
|
||||
cache.entry(info, gl::cache_buffers::local).bind(index);
|
||||
|
|
|
@ -6,12 +6,16 @@
|
|||
namespace gl
|
||||
{
|
||||
class texture_cache;
|
||||
struct texture_format;
|
||||
|
||||
const texture_format& get_texture_format(u32 texture_id);
|
||||
}
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
class texture;
|
||||
|
||||
|
||||
namespace gl_texture
|
||||
{
|
||||
void bind(gl::texture_cache& cache, int index, rsx::texture& tex);
|
||||
|
|
|
@ -667,7 +667,7 @@ void RSXDebugger::GetBuffers()
|
|||
if(!vm::check_addr(RSXbuffer_addr))
|
||||
continue;
|
||||
|
||||
auto RSXbuffer = vm::ps3::_ptr<u8>(RSXbuffer_addr);
|
||||
auto RSXbuffer = (u8*)vm::base_priv(RSXbuffer_addr);
|
||||
|
||||
u32 width = buffers[bufferId].width;
|
||||
u32 height = buffers[bufferId].height;
|
||||
|
|
Loading…
Add table
Reference in a new issue