Implemented color texture reading/writing

Fixed region protection
This commit is contained in:
DHrpcs3 2016-03-07 01:36:40 +03:00
parent 18caf477c9
commit c365004776
7 changed files with 468 additions and 153 deletions

View file

@ -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);
}
}

View file

@ -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);
};

View file

@ -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 = &region->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()

View file

@ -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();
};
}

View file

@ -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);

View file

@ -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);

View file

@ -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;