From ec113275dcc731d5c874adc6a93e58b32abffedd Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Mon, 7 Dec 2015 22:39:33 -0800 Subject: [PATCH] Making texture swizzles dynamic. Seems to fix some color swap issues. And probably exposes many more ;) --- src/xenia/gpu/gl4/draw_batcher.h | 4 +++- src/xenia/gpu/gl4/gl4_command_processor.cc | 11 +++++----- src/xenia/gpu/gl4/gl4_graphics_system.cc | 2 +- src/xenia/gpu/gl4/texture_cache.cc | 25 +++------------------- src/xenia/gpu/glsl_shader_translator.cc | 11 ++++++++++ src/xenia/gpu/texture_info.cc | 1 - src/xenia/gpu/texture_info.h | 1 - src/xenia/gpu/trace_viewer.cc | 12 +++++------ src/xenia/ui/gl/blitter.cc | 20 +++++++---------- src/xenia/ui/gl/blitter.h | 5 +++-- 10 files changed, 40 insertions(+), 52 deletions(-) diff --git a/src/xenia/gpu/gl4/draw_batcher.h b/src/xenia/gpu/gl4/draw_batcher.h index c62542194..902b049e4 100644 --- a/src/xenia/gpu/gl4/draw_batcher.h +++ b/src/xenia/gpu/gl4/draw_batcher.h @@ -78,8 +78,9 @@ class DrawBatcher { void set_ps_param_gen(int register_index) { active_draw_.header->ps_param_gen = register_index; } - void set_texture_sampler(int index, GLuint64 handle) { + void set_texture_sampler(int index, GLuint64 handle, uint32_t swizzle) { active_draw_.header->texture_samplers[index] = handle; + active_draw_.header->texture_swizzles[index] = swizzle; } void set_index_buffer(const CircularBuffer::Allocation& allocation) { // Offset is used in glDrawElements. @@ -140,6 +141,7 @@ class DrawBatcher { // TODO(benvanik): pack tightly GLuint64 texture_samplers[32]; + GLuint texture_swizzles[32]; float4 float_consts[512]; uint32_t bool_consts[8]; diff --git a/src/xenia/gpu/gl4/gl4_command_processor.cc b/src/xenia/gpu/gl4/gl4_command_processor.cc index a2c1d7a13..9855b137f 100644 --- a/src/xenia/gpu/gl4/gl4_command_processor.cc +++ b/src/xenia/gpu/gl4/gl4_command_processor.cc @@ -408,7 +408,7 @@ void GL4CommandProcessor::PerformSwap(uint32_t frontbuffer_ptr, ->blitter() ->CopyColorTexture2D(framebuffer_texture, src_rect, static_cast(swap_state_.back_buffer_texture), - dest_rect, GL_LINEAR); + dest_rect, GL_LINEAR, true); if (FLAGS_draw_all_framebuffers) { int32_t offsetx = (1280 - (1280 / 5)); @@ -431,7 +431,7 @@ void GL4CommandProcessor::PerformSwap(uint32_t frontbuffer_ptr, ->CopyColorTexture2D( tex, src_rect, static_cast(swap_state_.back_buffer_texture), dest_rect, - GL_LINEAR); + GL_LINEAR, true); offsety += 720 / 5; } @@ -455,7 +455,7 @@ void GL4CommandProcessor::PerformSwap(uint32_t frontbuffer_ptr, ->CopyColorTexture2D( tex, src_rect, static_cast(swap_state_.back_buffer_texture), dest_rect, - GL_LINEAR); + GL_LINEAR, false); doffsetx += 1280 / 5; } @@ -1485,7 +1485,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::PopulateSampler( // Reset slot. // If we fail, we still draw but with an invalid texture. - draw_batcher_.set_texture_sampler(texture_binding.fetch_constant, 0); + draw_batcher_.set_texture_sampler(texture_binding.fetch_constant, 0, 0); if (FLAGS_disable_textures) { return UpdateStatus::kCompatible; @@ -1521,7 +1521,8 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::PopulateSampler( // Shaders will use bindless to fetch right from it. draw_batcher_.set_texture_sampler(texture_binding.fetch_constant, - entry_view->texture_sampler_handle); + entry_view->texture_sampler_handle, + fetch.swizzle); return UpdateStatus::kCompatible; } diff --git a/src/xenia/gpu/gl4/gl4_graphics_system.cc b/src/xenia/gpu/gl4/gl4_graphics_system.cc index 8632f5729..efca2fa08 100644 --- a/src/xenia/gpu/gl4/gl4_graphics_system.cc +++ b/src/xenia/gpu/gl4/gl4_graphics_system.cc @@ -78,7 +78,7 @@ void GL4GraphicsSystem::Swap(xe::ui::UIEvent* e) { static_cast(swap_state.front_buffer_texture), Rect2D(0, 0, swap_state.width, swap_state.height), Rect2D(0, 0, target_window_->width(), target_window_->height()), - GL_LINEAR); + GL_LINEAR, false); } } // namespace gl4 diff --git a/src/xenia/gpu/gl4/texture_cache.cc b/src/xenia/gpu/gl4/texture_cache.cc index d54ae3318..2344c6459 100644 --- a/src/xenia/gpu/gl4/texture_cache.cc +++ b/src/xenia/gpu/gl4/texture_cache.cc @@ -473,25 +473,6 @@ TextureCache::TextureEntry* TextureCache::LookupOrInsertTexture( glTextureParameteri(entry->handle, GL_TEXTURE_BASE_LEVEL, 0); glTextureParameteri(entry->handle, GL_TEXTURE_MAX_LEVEL, 1); - // Pre-shader swizzle. - // TODO(benvanik): can this be dynamic? Maybe per view? - // We may have to emulate this in the shader. - uint32_t swizzle_r = texture_info.swizzle & 0x7; - uint32_t swizzle_g = (texture_info.swizzle >> 3) & 0x7; - uint32_t swizzle_b = (texture_info.swizzle >> 6) & 0x7; - uint32_t swizzle_a = (texture_info.swizzle >> 9) & 0x7; - static const GLenum swizzle_map[] = { - GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_ZERO, GL_ONE, - }; - glTextureParameteri(entry->handle, GL_TEXTURE_SWIZZLE_R, - swizzle_map[swizzle_r]); - glTextureParameteri(entry->handle, GL_TEXTURE_SWIZZLE_G, - swizzle_map[swizzle_g]); - glTextureParameteri(entry->handle, GL_TEXTURE_SWIZZLE_B, - swizzle_map[swizzle_b]); - glTextureParameteri(entry->handle, GL_TEXTURE_SWIZZLE_A, - swizzle_map[swizzle_a]); - // Upload/convert. bool uploaded = false; switch (texture_info.dimension) { @@ -590,7 +571,7 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, dest_rect); } else { blitter->CopyColorTexture2D(src_texture, src_rect, texture_entry->handle, - dest_rect, GL_LINEAR); + dest_rect, GL_LINEAR, swap_channels); } // HACK: remove texture from write watch list so readback won't kill us. @@ -615,7 +596,7 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, dest_rect); } else { blitter->CopyColorTexture2D(src_texture, src_rect, entry->handle, - dest_rect, GL_LINEAR); + dest_rect, GL_LINEAR, swap_channels); } return entry->handle; } @@ -642,7 +623,7 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, blitter->CopyDepthTexture(src_texture, src_rect, entry->handle, dest_rect); } else { blitter->CopyColorTexture2D(src_texture, src_rect, entry->handle, dest_rect, - GL_LINEAR); + GL_LINEAR, swap_channels); } GLuint handle = entry->handle; diff --git a/src/xenia/gpu/glsl_shader_translator.cc b/src/xenia/gpu/glsl_shader_translator.cc index 3f20b8b20..8cea8c646 100644 --- a/src/xenia/gpu/glsl_shader_translator.cc +++ b/src/xenia/gpu/glsl_shader_translator.cc @@ -115,6 +115,7 @@ struct StateData { int padding[3]; // TODO(benvanik): variable length. uvec2 texture_samplers[32]; + uint texture_swizzles[32]; vec4 float_consts[512]; int bool_consts[8]; int loop_consts[32]; @@ -625,6 +626,16 @@ void GlslShaderTranslator::ProcessTextureFetchInstruction( EmitSourceDepth("}\n"); break; } + EmitSourceDepth("{\n"); + EmitSourceDepth( + " float swiz_source[6] = {pv.x, pv.y, pv.z, pv.w, 0.0, 1.0};\n"); + EmitSourceDepth(" uint swiz = state.texture_swizzles[%d];\n", + instr.operands[1].storage_index); + EmitSourceDepth(" pv = vec4(swiz_source[swiz & 0x7],\n"); + EmitSourceDepth(" swiz_source[(swiz >> 3) & 0x7],\n"); + EmitSourceDepth(" swiz_source[(swiz >> 6) & 0x7],\n"); + EmitSourceDepth(" swiz_source[(swiz >> 9) & 0x7]);\n"); + EmitSourceDepth("}\n"); break; case FetchOpcode::kGetTextureBorderColorFrac: EmitUnimplementedTranslationError(); diff --git a/src/xenia/gpu/texture_info.cc b/src/xenia/gpu/texture_info.cc index 2de06e973..0d9cb91fd 100644 --- a/src/xenia/gpu/texture_info.cc +++ b/src/xenia/gpu/texture_info.cc @@ -109,7 +109,6 @@ bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch, // a2xx_sq_surfaceformat auto& info = *out_info; info.guest_address = fetch.address << 12; - info.swizzle = fetch.swizzle; info.dimension = static_cast(fetch.dimension); info.width = info.height = info.depth = 0; diff --git a/src/xenia/gpu/texture_info.h b/src/xenia/gpu/texture_info.h index aa05d890c..500f22bb3 100644 --- a/src/xenia/gpu/texture_info.h +++ b/src/xenia/gpu/texture_info.h @@ -155,7 +155,6 @@ struct FormatInfo { struct TextureInfo { uint32_t guest_address; - uint32_t swizzle; Dimension dimension; uint32_t width; uint32_t height; diff --git a/src/xenia/gpu/trace_viewer.cc b/src/xenia/gpu/trace_viewer.cc index a68d2b907..f5517ea41 100644 --- a/src/xenia/gpu/trace_viewer.cc +++ b/src/xenia/gpu/trace_viewer.cc @@ -621,13 +621,11 @@ void TraceViewer::DrawTextureInfo( ImGui::Text("Cube: ?"); break; } - static const char* swizzle_map[] = {"Red", "Green", "Blue", "Alpha", - "Zero", "One", "UNK6", "UNK7"}; - ImGui::Text("Swizzle: %s %s %s %s", - swizzle_map[(texture_info.swizzle >> 0) & 0x7], - swizzle_map[(texture_info.swizzle >> 3) & 0x7], - swizzle_map[(texture_info.swizzle >> 6) & 0x7], - swizzle_map[(texture_info.swizzle >> 9) & 0x7]); + static const char* kSwizzleMap[] = {"R", "G", "B", "A", "0", "1"}; + ImGui::Text("Swizzle: %s%s%s%s", kSwizzleMap[(fetch.swizzle >> 0) & 0x7], + kSwizzleMap[(fetch.swizzle >> 3) & 0x7], + kSwizzleMap[(fetch.swizzle >> 6) & 0x7], + kSwizzleMap[(fetch.swizzle >> 9) & 0x7]); ImGui::Columns(1); } diff --git a/src/xenia/ui/gl/blitter.cc b/src/xenia/ui/gl/blitter.cc index fc86d5682..21c2aec36 100644 --- a/src/xenia/ui/gl/blitter.cc +++ b/src/xenia/ui/gl/blitter.cc @@ -62,10 +62,12 @@ void main() { const std::string color_fs_source = header + R"( layout(location = 1) uniform sampler2D src_texture; +layout(location = 2) uniform bool swap; layout(location = 0) in vec2 vtx_uv; layout(location = 0) out vec4 oC; void main() { oC = texture(src_texture, vtx_uv); + if (!swap) oC = oC.bgra; })"; const std::string depth_fs_source = header + R"( @@ -242,7 +244,8 @@ void Blitter::Draw(GLuint src_texture, Rect2D src_rect, Rect2D dest_rect, } void Blitter::BlitTexture2D(GLuint src_texture, Rect2D src_rect, - Rect2D dest_rect, GLenum filter) { + Rect2D dest_rect, GLenum filter, + bool swap_channels) { SavedState state; state.Save(); @@ -252,6 +255,8 @@ void Blitter::BlitTexture2D(GLuint src_texture, Rect2D src_rect, glStencilMask(0xFF); glBindProgramPipeline(color_pipeline_); + glProgramUniform1i(color_fragment_program_, 2, swap_channels ? 1 : 0); + Draw(src_texture, src_rect, dest_rect, filter); state.Restore(); @@ -259,7 +264,7 @@ void Blitter::BlitTexture2D(GLuint src_texture, Rect2D src_rect, void Blitter::CopyColorTexture2D(GLuint src_texture, Rect2D src_rect, GLuint dest_texture, Rect2D dest_rect, - GLenum filter) { + GLenum filter, bool swap_channels) { SavedState state; state.Save(); @@ -268,14 +273,7 @@ void Blitter::CopyColorTexture2D(GLuint src_texture, Rect2D src_rect, glDepthMask(GL_FALSE); glBindProgramPipeline(color_pipeline_); - // Make sure the texture swizzles match before performing a copy - // TODO: Is this a good place for this? - GLint swizzle_map[2][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}}; - glGetTextureParameteriv(src_texture, GL_TEXTURE_SWIZZLE_RGBA, swizzle_map[0]); - glGetTextureParameteriv(dest_texture, GL_TEXTURE_SWIZZLE_RGBA, - swizzle_map[1]); - - glTextureParameteriv(src_texture, GL_TEXTURE_SWIZZLE_RGBA, swizzle_map[1]); + glProgramUniform1i(color_fragment_program_, 2, swap_channels ? 1 : 0); glNamedFramebufferTexture(scratch_framebuffer_, GL_COLOR_ATTACHMENT0, dest_texture, 0); @@ -286,8 +284,6 @@ void Blitter::CopyColorTexture2D(GLuint src_texture, Rect2D src_rect, glNamedFramebufferTexture(scratch_framebuffer_, GL_COLOR_ATTACHMENT0, GL_NONE, 0); - glTextureParameteriv(src_texture, GL_TEXTURE_SWIZZLE_RGBA, swizzle_map[0]); - state.Restore(); } diff --git a/src/xenia/ui/gl/blitter.h b/src/xenia/ui/gl/blitter.h index 5e86946f6..3080c6aaa 100644 --- a/src/xenia/ui/gl/blitter.h +++ b/src/xenia/ui/gl/blitter.h @@ -39,10 +39,11 @@ class Blitter { void Shutdown(); void BlitTexture2D(GLuint src_texture, Rect2D src_rect, Rect2D dest_rect, - GLenum filter); + GLenum filter, bool swap_channels); void CopyColorTexture2D(GLuint src_texture, Rect2D src_rect, - GLuint dest_texture, Rect2D dest_rect, GLenum filter); + GLuint dest_texture, Rect2D dest_rect, GLenum filter, + bool swap_channels); void CopyDepthTexture(GLuint src_texture, Rect2D src_rect, GLuint dest_texture, Rect2D dest_rect);