Hacking on render targets. Kind of work in simple cases, upside down :/

This commit is contained in:
Ben Vanik 2015-03-06 20:36:10 -08:00
parent a1e68c0036
commit 84fa131f12
4 changed files with 354 additions and 143 deletions

View File

@ -2400,6 +2400,7 @@ bool CommandProcessor::IssueCopy() {
// Depending on the source, pick the buffer we'll be sourcing. // Depending on the source, pick the buffer we'll be sourcing.
// We then query for a cached framebuffer setup with that buffer active. // We then query for a cached framebuffer setup with that buffer active.
TextureFormat src_format = TextureFormat::kUnknown;
GLuint color_targets[4] = {kAnyTarget, kAnyTarget, kAnyTarget, kAnyTarget}; GLuint color_targets[4] = {kAnyTarget, kAnyTarget, kAnyTarget, kAnyTarget};
GLuint depth_target = kAnyTarget; GLuint depth_target = kAnyTarget;
if (copy_src_select <= 3) { if (copy_src_select <= 3) {
@ -2414,6 +2415,7 @@ bool CommandProcessor::IssueCopy() {
(color_info[copy_src_select] >> 16) & 0xF); (color_info[copy_src_select] >> 16) & 0xF);
color_targets[copy_src_select] = GetColorRenderTarget( color_targets[copy_src_select] = GetColorRenderTarget(
surface_pitch, surface_msaa, color_base, color_format); surface_pitch, surface_msaa, color_base, color_format);
src_format = ColorRenderTargetToTextureFormat(color_format);
} else { } else {
// Source from depth/stencil. // Source from depth/stencil.
uint32_t depth_info = regs[XE_GPU_REG_RB_DEPTH_INFO].u32; uint32_t depth_info = regs[XE_GPU_REG_RB_DEPTH_INFO].u32;
@ -2422,6 +2424,7 @@ bool CommandProcessor::IssueCopy() {
static_cast<DepthRenderTargetFormat>((depth_info >> 16) & 0x1); static_cast<DepthRenderTargetFormat>((depth_info >> 16) & 0x1);
depth_target = GetDepthRenderTarget(surface_pitch, surface_msaa, depth_base, depth_target = GetDepthRenderTarget(surface_pitch, surface_msaa, depth_base,
depth_format); depth_format);
src_format = DepthRenderTargetToTextureFormat(depth_format);
} }
auto source_framebuffer = GetFramebuffer(color_targets, depth_target); auto source_framebuffer = GetFramebuffer(color_targets, depth_target);
if (!source_framebuffer) { if (!source_framebuffer) {
@ -2468,7 +2471,7 @@ bool CommandProcessor::IssueCopy() {
glPixelStorei(GL_PACK_SWAP_BYTES, GL_TRUE); glPixelStorei(GL_PACK_SWAP_BYTES, GL_TRUE);
break; break;
default: default:
assert_unhandled_case(copy_dest_endian); //assert_unhandled_case(copy_dest_endian);
glPixelStorei(GL_PACK_SWAP_BYTES, GL_TRUE); glPixelStorei(GL_PACK_SWAP_BYTES, GL_TRUE);
break; break;
} }
@ -2493,23 +2496,61 @@ bool CommandProcessor::IssueCopy() {
uint32_t w = copy_dest_pitch; uint32_t w = copy_dest_pitch;
uint32_t h = copy_dest_height; uint32_t h = copy_dest_height;
if (!FLAGS_disable_framebuffer_readback) {
// Make active so glReadPixels reads from us. // Make active so glReadPixels reads from us.
glBindFramebuffer(GL_READ_FRAMEBUFFER, source_framebuffer->framebuffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, source_framebuffer->framebuffer);
switch (copy_command) { switch (copy_command) {
case CopyCommand::kConvert: case CopyCommand::kRaw: {
// This performs a byte-for-byte copy of the textures from src to dest
// with no conversion. Byte swapping may still occur.
if (copy_src_select <= 3) { if (copy_src_select <= 3) {
// Source from a bound render target. // Source from a bound render target.
// glBindBuffer(GL_READ_FRAMEBUFFER, framebuffer)
glNamedFramebufferReadBuffer(source_framebuffer->framebuffer, glNamedFramebufferReadBuffer(source_framebuffer->framebuffer,
GL_COLOR_ATTACHMENT0 + copy_src_select); GL_COLOR_ATTACHMENT0 + copy_src_select);
glReadPixels(x, y, w, h, read_format, read_type, ptr); // TODO(benvanik): RAW copy.
texture_cache_.CopyReadBufferTexture(
copy_dest_base, x, y, w, h,
ColorFormatToTextureFormat(copy_dest_format),
copy_dest_swap ? true : false);
if (!FLAGS_disable_framebuffer_readback) {
// glReadPixels(x, y, w, h, read_format, read_type, ptr);
}
} else { } else {
// Source from the bound depth/stencil target. // Source from the bound depth/stencil target.
glReadPixels(x, y, w, h, GL_DEPTH_STENCIL, read_type, ptr); // TODO(benvanik): RAW copy.
texture_cache_.CopyReadBufferTexture(copy_dest_base, x, y, w, h,
src_format,
copy_dest_swap ? true : false);
if (!FLAGS_disable_framebuffer_readback) {
// glReadPixels(x, y, w, h, GL_DEPTH_STENCIL, read_type, ptr);
}
} }
break; break;
case CopyCommand::kRaw: }
case CopyCommand::kConvert: {
if (copy_src_select <= 3) {
// Source from a bound render target.
glNamedFramebufferReadBuffer(source_framebuffer->framebuffer,
GL_COLOR_ATTACHMENT0 + copy_src_select);
// Either copy the readbuffer into an existing texture or create a new
// one in the cache so we can service future upload requests.
texture_cache_.CopyReadBufferTexture(
copy_dest_base, x, y, w, h,
ColorFormatToTextureFormat(copy_dest_format),
copy_dest_swap ? true : false);
if (!FLAGS_disable_framebuffer_readback) {
// glReadPixels(x, y, w, h, read_format, read_type, ptr);
}
} else {
// Source from the bound depth/stencil target.
texture_cache_.CopyReadBufferTexture(copy_dest_base, x, y, w, h,
src_format,
copy_dest_swap ? true : false);
if (!FLAGS_disable_framebuffer_readback) {
// glReadPixels(x, y, w, h, GL_DEPTH_STENCIL, read_type, ptr);
}
}
break;
}
case CopyCommand::kConstantOne: case CopyCommand::kConstantOne:
case CopyCommand::kNull: case CopyCommand::kNull:
default: default:
@ -2517,7 +2558,6 @@ bool CommandProcessor::IssueCopy() {
return false; return false;
} }
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
// Perform any requested clears. // Perform any requested clears.
uint32_t copy_depth_clear = regs[XE_GPU_REG_RB_DEPTH_CLEAR].u32; uint32_t copy_depth_clear = regs[XE_GPU_REG_RB_DEPTH_CLEAR].u32;

View File

@ -22,6 +22,125 @@ using namespace xe::gpu::xenos;
extern "C" GLEWContext* glewGetContext(); extern "C" GLEWContext* glewGetContext();
extern "C" WGLEWContext* wglewGetContext(); extern "C" WGLEWContext* wglewGetContext();
struct TextureConfig {
TextureFormat texture_format;
GLenum internal_format;
GLenum format;
GLenum type;
};
// https://code.google.com/p/glsnewton/source/browse/trunk/Source/uDDSLoader.pas?r=62
// http://dench.flatlib.jp/opengl/textures
// http://fossies.org/linux/WebKit/Source/ThirdParty/ANGLE/src/libGLESv2/formatutils.cpp
static const TextureConfig texture_configs[64] = {
{ TextureFormat::k_1_REVERSE, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_1, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM },
{ TextureFormat::k_8, GL_R8, GL_RED, GL_UNSIGNED_BYTE },
{ TextureFormat::k_1_5_5_5, GL_RGB5_A1, GL_RGBA,
GL_UNSIGNED_SHORT_1_5_5_5_REV },
{ TextureFormat::k_5_6_5, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 },
{ TextureFormat::k_6_5_5, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM },
{ TextureFormat::k_8_8_8_8, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE },
{ TextureFormat::k_2_10_10_10, GL_RGB10_A2, GL_RGBA,
GL_UNSIGNED_INT_2_10_10_10_REV },
{ TextureFormat::k_8_A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM },
{ TextureFormat::k_8_B, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM },
{ TextureFormat::k_8_8, GL_RG8, GL_RG, GL_UNSIGNED_BYTE },
{ TextureFormat::k_Cr_Y1_Cb_Y0, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_Y1_Cr_Y0_Cb, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_8_8_8_8_A, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_4_4_4_4, GL_RGBA4, GL_RGBA,
GL_UNSIGNED_SHORT_4_4_4_4_REV },
{ TextureFormat::k_10_11_11, GL_R11F_G11F_B10F, GL_RGB,
GL_UNSIGNED_INT_10F_11F_11F_REV }, // ?
{ TextureFormat::k_11_11_10, GL_R11F_G11F_B10F, GL_RGB,
GL_UNSIGNED_INT_10F_11F_11F_REV }, // ?
{ TextureFormat::k_DXT1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE },
{ TextureFormat::k_DXT2_3, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE },
{ TextureFormat::k_DXT4_5, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE },
{ TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_24_8, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8 },
{ TextureFormat::k_24_8_FLOAT, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL,
GL_FLOAT_32_UNSIGNED_INT_24_8_REV },
{ TextureFormat::k_16, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM },
{ TextureFormat::k_16_16, GL_RG16, GL_RG, GL_UNSIGNED_SHORT },
{ TextureFormat::k_16_16_16_16, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_16_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_16_16_16_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_16_FLOAT, GL_R16F, GL_RED, GL_HALF_FLOAT },
{ TextureFormat::k_16_16_FLOAT, GL_RG16F, GL_RG, GL_HALF_FLOAT },
{ TextureFormat::k_16_16_16_16_FLOAT, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT },
{ TextureFormat::k_32, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM },
{ TextureFormat::k_32_32, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM },
{ TextureFormat::k_32_32_32_32, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_32_FLOAT, GL_R32F, GL_RED, GL_FLOAT },
{ TextureFormat::k_32_32_FLOAT, GL_RG32F, GL_RG, GL_FLOAT },
{ TextureFormat::k_32_32_32_32_FLOAT, GL_RGBA32F, GL_RGBA, GL_FLOAT },
{ TextureFormat::k_32_AS_8, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_32_AS_8_8, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_16_MPEG, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_16_16_MPEG, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_32_AS_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_32_AS_8_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_16_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_16_MPEG_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_16_16_MPEG_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::k_DXN, GL_COMPRESSED_RG_RGTC2, GL_COMPRESSED_RG_RGTC2,
GL_INVALID_ENUM },
{ TextureFormat::k_8_8_8_8_AS_16_16_16_16, GL_RGBA8, GL_RGBA,
GL_UNSIGNED_BYTE },
{ TextureFormat::k_DXT1_AS_16_16_16_16, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE },
{ TextureFormat::k_DXT2_3_AS_16_16_16_16, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE },
{ TextureFormat::k_DXT4_5_AS_16_16_16_16, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE },
{ TextureFormat::k_2_10_10_10_AS_16_16_16_16, GL_RGB10_A2, GL_RGBA,
GL_UNSIGNED_INT_2_10_10_10_REV },
{ TextureFormat::k_10_11_11_AS_16_16_16_16, GL_R11F_G11F_B10F, GL_RGB,
GL_UNSIGNED_INT_10F_11F_11F_REV },
{ TextureFormat::k_11_11_10_AS_16_16_16_16, GL_R11F_G11F_B10F,
GL_INVALID_ENUM, GL_INVALID_ENUM },
{ TextureFormat::k_32_32_32_FLOAT, GL_RGB32F, GL_RGB, GL_FLOAT },
{ TextureFormat::k_DXT3A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM },
{ TextureFormat::k_DXT5A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM },
{ TextureFormat::k_CTX1, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM },
{ TextureFormat::k_DXT3A_AS_1_1_1_1, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
{ TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM },
};
TextureCache::TextureCache() : memory_(nullptr), scratch_buffer_(nullptr) { TextureCache::TextureCache() : memory_(nullptr), scratch_buffer_(nullptr) {
invalidated_textures_sets_[0].reserve(64); invalidated_textures_sets_[0].reserve(64);
invalidated_textures_sets_[1].reserve(64); invalidated_textures_sets_[1].reserve(64);
@ -70,7 +189,7 @@ void TextureCache::Clear() {
void TextureCache::EvictAllTextures() { void TextureCache::EvictAllTextures() {
// Kill all textures - some may be in the eviction list, but that's fine // Kill all textures - some may be in the eviction list, but that's fine
// as we will clear that below. // as we will clear that below.
while (texture_entries_.size()) { while (!texture_entries_.empty()) {
auto entry = texture_entries_.begin()->second; auto entry = texture_entries_.begin()->second;
EvictTexture(entry); EvictTexture(entry);
} }
@ -80,6 +199,15 @@ void TextureCache::EvictAllTextures() {
invalidated_textures_sets_[0].clear(); invalidated_textures_sets_[0].clear();
invalidated_textures_sets_[1].clear(); invalidated_textures_sets_[1].clear();
} }
// Kill all readbuffer textures.
while (!read_buffer_textures_.empty()) {
auto it = --read_buffer_textures_.end();
auto entry = *it;
glDeleteTextures(1, &entry->handle);
delete entry;
read_buffer_textures_.erase(it);
}
} }
TextureCache::TextureEntryView* TextureCache::Demand( TextureCache::TextureEntryView* TextureCache::Demand(
@ -278,6 +406,25 @@ TextureCache::TextureEntry* TextureCache::LookupOrInsertTexture(
entry->pending_invalidation = false; entry->pending_invalidation = false;
entry->handle = 0; entry->handle = 0;
// Check read buffer textures - there may be one waiting for us.
// TODO(benvanik): speed up existence check?
for (auto it = read_buffer_textures_.begin();
it != read_buffer_textures_.end(); ++it) {
auto read_buffer_entry = *it;
if (read_buffer_entry->guest_address == texture_info.guest_address &&
read_buffer_entry->width == texture_info.size_2d.logical_width &&
read_buffer_entry->height == texture_info.size_2d.logical_height) {
// Found! Acquire the handle and remove the readbuffer entry.
read_buffer_textures_.erase(it);
entry->handle = read_buffer_entry->handle;
delete read_buffer_entry;
// TODO(benvanik): set more texture properties? swizzle/etc?
auto entry_ptr = entry.get();
texture_entries_.insert({hash, entry.release()});
return entry_ptr;
}
}
GLenum target; GLenum target;
switch (texture_info.dimension) { switch (texture_info.dimension) {
case Dimension::k1D: case Dimension::k1D:
@ -362,6 +509,84 @@ TextureCache::TextureEntry* TextureCache::LookupOrInsertTexture(
return entry_ptr; return entry_ptr;
} }
TextureCache::TextureEntry* TextureCache::LookupAddress(uint32_t guest_address,
uint32_t width,
uint32_t height,
TextureFormat format) {
// TODO(benvanik): worth speeding up?
for (auto it = texture_entries_.begin(); it != texture_entries_.end(); ++it) {
const auto& texture_info = it->second->texture_info;
if (texture_info.guest_address == guest_address &&
texture_info.dimension == Dimension::k2D &&
texture_info.size_2d.logical_width == width &&
texture_info.size_2d.logical_height == height) {
return it->second;
}
}
return nullptr;
}
void TextureCache::CopyReadBufferTexture(uint32_t guest_address, uint32_t x,
uint32_t y, uint32_t width,
uint32_t height,
TextureFormat format,
bool swap_channels) {
// See if we have used a texture at this address before. If we have, we can
// reuse it.
// TODO(benvanik): better lookup matching format/etc?
auto texture_entry = LookupAddress(guest_address, width, height, format);
if (texture_entry) {
// Have existing texture.
assert_false(texture_entry->pending_invalidation);
glCopyTextureSubImage2D(texture_entry->handle, 0, 0, 0, x, y, width,
height);
// HACK: remove texture from write watch list so readback won't kill us.
if (texture_entry->write_watch_handle) {
memory_->CancelWriteWatch(texture_entry->write_watch_handle);
texture_entry->write_watch_handle = 0;
}
return;
}
// Check pending read buffer textures (for multiple resolves with no
// uploads inbetween).
for (auto it = read_buffer_textures_.begin();
it != read_buffer_textures_.end(); ++it) {
const auto& entry = *it;
if (entry->guest_address == guest_address && entry->width == width &&
entry->height == height && entry->format == format) {
// Found an existing entry - just reupload.
glCopyTextureSubImage2D(entry->handle, 0, 0, 0, x, y, width, height);
return;
}
}
const auto& config = texture_configs[uint32_t(format)];
if (config.format == GL_INVALID_ENUM) {
assert_always("Unhandled destination texture format");
return;
}
// Need to create a new texture.
// As we don't know anything about this texture, we'll add it to the
// pending readbuffer list. If nobody claims it after a certain amount
// of time we'll dump it.
auto entry = std::make_unique<ReadBufferTexture>();
entry->guest_address = guest_address;
entry->width = width;
entry->height = height;
entry->format = format;
glCreateTextures(GL_TEXTURE_2D, 1, &entry->handle);
glTextureParameteri(entry->handle, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(entry->handle, GL_TEXTURE_MAX_LEVEL, 1);
glTextureStorage2D(entry->handle, 1, config.internal_format, width, height);
glCopyTextureSubImage2D(entry->handle, 0, 0, 0, x, y, width, height);
read_buffer_textures_.push_back(entry.release());
}
void TextureCache::EvictTexture(TextureEntry* entry) { void TextureCache::EvictTexture(TextureEntry* entry) {
if (entry->write_watch_handle) { if (entry->write_watch_handle) {
memory_->CancelWriteWatch(entry->write_watch_handle); memory_->CancelWriteWatch(entry->write_watch_handle);
@ -413,125 +638,6 @@ void TextureSwap(Endian endianness, void* dest, const void* src,
} }
} }
struct TextureConfig {
TextureFormat texture_format;
GLenum internal_format;
GLenum format;
GLenum type;
};
// https://code.google.com/p/glsnewton/source/browse/trunk/Source/uDDSLoader.pas?r=62
// http://dench.flatlib.jp/opengl/textures
// http://fossies.org/linux/WebKit/Source/ThirdParty/ANGLE/src/libGLESv2/formatutils.cpp
static const TextureConfig texture_configs[64] = {
{TextureFormat::k_1_REVERSE, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_1, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_8, GL_R8, GL_RED, GL_UNSIGNED_BYTE},
{TextureFormat::k_1_5_5_5, GL_RGB5_A1, GL_RGBA,
GL_UNSIGNED_SHORT_1_5_5_5_REV},
{TextureFormat::k_5_6_5, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},
{TextureFormat::k_6_5_5, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_8_8_8_8, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE},
{TextureFormat::k_2_10_10_10, GL_RGB10_A2, GL_RGBA,
GL_UNSIGNED_INT_2_10_10_10_REV},
{TextureFormat::k_8_A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_8_B, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_8_8, GL_RG8, GL_RG, GL_UNSIGNED_BYTE},
{TextureFormat::k_Cr_Y1_Cb_Y0, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_Y1_Cr_Y0_Cb, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_8_8_8_8_A, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_4_4_4_4, GL_RGBA4, GL_RGBA,
GL_UNSIGNED_SHORT_4_4_4_4_REV},
{TextureFormat::k_10_11_11, GL_R11F_G11F_B10F, GL_RGB,
GL_UNSIGNED_INT_10F_11F_11F_REV}, // ?
{TextureFormat::k_11_11_10, GL_R11F_G11F_B10F, GL_RGB,
GL_UNSIGNED_INT_10F_11F_11F_REV}, // ?
{TextureFormat::k_DXT1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::k_DXT2_3, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::k_DXT4_5, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_24_8, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8},
{TextureFormat::k_24_8_FLOAT, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL,
GL_FLOAT_32_UNSIGNED_INT_24_8_REV},
{TextureFormat::k_16, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_16_16, GL_RG16, GL_RG, GL_UNSIGNED_SHORT},
{TextureFormat::k_16_16_16_16, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_16_16_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_FLOAT, GL_R16F, GL_RED, GL_HALF_FLOAT},
{TextureFormat::k_16_16_FLOAT, GL_RG16F, GL_RG, GL_HALF_FLOAT},
{TextureFormat::k_16_16_16_16_FLOAT, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT},
{TextureFormat::k_32, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_32_32, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_32_32_32_32, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_32_FLOAT, GL_R32F, GL_RED, GL_FLOAT},
{TextureFormat::k_32_32_FLOAT, GL_RG32F, GL_RG, GL_FLOAT},
{TextureFormat::k_32_32_32_32_FLOAT, GL_RGBA32F, GL_RGBA, GL_FLOAT},
{TextureFormat::k_32_AS_8, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_32_AS_8_8, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_MPEG, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_16_MPEG, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_32_AS_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_32_AS_8_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_MPEG_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_16_MPEG_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_DXN, GL_COMPRESSED_RG_RGTC2, GL_COMPRESSED_RG_RGTC2,
GL_INVALID_ENUM},
{TextureFormat::k_8_8_8_8_AS_16_16_16_16, GL_RGBA8, GL_RGBA,
GL_UNSIGNED_BYTE},
{TextureFormat::k_DXT1_AS_16_16_16_16, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::k_DXT2_3_AS_16_16_16_16, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::k_DXT4_5_AS_16_16_16_16, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::k_2_10_10_10_AS_16_16_16_16, GL_RGB10_A2, GL_RGBA,
GL_UNSIGNED_INT_2_10_10_10_REV},
{TextureFormat::k_10_11_11_AS_16_16_16_16, GL_R11F_G11F_B10F, GL_RGB,
GL_UNSIGNED_INT_10F_11F_11F_REV},
{TextureFormat::k_11_11_10_AS_16_16_16_16, GL_R11F_G11F_B10F,
GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_32_32_32_FLOAT, GL_RGB32F, GL_RGB, GL_FLOAT},
{TextureFormat::k_DXT3A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_DXT5A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_CTX1, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_DXT3A_AS_1_1_1_1, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
};
bool TextureCache::UploadTexture2D(GLuint texture, bool TextureCache::UploadTexture2D(GLuint texture,
const TextureInfo& texture_info) { const TextureInfo& texture_info) {
const auto host_address = memory_->Translate(texture_info.guest_address); const auto host_address = memory_->Translate(texture_info.guest_address);

View File

@ -57,13 +57,26 @@ class TextureCache {
TextureEntryView* Demand(const TextureInfo& texture_info, TextureEntryView* Demand(const TextureInfo& texture_info,
const SamplerInfo& sampler_info); const SamplerInfo& sampler_info);
void CopyReadBufferTexture(uint32_t guest_address, uint32_t x, uint32_t y,
uint32_t width, uint32_t height,
TextureFormat format, bool swap_channels);
private: private:
struct ReadBufferTexture {
uint32_t guest_address;
uint32_t width;
uint32_t height;
TextureFormat format;
GLuint handle;
};
SamplerEntry* LookupOrInsertSampler(const SamplerInfo& sampler_info, SamplerEntry* LookupOrInsertSampler(const SamplerInfo& sampler_info,
uint64_t opt_hash = 0); uint64_t opt_hash = 0);
void EvictSampler(SamplerEntry* entry); void EvictSampler(SamplerEntry* entry);
TextureEntry* LookupOrInsertTexture(const TextureInfo& texture_info, TextureEntry* LookupOrInsertTexture(const TextureInfo& texture_info,
uint64_t opt_hash = 0); uint64_t opt_hash = 0);
TextureEntry* LookupAddress(uint32_t guest_address, uint32_t width,
uint32_t height, TextureFormat format);
void EvictTexture(TextureEntry* entry); void EvictTexture(TextureEntry* entry);
bool UploadTexture2D(GLuint texture, const TextureInfo& texture_info); bool UploadTexture2D(GLuint texture, const TextureInfo& texture_info);
@ -73,6 +86,8 @@ class TextureCache {
std::unordered_map<uint64_t, SamplerEntry*> sampler_entries_; std::unordered_map<uint64_t, SamplerEntry*> sampler_entries_;
std::unordered_map<uint64_t, TextureEntry*> texture_entries_; std::unordered_map<uint64_t, TextureEntry*> texture_entries_;
std::vector<ReadBufferTexture*> read_buffer_textures_;
std::mutex invalidated_textures_mutex_; std::mutex invalidated_textures_mutex_;
std::vector<TextureEntry*>* invalidated_textures_; std::vector<TextureEntry*>* invalidated_textures_;
std::vector<TextureEntry*> invalidated_textures_sets_[2]; std::vector<TextureEntry*> invalidated_textures_sets_[2];

View File

@ -80,10 +80,60 @@ enum class TextureFormat : uint32_t {
k_DXT5A = 59, k_DXT5A = 59,
k_CTX1 = 60, k_CTX1 = 60,
k_DXT3A_AS_1_1_1_1 = 61, k_DXT3A_AS_1_1_1_1 = 61,
k_2_10_10_10_FLOAT = 62,
kUnknown = 0xFFFFFFFFu, kUnknown = 0xFFFFFFFFu,
}; };
inline TextureFormat ColorFormatToTextureFormat(
xenos::ColorFormat color_format) {
return static_cast<TextureFormat>(color_format);
}
inline TextureFormat ColorRenderTargetToTextureFormat(
xenos::ColorRenderTargetFormat color_format) {
switch (color_format) {
case xenos::ColorRenderTargetFormat::k_8_8_8_8:
return TextureFormat::k_8_8_8_8;
case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA:
return TextureFormat::k_8_8_8_8;
case xenos::ColorRenderTargetFormat::k_2_10_10_10:
return TextureFormat::k_2_10_10_10;
case xenos::ColorRenderTargetFormat::k_2_10_10_10_FLOAT:
return TextureFormat::k_2_10_10_10_FLOAT;
case xenos::ColorRenderTargetFormat::k_16_16:
return TextureFormat::k_16_16;
case xenos::ColorRenderTargetFormat::k_16_16_16_16:
return TextureFormat::k_16_16_16_16;
case xenos::ColorRenderTargetFormat::k_16_16_FLOAT:
return TextureFormat::k_16_16_FLOAT;
case xenos::ColorRenderTargetFormat::k_16_16_16_16_FLOAT:
return TextureFormat::k_16_16_16_16_FLOAT;
case xenos::ColorRenderTargetFormat::k_2_10_10_10_unknown:
return TextureFormat::k_2_10_10_10;
case xenos::ColorRenderTargetFormat::k_2_10_10_10_FLOAT_unknown:
return TextureFormat::k_2_10_10_10_FLOAT;
case xenos::ColorRenderTargetFormat::k_32_FLOAT:
return TextureFormat::k_32_FLOAT;
default:
assert_unhandled_case(color_format);
return TextureFormat::kUnknown;
}
}
inline TextureFormat DepthRenderTargetToTextureFormat(
xenos::DepthRenderTargetFormat depth_format) {
switch (depth_format) {
case xenos::DepthRenderTargetFormat::kD24S8:
return TextureFormat::k_24_8;
case xenos::DepthRenderTargetFormat::kD24FS8:
return TextureFormat::k_24_8_FLOAT;
default:
assert_unhandled_case(depth_format);
return TextureFormat::kUnknown;
}
}
enum class FormatType { enum class FormatType {
kUncompressed, kUncompressed,
kCompressed, kCompressed,