mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-14 15:00:30 +02:00
The GE's blend terms are floor((2c+1)(2f+1)/1024), which truncates, while the hardware multiplies by f/255 and rounds, so every pass of a fixed color blend chain came out up to a level brighter. God Eater Burst's bloom is many such passes and ended up far too bright. For additive FIXA/FIXB blends that aren't just 0 and 0xFFFFFF, the shader now computes the src term exactly and lowers it by 0.5 - (2B+1)/1024, and the blend constant is the GE's dst factor (2B+1)/512, so the hardware's rounding of the sum lands on the GE's floor (except where the src term would go below zero). Blend constants are passed as floats to make that possible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
72 lines
2.2 KiB
C++
72 lines
2.2 KiB
C++
#pragma once
|
|
|
|
#include "Common/GPU/Vulkan/VulkanLoader.h"
|
|
|
|
#include <cstring>
|
|
|
|
class FramebufferManagerVulkan;
|
|
|
|
struct ScissorRect {
|
|
int x, y;
|
|
int width, height;
|
|
};
|
|
|
|
struct VulkanDynamicState {
|
|
VkViewport viewport;
|
|
ScissorRect scissor;
|
|
bool useBlendColor;
|
|
float blendColor[4];
|
|
bool useStencil;
|
|
uint8_t stencilRef;
|
|
uint8_t stencilWriteMask;
|
|
uint8_t stencilCompareMask;
|
|
};
|
|
|
|
// Let's pack this tight using bitfields.
|
|
// If an enable flag is set to 0, all the data fields for that section should
|
|
// also be set to 0.
|
|
// ~64 bits.
|
|
// Can't use enums unfortunately, they end up signed and breaking values above half their ranges.
|
|
// Stored in the shader cache on disk (as part of VulkanPipelineKey): changing it requires bumping
|
|
// CACHE_VERSION in ShaderManagerVulkan.cpp.
|
|
struct VulkanPipelineRasterStateKey {
|
|
// Blend
|
|
unsigned int blendEnable : 1;
|
|
unsigned int srcColor : 5; // VkBlendFactor
|
|
unsigned int destColor : 5; // VkBlendFactor
|
|
unsigned int srcAlpha : 5; // VkBlendFactor
|
|
unsigned int destAlpha : 5; // VkBlendFactor
|
|
unsigned int blendOpColor : 3; // VkBlendOp
|
|
unsigned int blendOpAlpha : 3; // VkBlendOp
|
|
unsigned int logicOpEnable : 1;
|
|
unsigned int logicOp : 4; // VkLogicOp
|
|
unsigned int colorWriteMask : 4;
|
|
|
|
// Depth/Stencil
|
|
unsigned int depthClampEnable : 1;
|
|
unsigned int depthTestEnable : 1;
|
|
unsigned int depthWriteEnable : 1;
|
|
unsigned int depthCompareOp : 3; // VkCompareOp
|
|
unsigned int stencilTestEnable : 1;
|
|
unsigned int stencilCompareOp : 3; // VkCompareOp
|
|
unsigned int stencilPassOp : 4; // VkStencilOp
|
|
unsigned int stencilFailOp : 4; // VkStencilOp
|
|
unsigned int stencilDepthFailOp : 4; // VkStencilOp
|
|
|
|
// We'll use dynamic state for writemask, reference and comparemask to start with,
|
|
// and viewport/scissor. More dynamic state requires extensions.
|
|
|
|
// Rasterizer
|
|
unsigned int cullMode : 2; // VkCullModeFlagBits
|
|
unsigned int topology : 4; // VkPrimitiveTopology
|
|
|
|
bool operator < (const VulkanPipelineRasterStateKey &other) const {
|
|
constexpr size_t size = sizeof(VulkanPipelineRasterStateKey);
|
|
return memcmp(this, &other, size) < 0;
|
|
}
|
|
bool operator == (const VulkanPipelineRasterStateKey &other) const {
|
|
constexpr size_t size = sizeof(VulkanPipelineRasterStateKey);
|
|
return memcmp(this, &other, size) == 0;
|
|
}
|
|
};
|