diff --git a/src/xenia/gpu/vulkan/vulkan_command_processor.cc b/src/xenia/gpu/vulkan/vulkan_command_processor.cc index 523c5f7d5..a8b82a5bc 100644 --- a/src/xenia/gpu/vulkan/vulkan_command_processor.cc +++ b/src/xenia/gpu/vulkan/vulkan_command_processor.cc @@ -212,9 +212,58 @@ void VulkanCommandProcessor::WriteRegister(uint32_t index, uint32_t value) { offset ^= 0x1F; dirty_loop_constants_ |= (1 << offset); + } else if (index == XE_GPU_REG_DC_LUT_PWL_DATA) { + UpdateGammaRampValue(GammaRampType::kPWL, value); + } else if (index == XE_GPU_REG_DC_LUT_30_COLOR) { + UpdateGammaRampValue(GammaRampType::kNormal, value); + } else if (index >= XE_GPU_REG_DC_LUT_RW_MODE && + index <= XE_GPU_REG_DC_LUTA_CONTROL) { + uint32_t offset = index - XE_GPU_REG_DC_LUT_RW_MODE; + offset ^= 0x05; + + dirty_gamma_constants_ |= (1 << offset); + + if (index == XE_GPU_REG_DC_LUT_RW_INDEX) { + gamma_ramp_rw_subindex_ = 0; + } } } +void VulkanCommandProcessor::UpdateGammaRampValue(GammaRampType type, + uint32_t value) { + RegisterFile* regs = register_file_; + + auto index = regs->values[XE_GPU_REG_DC_LUT_RW_INDEX].u32; + + auto mask = regs->values[XE_GPU_REG_DC_LUT_WRITE_EN_MASK].u32; + auto mask_lo = (mask >> 0) & 0x7; + auto mask_hi = (mask >> 3) & 0x7; + + // If games update individual components we're going to have a problem. + assert_true(mask_lo == 0 || mask_lo == 7); + assert_true(mask_hi == 0); + + auto subindex = gamma_ramp_rw_subindex_; + + if (mask_lo) { + switch (type) { + case GammaRampType::kNormal: + assert_true(regs->values[XE_GPU_REG_DC_LUT_RW_MODE].u32 == 0); + gamma_ramp_.normal[index].value = value; + break; + case GammaRampType::kPWL: + assert_true(regs->values[XE_GPU_REG_DC_LUT_RW_MODE].u32 == 1); + gamma_ramp_.pwl[index].values[subindex].value = value; + break; + default: + assert_unhandled_case(type); + } + } + + gamma_ramp_rw_subindex_ = (subindex + 1) % 3; + dirty_gamma_ramp_ = true; +} + void VulkanCommandProcessor::CreateSwapImage(VkCommandBuffer setup_buffer, VkExtent2D extents) { VkImageCreateInfo image_info; diff --git a/src/xenia/gpu/vulkan/vulkan_command_processor.h b/src/xenia/gpu/vulkan/vulkan_command_processor.h index 3a1add0fe..cd9a5f36c 100644 --- a/src/xenia/gpu/vulkan/vulkan_command_processor.h +++ b/src/xenia/gpu/vulkan/vulkan_command_processor.h @@ -44,6 +44,50 @@ namespace vulkan { class VulkanGraphicsSystem; class TextureCache; +enum class GammaRampType { + kUnknown = 0, + kNormal, + kPWL, +}; + +struct GammaRamp { + struct NormalEntry { + union { + struct { + uint32_t r : 10; + uint32_t g : 10; + uint32_t b : 10; + uint32_t : 2; + }; + uint32_t value; + }; + }; + + struct PWLValue { + union { + struct { + uint16_t base; + uint16_t delta; + }; + uint32_t value; + }; + }; + + struct PWLEntry { + union { + struct { + PWLValue r; + PWLValue g; + PWLValue b; + }; + PWLValue values[3]; + }; + }; + + NormalEntry normal[256]; + PWLEntry pwl[256]; +}; + class VulkanCommandProcessor : public CommandProcessor { public: VulkanCommandProcessor(VulkanGraphicsSystem* graphics_system, @@ -94,6 +138,8 @@ class VulkanCommandProcessor : public CommandProcessor { VulkanShader* pixel_shader); bool IssueCopy() override; + void UpdateGammaRampValue(GammaRampType type, uint32_t value); + xe::ui::vulkan::VulkanDevice* device_ = nullptr; // front buffer / back buffer memory @@ -104,6 +150,7 @@ class VulkanCommandProcessor : public CommandProcessor { uint64_t dirty_float_constants_ = 0; // Dirty float constants in blocks of 4 uint8_t dirty_bool_constants_ = 0; uint32_t dirty_loop_constants_ = 0; + uint8_t dirty_gamma_constants_ = 0; uint32_t coher_base_vc_ = 0; uint32_t coher_size_vc_ = 0; @@ -136,6 +183,10 @@ class VulkanCommandProcessor : public CommandProcessor { VkCommandBuffer current_command_buffer_ = nullptr; VkCommandBuffer current_setup_buffer_ = nullptr; VkFence current_batch_fence_; + + GammaRamp gamma_ramp_ = {}; + int gamma_ramp_rw_subindex_ = 0; + bool dirty_gamma_ramp_ = true; }; } // namespace vulkan