mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Merge pull request #9541 from hrydgard/state-optimizations-prep
State optimizations prep
This commit is contained in:
commit
0ca16c29ae
@ -99,8 +99,6 @@ enum : uint64_t {
|
||||
DIRTY_TEXTURE_IMAGE = 1ULL << 41,
|
||||
DIRTY_TEXTURE_PARAMS = 1ULL << 42,
|
||||
|
||||
// Now we can add further dirty flags that are not uniforms.
|
||||
|
||||
DIRTY_ALL = 0xFFFFFFFFFFFFFFFF
|
||||
};
|
||||
|
||||
|
@ -113,7 +113,9 @@ struct ShaderID {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator != (const ShaderID &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
bool Bit(int bit) const {
|
||||
return (d[bit >> 5] >> (bit & 31)) & 1;
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ void TextureCacheCommon::SetTexture(bool force) {
|
||||
|
||||
TexCache::iterator iter = cache_.find(cachekey);
|
||||
TexCacheEntry *entry = nullptr;
|
||||
gstate_c.needShaderTexClamp = false;
|
||||
gstate_c.SetNeedShaderTexclamp(false);
|
||||
gstate_c.skipDrawReason &= ~SKIPDRAW_BAD_FB_TEXTURE;
|
||||
gstate_c.bgraTexture = isBgraBackend_;
|
||||
|
||||
@ -746,9 +746,9 @@ void TextureCacheCommon::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFram
|
||||
gstate_c.bgraTexture = false;
|
||||
gstate_c.curTextureXOffset = fbInfo.xOffset;
|
||||
gstate_c.curTextureYOffset = fbInfo.yOffset;
|
||||
gstate_c.needShaderTexClamp = gstate_c.curTextureWidth != (u32)gstate.getTextureWidth(0) || gstate_c.curTextureHeight != (u32)gstate.getTextureHeight(0);
|
||||
gstate_c.SetNeedShaderTexclamp(gstate_c.curTextureWidth != (u32)gstate.getTextureWidth(0) || gstate_c.curTextureHeight != (u32)gstate.getTextureHeight(0));
|
||||
if (gstate_c.curTextureXOffset != 0 || gstate_c.curTextureYOffset != 0) {
|
||||
gstate_c.needShaderTexClamp = true;
|
||||
gstate_c.SetNeedShaderTexclamp(true);
|
||||
}
|
||||
|
||||
nextTexture_ = entry;
|
||||
@ -758,7 +758,7 @@ void TextureCacheCommon::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFram
|
||||
framebuffer->fbo = nullptr;
|
||||
}
|
||||
Unbind();
|
||||
gstate_c.needShaderTexClamp = false;
|
||||
gstate_c.SetNeedShaderTexclamp(false);
|
||||
}
|
||||
|
||||
nextNeedsRehash_ = false;
|
||||
@ -1414,8 +1414,8 @@ void TextureCacheCommon::ApplyTexture() {
|
||||
ApplyTextureFramebuffer(entry, entry->framebuffer);
|
||||
} else {
|
||||
BindTexture(entry);
|
||||
gstate_c.textureFullAlpha = entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL;
|
||||
gstate_c.textureSimpleAlpha = entry->GetAlphaStatus() != TexCacheEntry::STATUS_ALPHA_UNKNOWN;
|
||||
gstate_c.SetTextureFullAlpha(entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL);
|
||||
gstate_c.SetTextureSimpleAlpha(entry->GetAlphaStatus() != TexCacheEntry::STATUS_ALPHA_UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -482,8 +482,6 @@ void GPU_D3D11::Execute_VertexTypeSkinning(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_D3D11::Execute_Prim(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_PRIM);
|
||||
|
||||
// This drives all drawing. All other state we just buffer up, then we apply it only
|
||||
// when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization.
|
||||
|
||||
@ -495,6 +493,8 @@ void GPU_D3D11::Execute_Prim(u32 op, u32 diff) {
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
SetDrawType(DRAW_PRIM, prim);
|
||||
|
||||
// Discard AA lines as we can't do anything that makes sense with these anyway. The SW plugin might, though.
|
||||
|
||||
if (gstate.isAntiAliasEnabled()) {
|
||||
@ -553,8 +553,6 @@ void GPU_D3D11::Execute_Prim(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_D3D11::Execute_Bezier(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_BEZIER);
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@ -588,6 +586,8 @@ void GPU_D3D11::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
|
||||
SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim));
|
||||
|
||||
int bz_ucount = op & 0xFF;
|
||||
int bz_vcount = (op >> 8) & 0xFF;
|
||||
bool computeNormals = gstate.isLightingEnabled();
|
||||
@ -612,8 +612,6 @@ void GPU_D3D11::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_D3D11::Execute_Spline(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_SPLINE);
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@ -651,6 +649,7 @@ void GPU_D3D11::Execute_Spline(u32 op, u32 diff) {
|
||||
int sp_utype = (op >> 16) & 0x3;
|
||||
int sp_vtype = (op >> 18) & 0x3;
|
||||
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
|
||||
SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim));
|
||||
bool computeNormals = gstate.isLightingEnabled();
|
||||
bool patchFacing = gstate.patchfacing & 1;
|
||||
u32 vertType = gstate.vertType;
|
||||
|
@ -132,219 +132,305 @@ class FramebufferManagerD3D11;
|
||||
class ShaderManagerD3D11;
|
||||
|
||||
void DrawEngineD3D11::ApplyDrawState(int prim) {
|
||||
memset(&keys_, 0, sizeof(keys_));
|
||||
memset(&dynState_, 0, sizeof(dynState_));
|
||||
|
||||
gstate_c.allowShaderBlend = !g_Config.bDisableSlowFramebufEffects;
|
||||
|
||||
// Set blend - unless we need to do it in the shader.
|
||||
GenericBlendState blendState;
|
||||
ConvertBlendState(blendState, gstate_c.allowShaderBlend);
|
||||
|
||||
bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
|
||||
|
||||
if (blendState.applyShaderBlending) {
|
||||
if (ApplyShaderBlending()) {
|
||||
// We may still want to do something about stencil -> alpha.
|
||||
ApplyStencilReplaceAndLogicOp(blendState.replaceAlphaWithStencil, blendState);
|
||||
}
|
||||
else {
|
||||
// Until next time, force it off.
|
||||
ResetShaderBlending();
|
||||
gstate_c.allowShaderBlend = false;
|
||||
}
|
||||
} else if (blendState.resetShaderBlending) {
|
||||
ResetShaderBlending();
|
||||
}
|
||||
|
||||
if (blendState.enabled) {
|
||||
keys_.blend.blendEnable = true;
|
||||
keys_.blend.logicOpEnable = false;
|
||||
keys_.blend.blendOpColor = d3d11BlendEqLookup[(size_t)blendState.eqColor];
|
||||
keys_.blend.blendOpAlpha = d3d11BlendEqLookup[(size_t)blendState.eqAlpha];
|
||||
keys_.blend.srcColor = d3d11BlendFactorLookup[(size_t)blendState.srcColor];
|
||||
keys_.blend.srcAlpha = d3d11BlendFactorLookup[(size_t)blendState.srcAlpha];
|
||||
keys_.blend.destColor = d3d11BlendFactorLookup[(size_t)blendState.dstColor];
|
||||
keys_.blend.destAlpha = d3d11BlendFactorLookup[(size_t)blendState.dstAlpha];
|
||||
if (blendState.dirtyShaderBlend) {
|
||||
gstate_c.Dirty(DIRTY_SHADERBLEND);
|
||||
}
|
||||
dynState_.useBlendColor = blendState.useBlendColor;
|
||||
if (blendState.useBlendColor) {
|
||||
dynState_.blendColor = blendState.blendColor;
|
||||
}
|
||||
}
|
||||
else {
|
||||
keys_.blend.blendEnable = false;
|
||||
dynState_.useBlendColor = false;
|
||||
}
|
||||
|
||||
dynState_.useStencil = false;
|
||||
|
||||
// Set ColorMask/Stencil/Depth
|
||||
if (gstate.isModeClear()) {
|
||||
keys_.blend.logicOpEnable = false;
|
||||
keys_.raster.cullMode = D3D11_CULL_NONE;
|
||||
|
||||
keys_.depthStencil.depthTestEnable = true;
|
||||
keys_.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS;
|
||||
keys_.depthStencil.depthWriteEnable = gstate.isClearModeDepthMask();
|
||||
if (gstate.isClearModeDepthMask()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Color Test
|
||||
bool colorMask = gstate.isClearModeColorMask();
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
keys_.blend.colorWriteMask = (colorMask ? (1 | 2 | 4) : 0) | (alphaMask ? 8 : 0);
|
||||
|
||||
// Stencil Test
|
||||
if (alphaMask) {
|
||||
keys_.depthStencil.stencilTestEnable = true;
|
||||
keys_.depthStencil.stencilCompareFunc = D3D11_COMPARISON_ALWAYS;
|
||||
keys_.depthStencil.stencilPassOp = D3D11_STENCIL_OP_REPLACE;
|
||||
keys_.depthStencil.stencilFailOp = D3D11_STENCIL_OP_REPLACE;
|
||||
keys_.depthStencil.stencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
|
||||
dynState_.useStencil = true;
|
||||
// In clear mode, the stencil value is set to the alpha value of the vertex.
|
||||
// A normal clear will be 2 points, the second point has the color.
|
||||
// We override this value in the pipeline from software transform for clear rectangles.
|
||||
dynState_.stencilRef = 0xFF;
|
||||
keys_.depthStencil.stencilWriteMask = 0xFF;
|
||||
}
|
||||
else {
|
||||
keys_.depthStencil.stencilTestEnable = false;
|
||||
dynState_.useStencil = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
// Logic Ops
|
||||
if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) {
|
||||
keys_.blend.blendEnable = false; // Can't have both blend & logic op - although I think the PSP can!
|
||||
keys_.blend.logicOpEnable = true;
|
||||
keys_.blend.logicOp = logicOps[gstate.getLogicOp()];
|
||||
// Blend
|
||||
{
|
||||
gstate_c.SetAllowShaderBlend(!g_Config.bDisableSlowFramebufEffects);
|
||||
if (gstate.isModeClear()) {
|
||||
keys_.blend.value = 0; // full wipe
|
||||
keys_.blend.blendEnable = false;
|
||||
dynState_.useBlendColor = false;
|
||||
// Color Test
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
bool colorMask = gstate.isClearModeColorMask();
|
||||
keys_.blend.colorWriteMask = (colorMask ? (1 | 2 | 4) : 0) | (alphaMask ? 8 : 0);
|
||||
} else {
|
||||
keys_.blend.value = 0;
|
||||
// Set blend - unless we need to do it in the shader.
|
||||
GenericBlendState blendState;
|
||||
ConvertBlendState(blendState, gstate_c.allowShaderBlend);
|
||||
if (blendState.applyShaderBlending) {
|
||||
if (ApplyShaderBlending()) {
|
||||
// We may still want to do something about stencil -> alpha.
|
||||
ApplyStencilReplaceAndLogicOp(blendState.replaceAlphaWithStencil, blendState);
|
||||
} else {
|
||||
// Until next time, force it off.
|
||||
ResetShaderBlending();
|
||||
gstate_c.SetAllowShaderBlend(false);
|
||||
}
|
||||
} else if (blendState.resetShaderBlending) {
|
||||
ResetShaderBlending();
|
||||
}
|
||||
else {
|
||||
|
||||
if (blendState.enabled) {
|
||||
keys_.blend.blendEnable = true;
|
||||
keys_.blend.logicOpEnable = false;
|
||||
keys_.blend.blendOpColor = d3d11BlendEqLookup[(size_t)blendState.eqColor];
|
||||
keys_.blend.blendOpAlpha = d3d11BlendEqLookup[(size_t)blendState.eqAlpha];
|
||||
keys_.blend.srcColor = d3d11BlendFactorLookup[(size_t)blendState.srcColor];
|
||||
keys_.blend.srcAlpha = d3d11BlendFactorLookup[(size_t)blendState.srcAlpha];
|
||||
keys_.blend.destColor = d3d11BlendFactorLookup[(size_t)blendState.dstColor];
|
||||
keys_.blend.destAlpha = d3d11BlendFactorLookup[(size_t)blendState.dstAlpha];
|
||||
if (blendState.dirtyShaderBlend) {
|
||||
gstate_c.Dirty(DIRTY_SHADERBLEND);
|
||||
}
|
||||
dynState_.useBlendColor = blendState.useBlendColor;
|
||||
if (blendState.useBlendColor) {
|
||||
dynState_.blendColor = blendState.blendColor;
|
||||
}
|
||||
} else {
|
||||
keys_.blend.blendEnable = false;
|
||||
dynState_.useBlendColor = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set cull
|
||||
bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
|
||||
keys_.raster.cullMode = wantCull ? (gstate.getCullMode() ? D3D11_CULL_FRONT : D3D11_CULL_BACK) : D3D11_CULL_NONE;
|
||||
|
||||
// Depth Test
|
||||
if (gstate.isDepthTestEnabled()) {
|
||||
keys_.depthStencil.depthTestEnable = true;
|
||||
keys_.depthStencil.depthCompareOp = compareOps[gstate.getDepthTestFunction()];
|
||||
keys_.depthStencil.depthWriteEnable = gstate.isDepthWriteEnabled();
|
||||
if (gstate.isDepthWriteEnabled()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
// Logic Ops
|
||||
if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) {
|
||||
keys_.blend.blendEnable = false; // Can't have both blend & logic op - although I think the PSP can!
|
||||
keys_.blend.logicOpEnable = true;
|
||||
keys_.blend.logicOp = logicOps[gstate.getLogicOp()];
|
||||
} else {
|
||||
keys_.blend.logicOpEnable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
keys_.depthStencil.depthTestEnable = false;
|
||||
keys_.depthStencil.depthWriteEnable = false;
|
||||
keys_.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS;
|
||||
}
|
||||
|
||||
// PSP color/alpha mask is per bit but we can only support per byte.
|
||||
// But let's do that, at least. And let's try a threshold.
|
||||
bool rmask = (gstate.pmskc & 0xFF) < 128;
|
||||
bool gmask = ((gstate.pmskc >> 8) & 0xFF) < 128;
|
||||
bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128;
|
||||
bool amask = (gstate.pmska & 0xFF) < 128;
|
||||
// PSP color/alpha mask is per bit but we can only support per byte.
|
||||
// But let's do that, at least. And let's try a threshold.
|
||||
bool rmask = (gstate.pmskc & 0xFF) < 128;
|
||||
bool gmask = ((gstate.pmskc >> 8) & 0xFF) < 128;
|
||||
bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128;
|
||||
bool amask = (gstate.pmska & 0xFF) < 128;
|
||||
|
||||
#ifndef MOBILE_DEVICE
|
||||
u8 abits = (gstate.pmska >> 0) & 0xFF;
|
||||
u8 rbits = (gstate.pmskc >> 0) & 0xFF;
|
||||
u8 gbits = (gstate.pmskc >> 8) & 0xFF;
|
||||
u8 bbits = (gstate.pmskc >> 16) & 0xFF;
|
||||
if ((rbits != 0 && rbits != 0xFF) || (gbits != 0 && gbits != 0xFF) || (bbits != 0 && bbits != 0xFF)) {
|
||||
WARN_LOG_REPORT_ONCE(rgbmask, G3D, "Unsupported RGB mask: r=%02x g=%02x b=%02x", rbits, gbits, bbits);
|
||||
}
|
||||
if (abits != 0 && abits != 0xFF) {
|
||||
// The stencil part of the mask is supported.
|
||||
WARN_LOG_REPORT_ONCE(amask, G3D, "Unsupported alpha/stencil mask: %02x", abits);
|
||||
}
|
||||
u8 abits = (gstate.pmska >> 0) & 0xFF;
|
||||
u8 rbits = (gstate.pmskc >> 0) & 0xFF;
|
||||
u8 gbits = (gstate.pmskc >> 8) & 0xFF;
|
||||
u8 bbits = (gstate.pmskc >> 16) & 0xFF;
|
||||
if ((rbits != 0 && rbits != 0xFF) || (gbits != 0 && gbits != 0xFF) || (bbits != 0 && bbits != 0xFF)) {
|
||||
WARN_LOG_REPORT_ONCE(rgbmask, G3D, "Unsupported RGB mask: r=%02x g=%02x b=%02x", rbits, gbits, bbits);
|
||||
}
|
||||
if (abits != 0 && abits != 0xFF) {
|
||||
// The stencil part of the mask is supported.
|
||||
WARN_LOG_REPORT_ONCE(amask, G3D, "Unsupported alpha/stencil mask: %02x", abits);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Let's not write to alpha if stencil isn't enabled.
|
||||
if (!gstate.isStencilTestEnabled()) {
|
||||
amask = false;
|
||||
}
|
||||
else {
|
||||
// If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel.
|
||||
if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_KEEP) {
|
||||
// Let's not write to alpha if stencil isn't enabled.
|
||||
if (!gstate.isStencilTestEnabled()) {
|
||||
amask = false;
|
||||
} else {
|
||||
// If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel.
|
||||
if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_KEEP) {
|
||||
amask = false;
|
||||
}
|
||||
}
|
||||
|
||||
keys_.blend.colorWriteMask = (rmask ? 1 : 0) | (gmask ? 2 : 0) | (bmask ? 4 : 0) | (amask ? 8 : 0);
|
||||
}
|
||||
|
||||
if (!device1_) {
|
||||
ID3D11BlendState *bs = nullptr;
|
||||
auto blendIter = blendCache_.find(keys_.blend.value);
|
||||
if (blendIter == blendCache_.end()) {
|
||||
D3D11_BLEND_DESC desc{};
|
||||
D3D11_RENDER_TARGET_BLEND_DESC &rt = desc.RenderTarget[0];
|
||||
rt.BlendEnable = keys_.blend.blendEnable;
|
||||
rt.BlendOp = (D3D11_BLEND_OP)keys_.blend.blendOpColor;
|
||||
rt.BlendOpAlpha = (D3D11_BLEND_OP)keys_.blend.blendOpAlpha;
|
||||
rt.SrcBlend = (D3D11_BLEND)keys_.blend.srcColor;
|
||||
rt.DestBlend = (D3D11_BLEND)keys_.blend.destColor;
|
||||
rt.SrcBlendAlpha = (D3D11_BLEND)keys_.blend.srcAlpha;
|
||||
rt.DestBlendAlpha = (D3D11_BLEND)keys_.blend.destAlpha;
|
||||
rt.RenderTargetWriteMask = keys_.blend.colorWriteMask;
|
||||
ASSERT_SUCCESS(device_->CreateBlendState(&desc, &bs));
|
||||
blendCache_.insert(std::pair<uint64_t, ID3D11BlendState *>(keys_.blend.value, bs));
|
||||
} else {
|
||||
bs = blendIter->second;
|
||||
}
|
||||
blendState_ = bs;
|
||||
} else {
|
||||
ID3D11BlendState1 *bs1 = nullptr;
|
||||
auto blendIter = blendCache1_.find(keys_.blend.value);
|
||||
if (blendIter == blendCache1_.end()) {
|
||||
D3D11_BLEND_DESC1 desc1{};
|
||||
D3D11_RENDER_TARGET_BLEND_DESC1 &rt = desc1.RenderTarget[0];
|
||||
rt.BlendEnable = keys_.blend.blendEnable;
|
||||
rt.BlendOp = (D3D11_BLEND_OP)keys_.blend.blendOpColor;
|
||||
rt.BlendOpAlpha = (D3D11_BLEND_OP)keys_.blend.blendOpAlpha;
|
||||
rt.SrcBlend = (D3D11_BLEND)keys_.blend.srcColor;
|
||||
rt.DestBlend = (D3D11_BLEND)keys_.blend.destColor;
|
||||
rt.SrcBlendAlpha = (D3D11_BLEND)keys_.blend.srcAlpha;
|
||||
rt.DestBlendAlpha = (D3D11_BLEND)keys_.blend.destAlpha;
|
||||
rt.RenderTargetWriteMask = keys_.blend.colorWriteMask;
|
||||
rt.LogicOpEnable = keys_.blend.logicOpEnable;
|
||||
rt.LogicOp = (D3D11_LOGIC_OP)keys_.blend.logicOp;
|
||||
ASSERT_SUCCESS(device1_->CreateBlendState1(&desc1, &bs1));
|
||||
blendCache1_.insert(std::pair<uint64_t, ID3D11BlendState1 *>(keys_.blend.value, bs1));
|
||||
} else {
|
||||
bs1 = blendIter->second;
|
||||
}
|
||||
blendState1_ = bs1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
keys_.raster.value = 0;
|
||||
if (gstate.isModeClear()) {
|
||||
keys_.raster.cullMode = D3D11_CULL_NONE;
|
||||
} else {
|
||||
// Set cull
|
||||
bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
|
||||
keys_.raster.cullMode = wantCull ? (gstate.getCullMode() ? D3D11_CULL_FRONT : D3D11_CULL_BACK) : D3D11_CULL_NONE;
|
||||
}
|
||||
ID3D11RasterizerState *rs = nullptr;
|
||||
auto rasterIter = rasterCache_.find(keys_.raster.value);
|
||||
if (rasterIter == rasterCache_.end()) {
|
||||
D3D11_RASTERIZER_DESC desc{};
|
||||
desc.CullMode = (D3D11_CULL_MODE)(keys_.raster.cullMode);
|
||||
desc.FillMode = D3D11_FILL_SOLID;
|
||||
desc.ScissorEnable = TRUE;
|
||||
desc.FrontCounterClockwise = TRUE;
|
||||
desc.DepthClipEnable = TRUE;
|
||||
ASSERT_SUCCESS(device_->CreateRasterizerState(&desc, &rs));
|
||||
rasterCache_.insert(std::pair<uint32_t, ID3D11RasterizerState *>(keys_.raster.value, rs));
|
||||
} else {
|
||||
rs = rasterIter->second;
|
||||
}
|
||||
rasterState_ = rs;
|
||||
}
|
||||
|
||||
{
|
||||
// Set ColorMask/Stencil/Depth
|
||||
if (gstate.isModeClear()) {
|
||||
keys_.depthStencil.value = 0;
|
||||
keys_.depthStencil.depthTestEnable = true;
|
||||
keys_.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS;
|
||||
keys_.depthStencil.depthWriteEnable = gstate.isClearModeDepthMask();
|
||||
if (gstate.isClearModeDepthMask()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Stencil Test
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
if (alphaMask) {
|
||||
keys_.depthStencil.stencilTestEnable = true;
|
||||
keys_.depthStencil.stencilCompareFunc = D3D11_COMPARISON_ALWAYS;
|
||||
keys_.depthStencil.stencilPassOp = D3D11_STENCIL_OP_REPLACE;
|
||||
keys_.depthStencil.stencilFailOp = D3D11_STENCIL_OP_REPLACE;
|
||||
keys_.depthStencil.stencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
|
||||
dynState_.useStencil = true;
|
||||
// In clear mode, the stencil value is set to the alpha value of the vertex.
|
||||
// A normal clear will be 2 points, the second point has the color.
|
||||
// We override this value in the pipeline from software transform for clear rectangles.
|
||||
dynState_.stencilRef = 0xFF;
|
||||
keys_.depthStencil.stencilWriteMask = 0xFF;
|
||||
} else {
|
||||
keys_.depthStencil.stencilTestEnable = false;
|
||||
dynState_.useStencil = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
keys_.depthStencil.value = 0;
|
||||
// Depth Test
|
||||
if (gstate.isDepthTestEnabled()) {
|
||||
keys_.depthStencil.depthTestEnable = true;
|
||||
keys_.depthStencil.depthCompareOp = compareOps[gstate.getDepthTestFunction()];
|
||||
keys_.depthStencil.depthWriteEnable = gstate.isDepthWriteEnabled();
|
||||
if (gstate.isDepthWriteEnabled()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
} else {
|
||||
keys_.depthStencil.depthTestEnable = false;
|
||||
keys_.depthStencil.depthWriteEnable = false;
|
||||
keys_.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS;
|
||||
}
|
||||
|
||||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
// Stencil Test
|
||||
if (stencilState.enabled) {
|
||||
keys_.depthStencil.stencilTestEnable = true;
|
||||
keys_.depthStencil.stencilCompareFunc = compareOps[stencilState.testFunc];
|
||||
keys_.depthStencil.stencilPassOp = stencilOps[stencilState.zPass];
|
||||
keys_.depthStencil.stencilFailOp = stencilOps[stencilState.sFail];
|
||||
keys_.depthStencil.stencilDepthFailOp = stencilOps[stencilState.zFail];
|
||||
keys_.depthStencil.stencilCompareMask = stencilState.testMask;
|
||||
keys_.depthStencil.stencilWriteMask = stencilState.writeMask;
|
||||
dynState_.useStencil = true;
|
||||
dynState_.stencilRef = stencilState.testRef;
|
||||
} else {
|
||||
keys_.depthStencil.stencilTestEnable = false;
|
||||
dynState_.useStencil = false;
|
||||
}
|
||||
}
|
||||
|
||||
keys_.blend.colorWriteMask = (rmask ? 1 : 0) | (gmask ? 2 : 0) | (bmask ? 4 : 0) | (amask ? 8 : 0);
|
||||
|
||||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
// Stencil Test
|
||||
if (stencilState.enabled) {
|
||||
keys_.depthStencil.stencilTestEnable = true;
|
||||
keys_.depthStencil.stencilCompareFunc = compareOps[stencilState.testFunc];
|
||||
keys_.depthStencil.stencilPassOp = stencilOps[stencilState.zPass];
|
||||
keys_.depthStencil.stencilFailOp = stencilOps[stencilState.sFail];
|
||||
keys_.depthStencil.stencilDepthFailOp = stencilOps[stencilState.zFail];
|
||||
keys_.depthStencil.stencilCompareMask = stencilState.testMask;
|
||||
keys_.depthStencil.stencilWriteMask = stencilState.writeMask;
|
||||
dynState_.useStencil = true;
|
||||
dynState_.stencilRef = stencilState.testRef;
|
||||
ID3D11DepthStencilState *ds = nullptr;
|
||||
auto depthIter = depthStencilCache_.find(keys_.depthStencil.value);
|
||||
if (depthIter == depthStencilCache_.end()) {
|
||||
D3D11_DEPTH_STENCIL_DESC desc{};
|
||||
desc.DepthEnable = keys_.depthStencil.depthTestEnable;
|
||||
desc.DepthWriteMask = keys_.depthStencil.depthWriteEnable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
|
||||
desc.DepthFunc = (D3D11_COMPARISON_FUNC)keys_.depthStencil.depthCompareOp;
|
||||
desc.StencilEnable = keys_.depthStencil.stencilTestEnable;
|
||||
desc.StencilReadMask = keys_.depthStencil.stencilCompareMask;
|
||||
desc.StencilWriteMask = keys_.depthStencil.stencilWriteMask;
|
||||
desc.FrontFace.StencilFailOp = (D3D11_STENCIL_OP)keys_.depthStencil.stencilFailOp;
|
||||
desc.FrontFace.StencilPassOp = (D3D11_STENCIL_OP)keys_.depthStencil.stencilPassOp;
|
||||
desc.FrontFace.StencilDepthFailOp = (D3D11_STENCIL_OP)keys_.depthStencil.stencilDepthFailOp;
|
||||
desc.FrontFace.StencilFunc = (D3D11_COMPARISON_FUNC)keys_.depthStencil.stencilCompareFunc;
|
||||
desc.BackFace = desc.FrontFace;
|
||||
ASSERT_SUCCESS(device_->CreateDepthStencilState(&desc, &ds));
|
||||
depthStencilCache_.insert(std::pair<uint64_t, ID3D11DepthStencilState *>(keys_.depthStencil.value, ds));
|
||||
} else {
|
||||
keys_.depthStencil.stencilTestEnable = false;
|
||||
dynState_.useStencil = false;
|
||||
ds = depthIter->second;
|
||||
}
|
||||
depthStencilState_ = ds;
|
||||
}
|
||||
|
||||
{
|
||||
ViewportAndScissor vpAndScissor;
|
||||
ConvertViewportAndScissor(useBufferedRendering,
|
||||
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
|
||||
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
|
||||
vpAndScissor);
|
||||
|
||||
float depthMin = vpAndScissor.depthRangeMin;
|
||||
float depthMax = vpAndScissor.depthRangeMax;
|
||||
|
||||
if (depthMin < 0.0f) depthMin = 0.0f;
|
||||
if (depthMax > 1.0f) depthMax = 1.0f;
|
||||
if (vpAndScissor.dirtyDepth) {
|
||||
gstate_c.Dirty(DIRTY_DEPTHRANGE);
|
||||
}
|
||||
|
||||
Draw::Viewport &vp = dynState_.viewport;
|
||||
vp.TopLeftX = vpAndScissor.viewportX;
|
||||
vp.TopLeftY = vpAndScissor.viewportY;
|
||||
vp.Width = vpAndScissor.viewportW;
|
||||
vp.Height = vpAndScissor.viewportH;
|
||||
vp.MinDepth = depthMin;
|
||||
vp.MaxDepth = depthMax;
|
||||
if (vpAndScissor.dirtyProj) {
|
||||
gstate_c.Dirty(DIRTY_PROJMATRIX);
|
||||
}
|
||||
|
||||
D3D11_RECT &scissor = dynState_.scissor;
|
||||
if (vpAndScissor.scissorEnable) {
|
||||
scissor.left = vpAndScissor.scissorX;
|
||||
scissor.top = vpAndScissor.scissorY;
|
||||
scissor.right = vpAndScissor.scissorX + std::max(0, vpAndScissor.scissorW);
|
||||
scissor.bottom = vpAndScissor.scissorY + std::max(0, vpAndScissor.scissorH);
|
||||
} else {
|
||||
scissor.left = 0;
|
||||
scissor.top = 0;
|
||||
scissor.right = framebufferManager_->GetRenderWidth();
|
||||
scissor.bottom = framebufferManager_->GetRenderHeight();
|
||||
}
|
||||
}
|
||||
|
||||
dynState_.topology = primToD3D11[prim];
|
||||
|
||||
ViewportAndScissor vpAndScissor;
|
||||
ConvertViewportAndScissor(useBufferedRendering,
|
||||
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
|
||||
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
|
||||
vpAndScissor);
|
||||
|
||||
float depthMin = vpAndScissor.depthRangeMin;
|
||||
float depthMax = vpAndScissor.depthRangeMax;
|
||||
|
||||
if (depthMin < 0.0f) depthMin = 0.0f;
|
||||
if (depthMax > 1.0f) depthMax = 1.0f;
|
||||
if (vpAndScissor.dirtyDepth) {
|
||||
gstate_c.Dirty(DIRTY_DEPTHRANGE);
|
||||
}
|
||||
|
||||
Draw::Viewport &vp = dynState_.viewport;
|
||||
vp.TopLeftX = vpAndScissor.viewportX;
|
||||
vp.TopLeftY = vpAndScissor.viewportY;
|
||||
vp.Width = vpAndScissor.viewportW;
|
||||
vp.Height = vpAndScissor.viewportH;
|
||||
vp.MinDepth = depthMin;
|
||||
vp.MaxDepth = depthMax;
|
||||
if (vpAndScissor.dirtyProj) {
|
||||
gstate_c.Dirty(DIRTY_PROJMATRIX);
|
||||
}
|
||||
|
||||
D3D11_RECT &scissor = dynState_.scissor;
|
||||
if (vpAndScissor.scissorEnable) {
|
||||
scissor.left = vpAndScissor.scissorX;
|
||||
scissor.top = vpAndScissor.scissorY;
|
||||
scissor.right = vpAndScissor.scissorX + std::max(0, vpAndScissor.scissorW);
|
||||
scissor.bottom = vpAndScissor.scissorY + std::max(0, vpAndScissor.scissorH);
|
||||
}
|
||||
else {
|
||||
scissor.left = 0;
|
||||
scissor.top = 0;
|
||||
scissor.right = framebufferManager_->GetRenderWidth();
|
||||
scissor.bottom = framebufferManager_->GetRenderHeight();
|
||||
}
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
|
||||
textureCache_->SetTexture();
|
||||
gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
@ -354,89 +440,6 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
|
||||
gstate_c.Dirty(DIRTY_TEXCLAMP);
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11BlendState *bs = nullptr;
|
||||
ID3D11BlendState1 *bs1 = nullptr;
|
||||
ID3D11DepthStencilState *ds = nullptr;
|
||||
ID3D11RasterizerState *rs = nullptr;
|
||||
|
||||
if (!device1_) {
|
||||
auto blendIter = blendCache_.find(keys_.blend.value);
|
||||
if (blendIter == blendCache_.end()) {
|
||||
D3D11_BLEND_DESC desc{};
|
||||
D3D11_RENDER_TARGET_BLEND_DESC &rt = desc.RenderTarget[0];
|
||||
rt.BlendEnable = keys_.blend.blendEnable;
|
||||
rt.BlendOp = (D3D11_BLEND_OP)keys_.blend.blendOpColor;
|
||||
rt.BlendOpAlpha = (D3D11_BLEND_OP)keys_.blend.blendOpAlpha;
|
||||
rt.SrcBlend = (D3D11_BLEND)keys_.blend.srcColor;
|
||||
rt.DestBlend = (D3D11_BLEND)keys_.blend.destColor;
|
||||
rt.SrcBlendAlpha = (D3D11_BLEND)keys_.blend.srcAlpha;
|
||||
rt.DestBlendAlpha = (D3D11_BLEND)keys_.blend.destAlpha;
|
||||
rt.RenderTargetWriteMask = keys_.blend.colorWriteMask;
|
||||
ASSERT_SUCCESS(device_->CreateBlendState(&desc, &bs));
|
||||
blendCache_.insert(std::pair<uint64_t, ID3D11BlendState *>(keys_.blend.value, bs));
|
||||
} else {
|
||||
bs = blendIter->second;
|
||||
}
|
||||
blendState_ = bs;
|
||||
} else {
|
||||
auto blendIter = blendCache1_.find(keys_.blend.value);
|
||||
if (blendIter == blendCache1_.end()) {
|
||||
D3D11_BLEND_DESC1 desc1{};
|
||||
D3D11_RENDER_TARGET_BLEND_DESC1 &rt = desc1.RenderTarget[0];
|
||||
rt.BlendEnable = keys_.blend.blendEnable;
|
||||
rt.BlendOp = (D3D11_BLEND_OP)keys_.blend.blendOpColor;
|
||||
rt.BlendOpAlpha = (D3D11_BLEND_OP)keys_.blend.blendOpAlpha;
|
||||
rt.SrcBlend = (D3D11_BLEND)keys_.blend.srcColor;
|
||||
rt.DestBlend = (D3D11_BLEND)keys_.blend.destColor;
|
||||
rt.SrcBlendAlpha = (D3D11_BLEND)keys_.blend.srcAlpha;
|
||||
rt.DestBlendAlpha = (D3D11_BLEND)keys_.blend.destAlpha;
|
||||
rt.RenderTargetWriteMask = keys_.blend.colorWriteMask;
|
||||
rt.LogicOpEnable = keys_.blend.logicOpEnable;
|
||||
rt.LogicOp = (D3D11_LOGIC_OP)keys_.blend.logicOp;
|
||||
ASSERT_SUCCESS(device1_->CreateBlendState1(&desc1, &bs1));
|
||||
blendCache1_.insert(std::pair<uint64_t, ID3D11BlendState1 *>(keys_.blend.value, bs1));
|
||||
} else {
|
||||
bs1 = blendIter->second;
|
||||
}
|
||||
blendState1_ = bs1;
|
||||
}
|
||||
|
||||
auto depthIter = depthStencilCache_.find(keys_.depthStencil.value);
|
||||
if (depthIter == depthStencilCache_.end()) {
|
||||
D3D11_DEPTH_STENCIL_DESC desc{};
|
||||
desc.DepthEnable = keys_.depthStencil.depthTestEnable;
|
||||
desc.DepthWriteMask = keys_.depthStencil.depthWriteEnable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
|
||||
desc.DepthFunc = (D3D11_COMPARISON_FUNC)keys_.depthStencil.depthCompareOp;
|
||||
desc.StencilEnable = keys_.depthStencil.stencilTestEnable;
|
||||
desc.StencilReadMask = keys_.depthStencil.stencilCompareMask;
|
||||
desc.StencilWriteMask = keys_.depthStencil.stencilWriteMask;
|
||||
desc.FrontFace.StencilFailOp = (D3D11_STENCIL_OP)keys_.depthStencil.stencilFailOp;
|
||||
desc.FrontFace.StencilPassOp = (D3D11_STENCIL_OP)keys_.depthStencil.stencilPassOp;
|
||||
desc.FrontFace.StencilDepthFailOp = (D3D11_STENCIL_OP)keys_.depthStencil.stencilDepthFailOp;
|
||||
desc.FrontFace.StencilFunc = (D3D11_COMPARISON_FUNC)keys_.depthStencil.stencilCompareFunc;
|
||||
desc.BackFace = desc.FrontFace;
|
||||
ASSERT_SUCCESS(device_->CreateDepthStencilState(&desc, &ds));
|
||||
depthStencilCache_.insert(std::pair<uint64_t, ID3D11DepthStencilState *>(keys_.depthStencil.value, ds));
|
||||
} else {
|
||||
ds = depthIter->second;
|
||||
}
|
||||
depthStencilState_ = ds;
|
||||
|
||||
auto rasterIter = rasterCache_.find(keys_.raster.value);
|
||||
if (rasterIter == rasterCache_.end()) {
|
||||
D3D11_RASTERIZER_DESC desc{};
|
||||
desc.CullMode = (D3D11_CULL_MODE)(keys_.raster.cullMode);
|
||||
desc.FillMode = D3D11_FILL_SOLID;
|
||||
desc.ScissorEnable = TRUE;
|
||||
desc.FrontCounterClockwise = TRUE;
|
||||
desc.DepthClipEnable = TRUE;
|
||||
ASSERT_SUCCESS(device_->CreateRasterizerState(&desc, &rs));
|
||||
rasterCache_.insert(std::pair<uint32_t, ID3D11RasterizerState *>(keys_.raster.value, rs));
|
||||
} else {
|
||||
rs = rasterIter->second;
|
||||
}
|
||||
rasterState_ = rs;
|
||||
}
|
||||
|
||||
void DrawEngineD3D11::ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef) {
|
||||
|
@ -424,15 +424,15 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra
|
||||
const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor;
|
||||
|
||||
TexCacheEntry::Status alphaStatus = CheckAlpha(clutBuf_, GetClutDestFormatD3D11(clutFormat), clutTotalColors, clutTotalColors, 1);
|
||||
gstate_c.textureFullAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL;
|
||||
gstate_c.textureSimpleAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE;
|
||||
gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL);
|
||||
gstate_c.SetTextureSimpleAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE);
|
||||
} else {
|
||||
entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE;
|
||||
|
||||
framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET);
|
||||
|
||||
gstate_c.textureFullAlpha = gstate.getTextureFormat() == GE_TFMT_5650;
|
||||
gstate_c.textureSimpleAlpha = gstate_c.textureFullAlpha;
|
||||
gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650);
|
||||
gstate_c.SetTextureSimpleAlpha(gstate_c.textureFullAlpha);
|
||||
framebufferManagerD3D11_->RebindFramebuffer();
|
||||
}
|
||||
SamplerCacheKey samplerKey;
|
||||
|
@ -449,8 +449,6 @@ void GPU_DX9::Execute_VertexTypeSkinning(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_DX9::Execute_Prim(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_PRIM);
|
||||
|
||||
// This drives all drawing. All other state we just buffer up, then we apply it only
|
||||
// when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization.
|
||||
|
||||
@ -462,6 +460,8 @@ void GPU_DX9::Execute_Prim(u32 op, u32 diff) {
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
SetDrawType(DRAW_PRIM, prim);
|
||||
|
||||
// Discard AA lines as we can't do anything that makes sense with these anyway. The SW plugin might, though.
|
||||
|
||||
if (gstate.isAntiAliasEnabled()) {
|
||||
@ -520,8 +520,6 @@ void GPU_DX9::Execute_Prim(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_DX9::Execute_Bezier(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_BEZIER);
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@ -555,6 +553,7 @@ void GPU_DX9::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
|
||||
SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim));
|
||||
int bz_ucount = op & 0xFF;
|
||||
int bz_vcount = (op >> 8) & 0xFF;
|
||||
bool computeNormals = gstate.isLightingEnabled();
|
||||
@ -568,8 +567,6 @@ void GPU_DX9::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_DX9::Execute_Spline(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_SPLINE);
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@ -607,6 +604,7 @@ void GPU_DX9::Execute_Spline(u32 op, u32 diff) {
|
||||
int sp_utype = (op >> 16) & 0x3;
|
||||
int sp_vtype = (op >> 18) & 0x3;
|
||||
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
|
||||
SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim));
|
||||
bool computeNormals = gstate.isLightingEnabled();
|
||||
bool patchFacing = gstate.patchfacing & 1;
|
||||
u32 vertType = gstate.vertType;
|
||||
|
@ -115,167 +115,180 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
||||
|
||||
bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
|
||||
|
||||
// Unfortunately, this isn't implemented yet.
|
||||
gstate_c.allowShaderBlend = false;
|
||||
{
|
||||
// Unfortunately, this isn't implemented yet.
|
||||
gstate_c.SetAllowShaderBlend(false);
|
||||
if (gstate.isModeClear()) {
|
||||
dxstate.blend.disable();
|
||||
|
||||
// Set blend - unless we need to do it in the shader.
|
||||
GenericBlendState blendState;
|
||||
ConvertBlendState(blendState, gstate_c.allowShaderBlend);
|
||||
|
||||
ViewportAndScissor vpAndScissor;
|
||||
ConvertViewportAndScissor(useBufferedRendering,
|
||||
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
|
||||
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
|
||||
vpAndScissor);
|
||||
|
||||
if (blendState.applyShaderBlending) {
|
||||
if (ApplyShaderBlending()) {
|
||||
// We may still want to do something about stencil -> alpha.
|
||||
ApplyStencilReplaceAndLogicOp(blendState.replaceAlphaWithStencil, blendState);
|
||||
// Color Mask
|
||||
bool colorMask = gstate.isClearModeColorMask();
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
dxstate.colorMask.set(colorMask, colorMask, colorMask, alphaMask);
|
||||
} else {
|
||||
// Until next time, force it off.
|
||||
ResetShaderBlending();
|
||||
gstate_c.allowShaderBlend = false;
|
||||
}
|
||||
} else if (blendState.resetShaderBlending) {
|
||||
ResetShaderBlending();
|
||||
}
|
||||
// Set blend - unless we need to do it in the shader.
|
||||
GenericBlendState blendState;
|
||||
ConvertBlendState(blendState, gstate_c.allowShaderBlend);
|
||||
|
||||
if (blendState.enabled) {
|
||||
dxstate.blend.enable();
|
||||
dxstate.blendSeparate.enable();
|
||||
dxstate.blendEquation.set(dxBlendEqLookup[(size_t)blendState.eqColor], dxBlendEqLookup[(size_t)blendState.eqAlpha]);
|
||||
dxstate.blendFunc.set(
|
||||
dxBlendFactorLookup[(size_t)blendState.srcColor], dxBlendFactorLookup[(size_t)blendState.dstColor],
|
||||
dxBlendFactorLookup[(size_t)blendState.srcAlpha], dxBlendFactorLookup[(size_t)blendState.dstAlpha]);
|
||||
if (blendState.dirtyShaderBlend) {
|
||||
gstate_c.Dirty(DIRTY_SHADERBLEND);
|
||||
if (blendState.applyShaderBlending) {
|
||||
if (ApplyShaderBlending()) {
|
||||
// We may still want to do something about stencil -> alpha.
|
||||
ApplyStencilReplaceAndLogicOp(blendState.replaceAlphaWithStencil, blendState);
|
||||
} else {
|
||||
// Until next time, force it off.
|
||||
ResetShaderBlending();
|
||||
gstate_c.SetAllowShaderBlend(false);
|
||||
}
|
||||
} else if (blendState.resetShaderBlending) {
|
||||
ResetShaderBlending();
|
||||
}
|
||||
|
||||
if (blendState.enabled) {
|
||||
dxstate.blend.enable();
|
||||
dxstate.blendSeparate.enable();
|
||||
dxstate.blendEquation.set(dxBlendEqLookup[(size_t)blendState.eqColor], dxBlendEqLookup[(size_t)blendState.eqAlpha]);
|
||||
dxstate.blendFunc.set(
|
||||
dxBlendFactorLookup[(size_t)blendState.srcColor], dxBlendFactorLookup[(size_t)blendState.dstColor],
|
||||
dxBlendFactorLookup[(size_t)blendState.srcAlpha], dxBlendFactorLookup[(size_t)blendState.dstAlpha]);
|
||||
if (blendState.dirtyShaderBlend) {
|
||||
gstate_c.Dirty(DIRTY_SHADERBLEND);
|
||||
}
|
||||
if (blendState.useBlendColor) {
|
||||
dxstate.blendColor.setDWORD(blendState.blendColor);
|
||||
}
|
||||
} else {
|
||||
dxstate.blend.disable();
|
||||
}
|
||||
|
||||
// PSP color/alpha mask is per bit but we can only support per byte.
|
||||
// But let's do that, at least. And let's try a threshold.
|
||||
bool rmask = (gstate.pmskc & 0xFF) < 128;
|
||||
bool gmask = ((gstate.pmskc >> 8) & 0xFF) < 128;
|
||||
bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128;
|
||||
bool amask = (gstate.pmska & 0xFF) < 128;
|
||||
|
||||
#ifndef MOBILE_DEVICE
|
||||
u8 abits = (gstate.pmska >> 0) & 0xFF;
|
||||
u8 rbits = (gstate.pmskc >> 0) & 0xFF;
|
||||
u8 gbits = (gstate.pmskc >> 8) & 0xFF;
|
||||
u8 bbits = (gstate.pmskc >> 16) & 0xFF;
|
||||
if ((rbits != 0 && rbits != 0xFF) || (gbits != 0 && gbits != 0xFF) || (bbits != 0 && bbits != 0xFF)) {
|
||||
WARN_LOG_REPORT_ONCE(rgbmask, G3D, "Unsupported RGB mask: r=%02x g=%02x b=%02x", rbits, gbits, bbits);
|
||||
}
|
||||
if (abits != 0 && abits != 0xFF) {
|
||||
// The stencil part of the mask is supported.
|
||||
WARN_LOG_REPORT_ONCE(amask, G3D, "Unsupported alpha/stencil mask: %02x", abits);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Let's not write to alpha if stencil isn't enabled.
|
||||
if (!gstate.isStencilTestEnabled()) {
|
||||
amask = false;
|
||||
} else {
|
||||
// If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel.
|
||||
if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_KEEP) {
|
||||
amask = false;
|
||||
}
|
||||
}
|
||||
|
||||
dxstate.colorMask.set(rmask, gmask, bmask, amask);
|
||||
}
|
||||
if (blendState.useBlendColor) {
|
||||
dxstate.blendColor.setDWORD(blendState.blendColor);
|
||||
}
|
||||
} else {
|
||||
dxstate.blend.disable();
|
||||
}
|
||||
|
||||
bool alwaysDepthWrite = g_Config.bAlwaysDepthWrite;
|
||||
bool enableStencilTest = !g_Config.bDisableStencilTest;
|
||||
|
||||
// Set Dither
|
||||
if (gstate.isDitherEnabled()) {
|
||||
dxstate.dither.enable();
|
||||
} else {
|
||||
dxstate.dither.disable();
|
||||
{
|
||||
// Set Dither
|
||||
if (gstate.isDitherEnabled()) {
|
||||
dxstate.dither.enable();
|
||||
} else {
|
||||
dxstate.dither.disable();
|
||||
}
|
||||
if (gstate.isModeClear()) {
|
||||
// Set Cull
|
||||
dxstate.cullMode.set(false, false);
|
||||
} else {
|
||||
// Set cull
|
||||
bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
|
||||
dxstate.cullMode.set(wantCull, gstate.getCullMode());
|
||||
}
|
||||
}
|
||||
|
||||
// Set ColorMask/Stencil/Depth
|
||||
if (gstate.isModeClear()) {
|
||||
// Set Cull
|
||||
dxstate.cullMode.set(false, false);
|
||||
|
||||
// Depth Test
|
||||
dxstate.depthTest.enable();
|
||||
dxstate.depthFunc.set(D3DCMP_ALWAYS);
|
||||
dxstate.depthWrite.set(gstate.isClearModeDepthMask());
|
||||
if (gstate.isClearModeDepthMask() || alwaysDepthWrite) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Color Test
|
||||
bool colorMask = gstate.isClearModeColorMask();
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
dxstate.colorMask.set(colorMask, colorMask, colorMask, alphaMask);
|
||||
|
||||
// Stencil Test
|
||||
if (alphaMask && enableStencilTest) {
|
||||
dxstate.stencilTest.enable();
|
||||
dxstate.stencilOp.set(D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE);
|
||||
dxstate.stencilFunc.set(D3DCMP_ALWAYS, 255, 0xFF);
|
||||
dxstate.stencilMask.set(0xFF);
|
||||
} else {
|
||||
dxstate.stencilTest.disable();
|
||||
}
|
||||
|
||||
} else {
|
||||
// Set cull
|
||||
bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
|
||||
dxstate.cullMode.set(wantCull, gstate.getCullMode());
|
||||
|
||||
// Depth Test
|
||||
if (gstate.isDepthTestEnabled()) {
|
||||
{
|
||||
// Set Stencil/Depth
|
||||
if (gstate.isModeClear()) {
|
||||
// Depth Test
|
||||
dxstate.depthTest.enable();
|
||||
dxstate.depthFunc.set(ztests[gstate.getDepthTestFunction()]);
|
||||
dxstate.depthWrite.set(gstate.isDepthWriteEnabled());
|
||||
if (gstate.isDepthWriteEnabled()) {
|
||||
dxstate.depthFunc.set(D3DCMP_ALWAYS);
|
||||
dxstate.depthWrite.set(gstate.isClearModeDepthMask());
|
||||
if (gstate.isClearModeDepthMask() || alwaysDepthWrite) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Stencil Test
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
if (alphaMask && enableStencilTest) {
|
||||
dxstate.stencilTest.enable();
|
||||
dxstate.stencilOp.set(D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE);
|
||||
dxstate.stencilFunc.set(D3DCMP_ALWAYS, 255, 0xFF);
|
||||
dxstate.stencilMask.set(0xFF);
|
||||
} else {
|
||||
dxstate.stencilTest.disable();
|
||||
}
|
||||
|
||||
} else {
|
||||
dxstate.depthTest.disable();
|
||||
}
|
||||
// Depth Test
|
||||
if (gstate.isDepthTestEnabled()) {
|
||||
dxstate.depthTest.enable();
|
||||
dxstate.depthFunc.set(ztests[gstate.getDepthTestFunction()]);
|
||||
dxstate.depthWrite.set(gstate.isDepthWriteEnabled());
|
||||
if (gstate.isDepthWriteEnabled()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
} else {
|
||||
dxstate.depthTest.disable();
|
||||
}
|
||||
|
||||
// PSP color/alpha mask is per bit but we can only support per byte.
|
||||
// But let's do that, at least. And let's try a threshold.
|
||||
bool rmask = (gstate.pmskc & 0xFF) < 128;
|
||||
bool gmask = ((gstate.pmskc >> 8) & 0xFF) < 128;
|
||||
bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128;
|
||||
bool amask = (gstate.pmska & 0xFF) < 128;
|
||||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
#ifndef MOBILE_DEVICE
|
||||
u8 abits = (gstate.pmska >> 0) & 0xFF;
|
||||
u8 rbits = (gstate.pmskc >> 0) & 0xFF;
|
||||
u8 gbits = (gstate.pmskc >> 8) & 0xFF;
|
||||
u8 bbits = (gstate.pmskc >> 16) & 0xFF;
|
||||
if ((rbits != 0 && rbits != 0xFF) || (gbits != 0 && gbits != 0xFF) || (bbits != 0 && bbits != 0xFF)) {
|
||||
WARN_LOG_REPORT_ONCE(rgbmask, G3D, "Unsupported RGB mask: r=%02x g=%02x b=%02x", rbits, gbits, bbits);
|
||||
}
|
||||
if (abits != 0 && abits != 0xFF) {
|
||||
// The stencil part of the mask is supported.
|
||||
WARN_LOG_REPORT_ONCE(amask, G3D, "Unsupported alpha/stencil mask: %02x", abits);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Let's not write to alpha if stencil isn't enabled.
|
||||
if (!gstate.isStencilTestEnabled()) {
|
||||
amask = false;
|
||||
} else {
|
||||
// If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel.
|
||||
if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_KEEP) {
|
||||
amask = false;
|
||||
// Stencil Test
|
||||
if (stencilState.enabled) {
|
||||
dxstate.stencilTest.enable();
|
||||
dxstate.stencilFunc.set(ztests[stencilState.testFunc], stencilState.testRef, stencilState.testMask);
|
||||
dxstate.stencilOp.set(stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
|
||||
dxstate.stencilMask.set(stencilState.writeMask);
|
||||
} else {
|
||||
dxstate.stencilTest.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dxstate.colorMask.set(rmask, gmask, bmask, amask);
|
||||
{
|
||||
ViewportAndScissor vpAndScissor;
|
||||
ConvertViewportAndScissor(useBufferedRendering,
|
||||
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
|
||||
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
|
||||
vpAndScissor);
|
||||
|
||||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
// Stencil Test
|
||||
if (stencilState.enabled) {
|
||||
dxstate.stencilTest.enable();
|
||||
dxstate.stencilFunc.set(ztests[stencilState.testFunc], stencilState.testRef, stencilState.testMask);
|
||||
dxstate.stencilOp.set(stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
|
||||
dxstate.stencilMask.set(stencilState.writeMask);
|
||||
if (vpAndScissor.scissorEnable) {
|
||||
dxstate.scissorTest.enable();
|
||||
dxstate.scissorRect.set(vpAndScissor.scissorX, vpAndScissor.scissorY, vpAndScissor.scissorX + vpAndScissor.scissorW, vpAndScissor.scissorY + vpAndScissor.scissorH);
|
||||
} else {
|
||||
dxstate.stencilTest.disable();
|
||||
dxstate.scissorTest.disable();
|
||||
}
|
||||
}
|
||||
|
||||
if (vpAndScissor.scissorEnable) {
|
||||
dxstate.scissorTest.enable();
|
||||
dxstate.scissorRect.set(vpAndScissor.scissorX, vpAndScissor.scissorY, vpAndScissor.scissorX + vpAndScissor.scissorW, vpAndScissor.scissorY + vpAndScissor.scissorH);
|
||||
} else {
|
||||
dxstate.scissorTest.disable();
|
||||
}
|
||||
float depthMin = vpAndScissor.depthRangeMin;
|
||||
float depthMax = vpAndScissor.depthRangeMax;
|
||||
|
||||
float depthMin = vpAndScissor.depthRangeMin;
|
||||
float depthMax = vpAndScissor.depthRangeMax;
|
||||
|
||||
dxstate.viewport.set(vpAndScissor.viewportX, vpAndScissor.viewportY, vpAndScissor.viewportW, vpAndScissor.viewportH, depthMin, depthMax);
|
||||
if (vpAndScissor.dirtyProj) {
|
||||
gstate_c.Dirty(DIRTY_PROJMATRIX);
|
||||
}
|
||||
if (vpAndScissor.dirtyDepth) {
|
||||
gstate_c.Dirty(DIRTY_DEPTHRANGE);
|
||||
dxstate.viewport.set(vpAndScissor.viewportX, vpAndScissor.viewportY, vpAndScissor.viewportW, vpAndScissor.viewportH, depthMin, depthMax);
|
||||
if (vpAndScissor.dirtyProj) {
|
||||
gstate_c.Dirty(DIRTY_PROJMATRIX);
|
||||
}
|
||||
if (vpAndScissor.dirtyDepth) {
|
||||
gstate_c.Dirty(DIRTY_DEPTHRANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,15 +445,15 @@ void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFrame
|
||||
const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor;
|
||||
|
||||
TexCacheEntry::Status alphaStatus = CheckAlpha(clutBuf_, getClutDestFormat(clutFormat), clutTotalColors, clutTotalColors, 1);
|
||||
gstate_c.textureFullAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL;
|
||||
gstate_c.textureSimpleAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE;
|
||||
gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL);
|
||||
gstate_c.SetTextureSimpleAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE);
|
||||
} else {
|
||||
entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE;
|
||||
|
||||
framebufferManagerDX9_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET);
|
||||
|
||||
gstate_c.textureFullAlpha = gstate.getTextureFormat() == GE_TFMT_5650;
|
||||
gstate_c.textureSimpleAlpha = gstate_c.textureFullAlpha;
|
||||
gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650);
|
||||
gstate_c.SetTextureSimpleAlpha(gstate_c.textureFullAlpha);
|
||||
}
|
||||
|
||||
framebufferManagerDX9_->RebindFramebuffer();
|
||||
|
@ -65,7 +65,7 @@ static const GLESCommandTableEntry commandTable[] = {
|
||||
// Changes that dirty the current texture.
|
||||
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, DIRTY_UVSCALEOFFSET, &GPU_GLES::Execute_TexSize0 },
|
||||
|
||||
{ GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE},
|
||||
{ GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE },
|
||||
|
||||
// Changing the vertex type requires us to flush.
|
||||
{ GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_GLES::Execute_VertexType },
|
||||
@ -636,8 +636,6 @@ void GPU_GLES::ExecuteOp(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_GLES::Execute_Prim(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_PRIM);
|
||||
|
||||
// This drives all drawing. All other state we just buffer up, then we apply it only
|
||||
// when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization.
|
||||
|
||||
@ -649,6 +647,8 @@ void GPU_GLES::Execute_Prim(u32 op, u32 diff) {
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
SetDrawType(DRAW_PRIM, prim);
|
||||
|
||||
// Discard AA lines as we can't do anything that makes sense with these anyway. The SW plugin might, though.
|
||||
|
||||
if (gstate.isAntiAliasEnabled()) {
|
||||
@ -728,8 +728,6 @@ void GPU_GLES::Execute_VertexTypeSkinning(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_GLES::Execute_Bezier(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_BEZIER);
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@ -763,6 +761,8 @@ void GPU_GLES::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
|
||||
SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim));
|
||||
|
||||
int bz_ucount = op & 0xFF;
|
||||
int bz_vcount = (op >> 8) & 0xFF;
|
||||
bool computeNormals = gstate.isLightingEnabled();
|
||||
@ -787,8 +787,6 @@ void GPU_GLES::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_GLES::Execute_Spline(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_SPLINE);
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@ -826,6 +824,7 @@ void GPU_GLES::Execute_Spline(u32 op, u32 diff) {
|
||||
int sp_utype = (op >> 16) & 0x3;
|
||||
int sp_vtype = (op >> 18) & 0x3;
|
||||
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
|
||||
SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim));
|
||||
bool computeNormals = gstate.isLightingEnabled();
|
||||
bool patchFacing = gstate.patchfacing & 1;
|
||||
u32 vertType = gstate.vertType;
|
||||
|
@ -130,7 +130,6 @@ inline void DrawEngineGLES::ResetShaderBlending() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: All this setup is so expensive that we'll need dirty flags, or simply do it in the command writes where we detect dirty by xoring. Silly to do all this work on every drawcall.
|
||||
void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
|
||||
textureCache_->SetTexture();
|
||||
@ -145,205 +144,220 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
// Start profiling here to skip SetTexture which is already accounted for
|
||||
PROFILE_THIS_SCOPE("applydrawstate");
|
||||
|
||||
// amask is needed for both stencil and blend state so we keep it outside for now
|
||||
bool amask = (gstate.pmska & 0xFF) < 128;
|
||||
// Let's not write to alpha if stencil isn't enabled.
|
||||
if (!gstate.isStencilTestEnabled()) {
|
||||
amask = false;
|
||||
} else {
|
||||
// If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel.
|
||||
if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_KEEP) {
|
||||
amask = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
|
||||
gstate_c.allowShaderBlend = !g_Config.bDisableSlowFramebufEffects;
|
||||
|
||||
// Do the large chunks of state conversion. We might be able to hide these two behind a dirty-flag each,
|
||||
// to avoid recomputing heavy stuff unnecessarily every draw call.
|
||||
GenericBlendState blendState;
|
||||
ConvertBlendState(blendState, gstate_c.allowShaderBlend);
|
||||
{
|
||||
gstate_c.SetAllowShaderBlend(!g_Config.bDisableSlowFramebufEffects);
|
||||
|
||||
if (blendState.applyShaderBlending) {
|
||||
if (ApplyShaderBlending()) {
|
||||
// We may still want to do something about stencil -> alpha.
|
||||
ApplyStencilReplaceAndLogicOp(blendState.replaceAlphaWithStencil, blendState);
|
||||
} else {
|
||||
// Until next time, force it off.
|
||||
ResetShaderBlending();
|
||||
gstate_c.allowShaderBlend = false;
|
||||
}
|
||||
} else if (blendState.resetShaderBlending) {
|
||||
ResetShaderBlending();
|
||||
}
|
||||
|
||||
if (blendState.enabled) {
|
||||
glstate.blend.enable();
|
||||
glstate.blendEquationSeparate.set(glBlendEqLookup[(size_t)blendState.eqColor], glBlendEqLookup[(size_t)blendState.eqAlpha]);
|
||||
glstate.blendFuncSeparate.set(
|
||||
glBlendFactorLookup[(size_t)blendState.srcColor], glBlendFactorLookup[(size_t)blendState.dstColor],
|
||||
glBlendFactorLookup[(size_t)blendState.srcAlpha], glBlendFactorLookup[(size_t)blendState.dstAlpha]);
|
||||
if (blendState.dirtyShaderBlend) {
|
||||
gstate_c.Dirty(DIRTY_SHADERBLEND);
|
||||
}
|
||||
if (blendState.useBlendColor) {
|
||||
uint32_t color = blendState.blendColor;
|
||||
const float col[4] = {
|
||||
(float)((color & 0xFF) >> 0) * (1.0f / 255.0f),
|
||||
(float)((color & 0xFF00) >> 8) * (1.0f / 255.0f),
|
||||
(float)((color & 0xFF0000) >> 16) * (1.0f / 255.0f),
|
||||
(float)((color & 0xFF000000) >> 24) * (1.0f / 255.0f),
|
||||
};
|
||||
glstate.blendColor.set(col);
|
||||
}
|
||||
} else {
|
||||
glstate.blend.disable();
|
||||
}
|
||||
|
||||
bool alwaysDepthWrite = g_Config.bAlwaysDepthWrite;
|
||||
bool enableStencilTest = !g_Config.bDisableStencilTest;
|
||||
|
||||
// Dither
|
||||
if (gstate.isDitherEnabled()) {
|
||||
glstate.dither.enable();
|
||||
glstate.dither.set(GL_TRUE);
|
||||
} else {
|
||||
glstate.dither.disable();
|
||||
}
|
||||
|
||||
if (gstate.isModeClear()) {
|
||||
if (gstate.isModeClear()) {
|
||||
glstate.blend.disable();
|
||||
// Color Test
|
||||
bool colorMask = gstate.isClearModeColorMask();
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
glstate.colorMask.set(colorMask, colorMask, colorMask, alphaMask);
|
||||
#ifndef USING_GLES2
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
// Logic Ops
|
||||
glstate.colorLogicOp.disable();
|
||||
}
|
||||
#endif
|
||||
// Culling
|
||||
glstate.cullFace.disable();
|
||||
|
||||
// Depth Test
|
||||
glstate.depthTest.enable();
|
||||
glstate.depthFunc.set(GL_ALWAYS);
|
||||
glstate.depthWrite.set(gstate.isClearModeDepthMask() || alwaysDepthWrite ? GL_TRUE : GL_FALSE);
|
||||
if (gstate.isClearModeDepthMask() || alwaysDepthWrite) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Color Test
|
||||
bool colorMask = gstate.isClearModeColorMask();
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
glstate.colorMask.set(colorMask, colorMask, colorMask, alphaMask);
|
||||
|
||||
// Stencil Test
|
||||
if (alphaMask && enableStencilTest) {
|
||||
glstate.stencilTest.enable();
|
||||
glstate.stencilOp.set(GL_REPLACE, GL_REPLACE, GL_REPLACE);
|
||||
// TODO: In clear mode, the stencil value is set to the alpha value of the vertex.
|
||||
// A normal clear will be 2 points, the second point has the color.
|
||||
// We should set "ref" to that value instead of 0.
|
||||
// In case of clear rectangles, we set it again once we know what the color is.
|
||||
glstate.stencilFunc.set(GL_ALWAYS, 255, 0xFF);
|
||||
glstate.stencilMask.set(0xFF);
|
||||
} else {
|
||||
glstate.stencilTest.disable();
|
||||
}
|
||||
} else {
|
||||
#ifndef USING_GLES2
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
// TODO: Make this dynamic
|
||||
// Logic Ops
|
||||
if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) {
|
||||
glstate.colorLogicOp.enable();
|
||||
glstate.logicOp.set(logicOps[gstate.getLogicOp()]);
|
||||
} else {
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
// Logic Ops
|
||||
glstate.colorLogicOp.disable();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Set cull
|
||||
bool cullEnabled = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
|
||||
if (cullEnabled) {
|
||||
glstate.cullFace.enable();
|
||||
glstate.cullFaceMode.set(cullingMode[gstate.getCullMode() ^ !useBufferedRendering]);
|
||||
} else {
|
||||
glstate.cullFace.disable();
|
||||
}
|
||||
// Do the large chunks of state conversion. We might be able to hide these two behind a dirty-flag each,
|
||||
// to avoid recomputing heavy stuff unnecessarily every draw call.
|
||||
GenericBlendState blendState;
|
||||
ConvertBlendState(blendState, gstate_c.allowShaderBlend);
|
||||
|
||||
// Depth Test
|
||||
if (gstate.isDepthTestEnabled()) {
|
||||
glstate.depthTest.enable();
|
||||
glstate.depthFunc.set(compareOps[gstate.getDepthTestFunction()]);
|
||||
glstate.depthWrite.set(gstate.isDepthWriteEnabled() || alwaysDepthWrite ? GL_TRUE : GL_FALSE);
|
||||
if (gstate.isDepthWriteEnabled() || alwaysDepthWrite) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
if (blendState.applyShaderBlending) {
|
||||
if (ApplyShaderBlending()) {
|
||||
// We may still want to do something about stencil -> alpha.
|
||||
ApplyStencilReplaceAndLogicOp(blendState.replaceAlphaWithStencil, blendState);
|
||||
} else {
|
||||
// Until next time, force it off.
|
||||
ResetShaderBlending();
|
||||
gstate_c.SetAllowShaderBlend(false);
|
||||
}
|
||||
} else if (blendState.resetShaderBlending) {
|
||||
ResetShaderBlending();
|
||||
}
|
||||
} else {
|
||||
glstate.depthTest.disable();
|
||||
}
|
||||
|
||||
// PSP color/alpha mask is per bit but we can only support per byte.
|
||||
// But let's do that, at least. And let's try a threshold.
|
||||
bool rmask = (gstate.pmskc & 0xFF) < 128;
|
||||
bool gmask = ((gstate.pmskc >> 8) & 0xFF) < 128;
|
||||
bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128;
|
||||
bool amask = (gstate.pmska & 0xFF) < 128;
|
||||
if (blendState.enabled) {
|
||||
glstate.blend.enable();
|
||||
glstate.blendEquationSeparate.set(glBlendEqLookup[(size_t)blendState.eqColor], glBlendEqLookup[(size_t)blendState.eqAlpha]);
|
||||
glstate.blendFuncSeparate.set(
|
||||
glBlendFactorLookup[(size_t)blendState.srcColor], glBlendFactorLookup[(size_t)blendState.dstColor],
|
||||
glBlendFactorLookup[(size_t)blendState.srcAlpha], glBlendFactorLookup[(size_t)blendState.dstAlpha]);
|
||||
if (blendState.dirtyShaderBlend) {
|
||||
gstate_c.Dirty(DIRTY_SHADERBLEND);
|
||||
}
|
||||
if (blendState.useBlendColor) {
|
||||
uint32_t color = blendState.blendColor;
|
||||
const float col[4] = {
|
||||
(float)((color & 0xFF) >> 0) * (1.0f / 255.0f),
|
||||
(float)((color & 0xFF00) >> 8) * (1.0f / 255.0f),
|
||||
(float)((color & 0xFF0000) >> 16) * (1.0f / 255.0f),
|
||||
(float)((color & 0xFF000000) >> 24) * (1.0f / 255.0f),
|
||||
};
|
||||
glstate.blendColor.set(col);
|
||||
}
|
||||
} else {
|
||||
glstate.blend.disable();
|
||||
}
|
||||
|
||||
// PSP color/alpha mask is per bit but we can only support per byte.
|
||||
// But let's do that, at least. And let's try a threshold.
|
||||
bool rmask = (gstate.pmskc & 0xFF) < 128;
|
||||
bool gmask = ((gstate.pmskc >> 8) & 0xFF) < 128;
|
||||
bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128;
|
||||
|
||||
#ifndef MOBILE_DEVICE
|
||||
u8 abits = (gstate.pmska >> 0) & 0xFF;
|
||||
u8 rbits = (gstate.pmskc >> 0) & 0xFF;
|
||||
u8 gbits = (gstate.pmskc >> 8) & 0xFF;
|
||||
u8 bbits = (gstate.pmskc >> 16) & 0xFF;
|
||||
if ((rbits != 0 && rbits != 0xFF) || (gbits != 0 && gbits != 0xFF) || (bbits != 0 && bbits != 0xFF)) {
|
||||
WARN_LOG_REPORT_ONCE(rgbmask, G3D, "Unsupported RGB mask: r=%02x g=%02x b=%02x", rbits, gbits, bbits);
|
||||
}
|
||||
if (abits != 0 && abits != 0xFF) {
|
||||
// The stencil part of the mask is supported.
|
||||
WARN_LOG_REPORT_ONCE(amask, G3D, "Unsupported alpha/stencil mask: %02x", abits);
|
||||
}
|
||||
u8 abits = (gstate.pmska >> 0) & 0xFF;
|
||||
u8 rbits = (gstate.pmskc >> 0) & 0xFF;
|
||||
u8 gbits = (gstate.pmskc >> 8) & 0xFF;
|
||||
u8 bbits = (gstate.pmskc >> 16) & 0xFF;
|
||||
if ((rbits != 0 && rbits != 0xFF) || (gbits != 0 && gbits != 0xFF) || (bbits != 0 && bbits != 0xFF)) {
|
||||
WARN_LOG_REPORT_ONCE(rgbmask, G3D, "Unsupported RGB mask: r=%02x g=%02x b=%02x", rbits, gbits, bbits);
|
||||
}
|
||||
if (abits != 0 && abits != 0xFF) {
|
||||
// The stencil part of the mask is supported.
|
||||
WARN_LOG_REPORT_ONCE(amask, G3D, "Unsupported alpha/stencil mask: %02x", abits);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Let's not write to alpha if stencil isn't enabled.
|
||||
if (!gstate.isStencilTestEnabled()) {
|
||||
amask = false;
|
||||
glstate.colorMask.set(rmask, gmask, bmask, amask);
|
||||
|
||||
#ifndef USING_GLES2
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
// TODO: Make this dynamic
|
||||
// Logic Ops
|
||||
if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) {
|
||||
glstate.colorLogicOp.enable();
|
||||
glstate.logicOp.set(logicOps[gstate.getLogicOp()]);
|
||||
} else {
|
||||
glstate.colorLogicOp.disable();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Dither
|
||||
if (gstate.isDitherEnabled()) {
|
||||
glstate.dither.enable();
|
||||
glstate.dither.set(GL_TRUE);
|
||||
} else {
|
||||
// If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel.
|
||||
if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_KEEP) {
|
||||
amask = false;
|
||||
glstate.dither.disable();
|
||||
}
|
||||
|
||||
if (gstate.isModeClear()) {
|
||||
// Culling
|
||||
glstate.cullFace.disable();
|
||||
} else {
|
||||
// Set cull
|
||||
bool cullEnabled = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
|
||||
if (cullEnabled) {
|
||||
glstate.cullFace.enable();
|
||||
glstate.cullFaceMode.set(cullingMode[gstate.getCullMode() ^ !useBufferedRendering]);
|
||||
} else {
|
||||
glstate.cullFace.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glstate.colorMask.set(rmask, gmask, bmask, amask);
|
||||
{
|
||||
bool alwaysDepthWrite = g_Config.bAlwaysDepthWrite;
|
||||
bool enableStencilTest = !g_Config.bDisableStencilTest;
|
||||
if (gstate.isModeClear()) {
|
||||
// Depth Test
|
||||
glstate.depthTest.enable();
|
||||
glstate.depthFunc.set(GL_ALWAYS);
|
||||
glstate.depthWrite.set(gstate.isClearModeDepthMask() || alwaysDepthWrite ? GL_TRUE : GL_FALSE);
|
||||
if (gstate.isClearModeDepthMask() || alwaysDepthWrite) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
// Stencil Test
|
||||
if (stencilState.enabled) {
|
||||
glstate.stencilTest.enable();
|
||||
glstate.stencilFunc.set(compareOps[stencilState.testFunc], stencilState.testRef, stencilState.testMask);
|
||||
glstate.stencilOp.set(stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
|
||||
glstate.stencilMask.set(stencilState.writeMask);
|
||||
// Stencil Test
|
||||
if (gstate.isClearModeAlphaMask() && enableStencilTest) {
|
||||
glstate.stencilTest.enable();
|
||||
glstate.stencilOp.set(GL_REPLACE, GL_REPLACE, GL_REPLACE);
|
||||
// TODO: In clear mode, the stencil value is set to the alpha value of the vertex.
|
||||
// A normal clear will be 2 points, the second point has the color.
|
||||
// We should set "ref" to that value instead of 0.
|
||||
// In case of clear rectangles, we set it again once we know what the color is.
|
||||
glstate.stencilFunc.set(GL_ALWAYS, 255, 0xFF);
|
||||
glstate.stencilMask.set(0xFF);
|
||||
} else {
|
||||
glstate.stencilTest.disable();
|
||||
}
|
||||
} else {
|
||||
glstate.stencilTest.disable();
|
||||
// Depth Test
|
||||
if (gstate.isDepthTestEnabled()) {
|
||||
glstate.depthTest.enable();
|
||||
glstate.depthFunc.set(compareOps[gstate.getDepthTestFunction()]);
|
||||
glstate.depthWrite.set(gstate.isDepthWriteEnabled() || alwaysDepthWrite ? GL_TRUE : GL_FALSE);
|
||||
if (gstate.isDepthWriteEnabled() || alwaysDepthWrite) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
} else {
|
||||
glstate.depthTest.disable();
|
||||
}
|
||||
|
||||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
// Stencil Test
|
||||
if (stencilState.enabled) {
|
||||
glstate.stencilTest.enable();
|
||||
glstate.stencilFunc.set(compareOps[stencilState.testFunc], stencilState.testRef, stencilState.testMask);
|
||||
glstate.stencilOp.set(stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
|
||||
glstate.stencilMask.set(stencilState.writeMask);
|
||||
} else {
|
||||
glstate.stencilTest.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ViewportAndScissor vpAndScissor;
|
||||
ConvertViewportAndScissor(useBufferedRendering,
|
||||
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
|
||||
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
|
||||
vpAndScissor);
|
||||
{
|
||||
ViewportAndScissor vpAndScissor;
|
||||
ConvertViewportAndScissor(useBufferedRendering,
|
||||
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
|
||||
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
|
||||
vpAndScissor);
|
||||
|
||||
if (vpAndScissor.scissorEnable) {
|
||||
glstate.scissorTest.enable();
|
||||
if (!useBufferedRendering) {
|
||||
vpAndScissor.scissorY = PSP_CoreParameter().pixelHeight - vpAndScissor.scissorH - vpAndScissor.scissorY;
|
||||
}
|
||||
glstate.scissorRect.set(vpAndScissor.scissorX, vpAndScissor.scissorY, vpAndScissor.scissorW, vpAndScissor.scissorH);
|
||||
} else {
|
||||
glstate.scissorTest.disable();
|
||||
}
|
||||
|
||||
if (vpAndScissor.scissorEnable) {
|
||||
glstate.scissorTest.enable();
|
||||
if (!useBufferedRendering) {
|
||||
vpAndScissor.scissorY = PSP_CoreParameter().pixelHeight - vpAndScissor.scissorH - vpAndScissor.scissorY;
|
||||
vpAndScissor.viewportY = PSP_CoreParameter().pixelHeight - vpAndScissor.viewportH - vpAndScissor.viewportY;
|
||||
}
|
||||
glstate.scissorRect.set(vpAndScissor.scissorX, vpAndScissor.scissorY, vpAndScissor.scissorW, vpAndScissor.scissorH);
|
||||
} else {
|
||||
glstate.scissorTest.disable();
|
||||
}
|
||||
glstate.viewport.set(vpAndScissor.viewportX, vpAndScissor.viewportY, vpAndScissor.viewportW, vpAndScissor.viewportH);
|
||||
glstate.depthRange.set(vpAndScissor.depthRangeMin, vpAndScissor.depthRangeMax);
|
||||
|
||||
if (!useBufferedRendering) {
|
||||
vpAndScissor.viewportY = PSP_CoreParameter().pixelHeight - vpAndScissor.viewportH - vpAndScissor.viewportY;
|
||||
}
|
||||
glstate.viewport.set(vpAndScissor.viewportX, vpAndScissor.viewportY, vpAndScissor.viewportW, vpAndScissor.viewportH);
|
||||
glstate.depthRange.set(vpAndScissor.depthRangeMin, vpAndScissor.depthRangeMax);
|
||||
|
||||
if (vpAndScissor.dirtyProj) {
|
||||
gstate_c.Dirty(DIRTY_PROJMATRIX);
|
||||
}
|
||||
if (vpAndScissor.dirtyDepth) {
|
||||
gstate_c.Dirty(DIRTY_DEPTHRANGE);
|
||||
if (vpAndScissor.dirtyProj) {
|
||||
gstate_c.Dirty(DIRTY_PROJMATRIX);
|
||||
}
|
||||
if (vpAndScissor.dirtyDepth) {
|
||||
gstate_c.Dirty(DIRTY_DEPTHRANGE);
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
}
|
||||
|
@ -503,15 +503,15 @@ void TextureCacheGLES::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFram
|
||||
const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor;
|
||||
|
||||
TexCacheEntry::Status alphaStatus = CheckAlpha(clutBuf_, getClutDestFormat(clutFormat), clutTotalColors, clutTotalColors, 1);
|
||||
gstate_c.textureFullAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL;
|
||||
gstate_c.textureSimpleAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE;
|
||||
gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL);
|
||||
gstate_c.SetTextureSimpleAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE);
|
||||
} else {
|
||||
entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE;
|
||||
|
||||
framebufferManagerGL_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET);
|
||||
|
||||
gstate_c.textureFullAlpha = gstate.getTextureFormat() == GE_TFMT_5650;
|
||||
gstate_c.textureSimpleAlpha = gstate_c.textureFullAlpha;
|
||||
gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650);
|
||||
gstate_c.SetTextureSimpleAlpha(gstate_c.textureFullAlpha);
|
||||
}
|
||||
|
||||
framebufferManagerGL_->RebindFramebuffer();
|
||||
|
@ -219,7 +219,7 @@ public:
|
||||
typedef void (GPUCommon::*CmdFunc)(u32 op, u32 diff);
|
||||
|
||||
protected:
|
||||
void SetDrawType(DrawType type) {
|
||||
void SetDrawType(DrawType type, GEPrimitiveType prim) {
|
||||
if (type != lastDraw_) {
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
lastDraw_ = type;
|
||||
|
@ -501,6 +501,18 @@ struct GPUStateCache {
|
||||
bool IsDirty(u64 what) const {
|
||||
return (dirty & what) != 0ULL;
|
||||
}
|
||||
void SetTextureFullAlpha(bool fullAlpha) {
|
||||
textureFullAlpha = fullAlpha;
|
||||
}
|
||||
void SetTextureSimpleAlpha(bool simpleAlpha) {
|
||||
textureSimpleAlpha = simpleAlpha;
|
||||
}
|
||||
void SetNeedShaderTexclamp(bool need) {
|
||||
needShaderTexClamp = need;
|
||||
}
|
||||
void SetAllowShaderBlend(bool allow) {
|
||||
allowShaderBlend = allow;
|
||||
}
|
||||
|
||||
u32 featureFlags;
|
||||
|
||||
|
@ -722,27 +722,25 @@ void DrawEngineVulkan::DoFlush(VkCommandBuffer cmd) {
|
||||
sampler = nullSampler_;
|
||||
}
|
||||
|
||||
VulkanPipelineRasterStateKey pipelineKey;
|
||||
VulkanDynamicState dynState;
|
||||
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey, dynState);
|
||||
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
|
||||
// TODO: Dirty-flag these.
|
||||
vkCmdSetScissor(cmd_, 0, 1, &dynState.scissor);
|
||||
vkCmdSetViewport(cmd_, 0, 1, &dynState.viewport);
|
||||
if (dynState.useStencil) {
|
||||
vkCmdSetStencilWriteMask(cmd_, VK_STENCIL_FRONT_AND_BACK, dynState.stencilWriteMask);
|
||||
vkCmdSetStencilCompareMask(cmd_, VK_STENCIL_FRONT_AND_BACK, dynState.stencilCompareMask);
|
||||
vkCmdSetStencilReference(cmd_, VK_STENCIL_FRONT_AND_BACK, dynState.stencilRef);
|
||||
vkCmdSetScissor(cmd_, 0, 1, &dynState_.scissor);
|
||||
vkCmdSetViewport(cmd_, 0, 1, &dynState_.viewport);
|
||||
if (dynState_.useStencil) {
|
||||
vkCmdSetStencilWriteMask(cmd_, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilWriteMask);
|
||||
vkCmdSetStencilCompareMask(cmd_, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilCompareMask);
|
||||
vkCmdSetStencilReference(cmd_, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilRef);
|
||||
}
|
||||
if (dynState.useBlendColor) {
|
||||
if (dynState_.useBlendColor) {
|
||||
float bc[4];
|
||||
Uint8x4ToFloat4(bc, dynState.blendColor);
|
||||
Uint8x4ToFloat4(bc, dynState_.blendColor);
|
||||
vkCmdSetBlendConstants(cmd_, bc);
|
||||
}
|
||||
|
||||
dirtyUniforms_ |= shaderManager_->UpdateUniforms();
|
||||
|
||||
shaderManager_->GetShaders(prim, lastVTypeID_, &vshader, &fshader, useHWTransform);
|
||||
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, pipelineKey, dec_, vshader, fshader, true);
|
||||
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, pipelineKey_, dec_, vshader, fshader, true);
|
||||
if (!pipeline) {
|
||||
// Already logged, let's bail out.
|
||||
return;
|
||||
|
@ -241,6 +241,9 @@ private:
|
||||
|
||||
DrawEngineVulkanStats stats_;
|
||||
|
||||
VulkanPipelineRasterStateKey pipelineKey_{};
|
||||
VulkanDynamicState dynState_{};
|
||||
|
||||
// Hardware tessellation
|
||||
class TessellationDataTransferVulkan : public TessellationDataTransfer {
|
||||
private:
|
||||
|
@ -465,8 +465,6 @@ void GPU_Vulkan::ExecuteOp(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_Vulkan::Execute_Prim(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_PRIM);
|
||||
|
||||
// This drives all drawing. All other state we just buffer up, then we apply it only
|
||||
// when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization.
|
||||
|
||||
@ -478,6 +476,8 @@ void GPU_Vulkan::Execute_Prim(u32 op, u32 diff) {
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
SetDrawType(DRAW_PRIM, prim);
|
||||
|
||||
// Discard AA lines as we can't do anything that makes sense with these anyway. The SW plugin might, though.
|
||||
|
||||
if (gstate.isAntiAliasEnabled()) {
|
||||
@ -540,8 +540,6 @@ void GPU_Vulkan::Execute_VertexType(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_BEZIER);
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@ -575,6 +573,8 @@ void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
|
||||
SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim));
|
||||
|
||||
int bz_ucount = op & 0xFF;
|
||||
int bz_vcount = (op >> 8) & 0xFF;
|
||||
bool computeNormals = gstate.isLightingEnabled();
|
||||
@ -599,8 +599,6 @@ void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPU_Vulkan::Execute_Spline(u32 op, u32 diff) {
|
||||
SetDrawType(DRAW_SPLINE);
|
||||
|
||||
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
|
||||
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@ -638,6 +636,7 @@ void GPU_Vulkan::Execute_Spline(u32 op, u32 diff) {
|
||||
int sp_utype = (op >> 16) & 0x3;
|
||||
int sp_vtype = (op >> 18) & 0x3;
|
||||
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
|
||||
SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim));
|
||||
bool computeNormals = gstate.isLightingEnabled();
|
||||
bool patchFacing = gstate.patchfacing & 1;
|
||||
u32 vertType = gstate.vertType;
|
||||
|
@ -129,199 +129,232 @@ void ResetShaderBlending() {
|
||||
// In Vulkan, we simply collect all the state together into a "pipeline key" - we don't actually set any state here
|
||||
// (the caller is responsible for setting the little dynamic state that is supported, dynState).
|
||||
void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState) {
|
||||
memset(&key, 0, sizeof(key));
|
||||
memset(&dynState, 0, sizeof(dynState));
|
||||
// Unfortunately, this isn't implemented yet.
|
||||
gstate_c.allowShaderBlend = false;
|
||||
|
||||
// Set blend - unless we need to do it in the shader.
|
||||
GenericBlendState blendState;
|
||||
ConvertBlendState(blendState, gstate_c.allowShaderBlend);
|
||||
|
||||
bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
|
||||
|
||||
ViewportAndScissor vpAndScissor;
|
||||
ConvertViewportAndScissor(useBufferedRendering,
|
||||
fbManager.GetRenderWidth(), fbManager.GetRenderHeight(),
|
||||
fbManager.GetTargetBufferWidth(), fbManager.GetTargetBufferHeight(),
|
||||
vpAndScissor);
|
||||
{
|
||||
// Unfortunately, this isn't implemented yet.
|
||||
gstate_c.SetAllowShaderBlend(false);
|
||||
if (gstate.isModeClear()) {
|
||||
key.logicOpEnable = false;
|
||||
key.logicOp = VK_LOGIC_OP_CLEAR;
|
||||
key.blendEnable = false;
|
||||
key.blendOpColor = VK_BLEND_OP_ADD;
|
||||
key.blendOpAlpha = VK_BLEND_OP_ADD;
|
||||
key.srcColor = VK_BLEND_FACTOR_ONE;
|
||||
key.srcAlpha = VK_BLEND_FACTOR_ONE;
|
||||
key.destColor = VK_BLEND_FACTOR_ZERO;
|
||||
key.destAlpha = VK_BLEND_FACTOR_ZERO;
|
||||
dynState.useBlendColor = false;
|
||||
|
||||
// Color Mask
|
||||
bool colorMask = gstate.isClearModeColorMask();
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
key.colorWriteMask = (colorMask ? (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT) : 0) | (alphaMask ? VK_COLOR_COMPONENT_A_BIT : 0);
|
||||
|
||||
if (blendState.applyShaderBlending) {
|
||||
if (ApplyShaderBlending()) {
|
||||
// We may still want to do something about stencil -> alpha.
|
||||
ApplyStencilReplaceAndLogicOp(blendState.replaceAlphaWithStencil, blendState);
|
||||
} else {
|
||||
// Until next time, force it off.
|
||||
ResetShaderBlending();
|
||||
gstate_c.allowShaderBlend = false;
|
||||
}
|
||||
} else if (blendState.resetShaderBlending) {
|
||||
ResetShaderBlending();
|
||||
}
|
||||
// Set blend - unless we need to do it in the shader.
|
||||
GenericBlendState blendState;
|
||||
ConvertBlendState(blendState, gstate_c.allowShaderBlend);
|
||||
|
||||
if (blendState.enabled) {
|
||||
key.blendEnable = true;
|
||||
key.blendOpColor = vkBlendEqLookup[(size_t)blendState.eqColor];
|
||||
key.blendOpAlpha = vkBlendEqLookup[(size_t)blendState.eqAlpha];
|
||||
key.srcColor = vkBlendFactorLookup[(size_t)blendState.srcColor];
|
||||
key.srcAlpha = vkBlendFactorLookup[(size_t)blendState.srcAlpha];
|
||||
key.destColor = vkBlendFactorLookup[(size_t)blendState.dstColor];
|
||||
key.destAlpha = vkBlendFactorLookup[(size_t)blendState.dstAlpha];
|
||||
if (blendState.dirtyShaderBlend) {
|
||||
gstate_c.Dirty(DIRTY_SHADERBLEND);
|
||||
}
|
||||
dynState.useBlendColor = blendState.useBlendColor;
|
||||
if (blendState.useBlendColor) {
|
||||
dynState.blendColor = blendState.blendColor;
|
||||
}
|
||||
} else {
|
||||
key.blendEnable = false;
|
||||
dynState.useBlendColor = false;
|
||||
}
|
||||
if (blendState.applyShaderBlending) {
|
||||
if (ApplyShaderBlending()) {
|
||||
// We may still want to do something about stencil -> alpha.
|
||||
ApplyStencilReplaceAndLogicOp(blendState.replaceAlphaWithStencil, blendState);
|
||||
} else {
|
||||
// Until next time, force it off.
|
||||
ResetShaderBlending();
|
||||
gstate_c.SetAllowShaderBlend(false);
|
||||
}
|
||||
} else if (blendState.resetShaderBlending) {
|
||||
ResetShaderBlending();
|
||||
}
|
||||
|
||||
dynState.useStencil = false;
|
||||
|
||||
// Set ColorMask/Stencil/Depth
|
||||
if (gstate.isModeClear()) {
|
||||
key.logicOpEnable = false;
|
||||
key.cullMode = VK_CULL_MODE_NONE;
|
||||
|
||||
key.depthTestEnable = true;
|
||||
key.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
key.depthWriteEnable = gstate.isClearModeDepthMask();
|
||||
if (gstate.isClearModeDepthMask()) {
|
||||
fbManager.SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Color Test
|
||||
bool colorMask = gstate.isClearModeColorMask();
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
key.colorWriteMask = (colorMask ? (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT) : 0) | (alphaMask ? VK_COLOR_COMPONENT_A_BIT : 0);
|
||||
|
||||
// Stencil Test
|
||||
if (alphaMask) {
|
||||
key.stencilTestEnable = true;
|
||||
key.stencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
key.stencilPassOp = VK_STENCIL_OP_REPLACE;
|
||||
key.stencilFailOp = VK_STENCIL_OP_REPLACE;
|
||||
key.stencilDepthFailOp = VK_STENCIL_OP_REPLACE;
|
||||
dynState.useStencil = true;
|
||||
// In clear mode, the stencil value is set to the alpha value of the vertex.
|
||||
// A normal clear will be 2 points, the second point has the color.
|
||||
// We override this value in the pipeline from software transform for clear rectangles.
|
||||
dynState.stencilRef = 0xFF;
|
||||
dynState.stencilWriteMask = 0xFF;
|
||||
} else {
|
||||
key.stencilTestEnable = false;
|
||||
dynState.useStencil = false;
|
||||
}
|
||||
} else {
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
// Logic Ops
|
||||
if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) {
|
||||
key.logicOpEnable = true;
|
||||
key.logicOp = logicOps[gstate.getLogicOp()];
|
||||
if (blendState.enabled) {
|
||||
key.blendEnable = true;
|
||||
key.blendOpColor = vkBlendEqLookup[(size_t)blendState.eqColor];
|
||||
key.blendOpAlpha = vkBlendEqLookup[(size_t)blendState.eqAlpha];
|
||||
key.srcColor = vkBlendFactorLookup[(size_t)blendState.srcColor];
|
||||
key.srcAlpha = vkBlendFactorLookup[(size_t)blendState.srcAlpha];
|
||||
key.destColor = vkBlendFactorLookup[(size_t)blendState.dstColor];
|
||||
key.destAlpha = vkBlendFactorLookup[(size_t)blendState.dstAlpha];
|
||||
if (blendState.dirtyShaderBlend) {
|
||||
gstate_c.Dirty(DIRTY_SHADERBLEND);
|
||||
}
|
||||
dynState.useBlendColor = blendState.useBlendColor;
|
||||
if (blendState.useBlendColor) {
|
||||
dynState.blendColor = blendState.blendColor;
|
||||
}
|
||||
} else {
|
||||
key.logicOpEnable = false;
|
||||
key.blendEnable = false;
|
||||
key.blendOpColor = VK_BLEND_OP_ADD;
|
||||
key.blendOpAlpha = VK_BLEND_OP_ADD;
|
||||
key.srcColor = VK_BLEND_FACTOR_ONE;
|
||||
key.srcAlpha = VK_BLEND_FACTOR_ONE;
|
||||
key.destColor = VK_BLEND_FACTOR_ZERO;
|
||||
key.destAlpha = VK_BLEND_FACTOR_ZERO;
|
||||
dynState.useBlendColor = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set cull
|
||||
bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
|
||||
key.cullMode = wantCull ? (gstate.getCullMode() ? VK_CULL_MODE_FRONT_BIT : VK_CULL_MODE_BACK_BIT) : VK_CULL_MODE_NONE;
|
||||
|
||||
// Depth Test
|
||||
if (gstate.isDepthTestEnabled()) {
|
||||
key.depthTestEnable = true;
|
||||
key.depthCompareOp = compareOps[gstate.getDepthTestFunction()];
|
||||
key.depthWriteEnable = gstate.isDepthWriteEnabled();
|
||||
if (gstate.isDepthWriteEnabled()) {
|
||||
fbManager.SetDepthUpdated();
|
||||
}
|
||||
} else {
|
||||
key.depthTestEnable = false;
|
||||
key.depthWriteEnable = false;
|
||||
key.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
}
|
||||
|
||||
// PSP color/alpha mask is per bit but we can only support per byte.
|
||||
// But let's do that, at least. And let's try a threshold.
|
||||
bool rmask = (gstate.pmskc & 0xFF) < 128;
|
||||
bool gmask = ((gstate.pmskc >> 8) & 0xFF) < 128;
|
||||
bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128;
|
||||
bool amask = (gstate.pmska & 0xFF) < 128;
|
||||
// PSP color/alpha mask is per bit but we can only support per byte.
|
||||
// But let's do that, at least. And let's try a threshold.
|
||||
bool rmask = (gstate.pmskc & 0xFF) < 128;
|
||||
bool gmask = ((gstate.pmskc >> 8) & 0xFF) < 128;
|
||||
bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128;
|
||||
bool amask = (gstate.pmska & 0xFF) < 128;
|
||||
|
||||
#ifndef MOBILE_DEVICE
|
||||
u8 abits = (gstate.pmska >> 0) & 0xFF;
|
||||
u8 rbits = (gstate.pmskc >> 0) & 0xFF;
|
||||
u8 gbits = (gstate.pmskc >> 8) & 0xFF;
|
||||
u8 bbits = (gstate.pmskc >> 16) & 0xFF;
|
||||
if ((rbits != 0 && rbits != 0xFF) || (gbits != 0 && gbits != 0xFF) || (bbits != 0 && bbits != 0xFF)) {
|
||||
WARN_LOG_REPORT_ONCE(rgbmask, G3D, "Unsupported RGB mask: r=%02x g=%02x b=%02x", rbits, gbits, bbits);
|
||||
}
|
||||
if (abits != 0 && abits != 0xFF) {
|
||||
// The stencil part of the mask is supported.
|
||||
WARN_LOG_REPORT_ONCE(amask, G3D, "Unsupported alpha/stencil mask: %02x", abits);
|
||||
}
|
||||
u8 abits = (gstate.pmska >> 0) & 0xFF;
|
||||
u8 rbits = (gstate.pmskc >> 0) & 0xFF;
|
||||
u8 gbits = (gstate.pmskc >> 8) & 0xFF;
|
||||
u8 bbits = (gstate.pmskc >> 16) & 0xFF;
|
||||
if ((rbits != 0 && rbits != 0xFF) || (gbits != 0 && gbits != 0xFF) || (bbits != 0 && bbits != 0xFF)) {
|
||||
WARN_LOG_REPORT_ONCE(rgbmask, G3D, "Unsupported RGB mask: r=%02x g=%02x b=%02x", rbits, gbits, bbits);
|
||||
}
|
||||
if (abits != 0 && abits != 0xFF) {
|
||||
// The stencil part of the mask is supported.
|
||||
WARN_LOG_REPORT_ONCE(amask, G3D, "Unsupported alpha/stencil mask: %02x", abits);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Let's not write to alpha if stencil isn't enabled.
|
||||
if (!gstate.isStencilTestEnabled()) {
|
||||
amask = false;
|
||||
} else {
|
||||
// If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel.
|
||||
if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_KEEP) {
|
||||
// Let's not write to alpha if stencil isn't enabled.
|
||||
if (!gstate.isStencilTestEnabled()) {
|
||||
amask = false;
|
||||
} else {
|
||||
// If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel.
|
||||
if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_KEEP) {
|
||||
amask = false;
|
||||
}
|
||||
}
|
||||
|
||||
key.colorWriteMask = (rmask ? VK_COLOR_COMPONENT_R_BIT : 0) | (gmask ? VK_COLOR_COMPONENT_G_BIT : 0) | (bmask ? VK_COLOR_COMPONENT_B_BIT : 0) | (amask ? VK_COLOR_COMPONENT_A_BIT : 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (gstate.isModeClear()) {
|
||||
key.cullMode = VK_CULL_MODE_NONE;
|
||||
} else {
|
||||
// Set cull
|
||||
bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
|
||||
key.cullMode = wantCull ? (gstate.getCullMode() ? VK_CULL_MODE_FRONT_BIT : VK_CULL_MODE_BACK_BIT) : VK_CULL_MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Set Stencil/Depth
|
||||
if (gstate.isModeClear()) {
|
||||
key.depthTestEnable = true;
|
||||
key.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
key.depthWriteEnable = gstate.isClearModeDepthMask();
|
||||
if (gstate.isClearModeDepthMask()) {
|
||||
fbManager.SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Stencil Test
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
if (alphaMask) {
|
||||
key.stencilTestEnable = true;
|
||||
key.stencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
key.stencilPassOp = VK_STENCIL_OP_REPLACE;
|
||||
key.stencilFailOp = VK_STENCIL_OP_REPLACE;
|
||||
key.stencilDepthFailOp = VK_STENCIL_OP_REPLACE;
|
||||
dynState.useStencil = true;
|
||||
// In clear mode, the stencil value is set to the alpha value of the vertex.
|
||||
// A normal clear will be 2 points, the second point has the color.
|
||||
// We override this value in the pipeline from software transform for clear rectangles.
|
||||
dynState.stencilRef = 0xFF;
|
||||
dynState.stencilWriteMask = 0xFF;
|
||||
} else {
|
||||
key.stencilTestEnable = false;
|
||||
key.stencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
key.stencilPassOp = VK_STENCIL_OP_REPLACE;
|
||||
key.stencilFailOp = VK_STENCIL_OP_REPLACE;
|
||||
key.stencilDepthFailOp = VK_STENCIL_OP_REPLACE;
|
||||
dynState.useStencil = false;
|
||||
}
|
||||
} else {
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
// Logic Ops
|
||||
if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) {
|
||||
key.logicOpEnable = true;
|
||||
key.logicOp = logicOps[gstate.getLogicOp()];
|
||||
} else {
|
||||
key.logicOpEnable = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Depth Test
|
||||
if (gstate.isDepthTestEnabled()) {
|
||||
key.depthTestEnable = true;
|
||||
key.depthCompareOp = compareOps[gstate.getDepthTestFunction()];
|
||||
key.depthWriteEnable = gstate.isDepthWriteEnabled();
|
||||
if (gstate.isDepthWriteEnabled()) {
|
||||
fbManager.SetDepthUpdated();
|
||||
}
|
||||
} else {
|
||||
key.depthTestEnable = false;
|
||||
key.depthWriteEnable = false;
|
||||
key.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
}
|
||||
|
||||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
// Stencil Test
|
||||
if (stencilState.enabled) {
|
||||
key.stencilTestEnable = true;
|
||||
key.stencilCompareOp = compareOps[stencilState.testFunc];
|
||||
key.stencilPassOp = stencilOps[stencilState.zPass];
|
||||
key.stencilFailOp = stencilOps[stencilState.sFail];
|
||||
key.stencilDepthFailOp = stencilOps[stencilState.zFail];
|
||||
dynState.useStencil = true;
|
||||
dynState.stencilRef = stencilState.testRef;
|
||||
dynState.stencilCompareMask = stencilState.testMask;
|
||||
dynState.stencilWriteMask = stencilState.writeMask;
|
||||
} else {
|
||||
key.stencilTestEnable = false;
|
||||
key.stencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
key.stencilPassOp = VK_STENCIL_OP_REPLACE;
|
||||
key.stencilFailOp = VK_STENCIL_OP_REPLACE;
|
||||
key.stencilDepthFailOp = VK_STENCIL_OP_REPLACE;
|
||||
dynState.useStencil = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
key.colorWriteMask = (rmask ? VK_COLOR_COMPONENT_R_BIT : 0) | (gmask ? VK_COLOR_COMPONENT_G_BIT : 0) | (bmask ? VK_COLOR_COMPONENT_B_BIT : 0) | (amask ? VK_COLOR_COMPONENT_A_BIT : 0);
|
||||
{
|
||||
ViewportAndScissor vpAndScissor;
|
||||
ConvertViewportAndScissor(useBufferedRendering,
|
||||
fbManager.GetRenderWidth(), fbManager.GetRenderHeight(),
|
||||
fbManager.GetTargetBufferWidth(), fbManager.GetTargetBufferHeight(),
|
||||
vpAndScissor);
|
||||
|
||||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
VkViewport &vp = dynState.viewport;
|
||||
vp.x = vpAndScissor.viewportX;
|
||||
vp.y = vpAndScissor.viewportY;
|
||||
vp.width = vpAndScissor.viewportW;
|
||||
vp.height = vpAndScissor.viewportH;
|
||||
vp.minDepth = vpAndScissor.depthRangeMin;
|
||||
vp.maxDepth = vpAndScissor.depthRangeMax;
|
||||
if (vpAndScissor.dirtyProj) {
|
||||
gstate_c.Dirty(DIRTY_PROJMATRIX);
|
||||
}
|
||||
|
||||
// Stencil Test
|
||||
if (stencilState.enabled) {
|
||||
key.stencilTestEnable = true;
|
||||
key.stencilCompareOp = compareOps[stencilState.testFunc];
|
||||
key.stencilPassOp = stencilOps[stencilState.zPass];
|
||||
key.stencilFailOp = stencilOps[stencilState.sFail];
|
||||
key.stencilDepthFailOp = stencilOps[stencilState.zFail];
|
||||
dynState.useStencil = true;
|
||||
dynState.stencilRef = stencilState.testRef;
|
||||
dynState.stencilCompareMask = stencilState.testMask;
|
||||
dynState.stencilWriteMask = stencilState.writeMask;
|
||||
} else {
|
||||
key.stencilTestEnable = false;
|
||||
dynState.useStencil = false;
|
||||
VkRect2D &scissor = dynState.scissor;
|
||||
scissor.offset.x = vpAndScissor.scissorX;
|
||||
scissor.offset.y = vpAndScissor.scissorY;
|
||||
scissor.extent.width = vpAndScissor.scissorW;
|
||||
scissor.extent.height = vpAndScissor.scissorH;
|
||||
|
||||
float depthMin = vpAndScissor.depthRangeMin;
|
||||
float depthMax = vpAndScissor.depthRangeMax;
|
||||
|
||||
if (depthMin < 0.0f) depthMin = 0.0f;
|
||||
if (depthMax > 1.0f) depthMax = 1.0f;
|
||||
if (vpAndScissor.dirtyDepth) {
|
||||
gstate_c.Dirty(DIRTY_DEPTHRANGE);
|
||||
}
|
||||
}
|
||||
|
||||
key.topology = primToVulkan[prim];
|
||||
|
||||
VkViewport &vp = dynState.viewport;
|
||||
vp.x = vpAndScissor.viewportX;
|
||||
vp.y = vpAndScissor.viewportY;
|
||||
vp.width = vpAndScissor.viewportW;
|
||||
vp.height = vpAndScissor.viewportH;
|
||||
vp.minDepth = vpAndScissor.depthRangeMin;
|
||||
vp.maxDepth = vpAndScissor.depthRangeMax;
|
||||
if (vpAndScissor.dirtyProj) {
|
||||
gstate_c.Dirty(DIRTY_PROJMATRIX);
|
||||
}
|
||||
|
||||
VkRect2D &scissor = dynState.scissor;
|
||||
scissor.offset.x = vpAndScissor.scissorX;
|
||||
scissor.offset.y = vpAndScissor.scissorY;
|
||||
scissor.extent.width = vpAndScissor.scissorW;
|
||||
scissor.extent.height = vpAndScissor.scissorH;
|
||||
|
||||
float depthMin = vpAndScissor.depthRangeMin;
|
||||
float depthMax = vpAndScissor.depthRangeMax;
|
||||
|
||||
if (depthMin < 0.0f) depthMin = 0.0f;
|
||||
if (depthMax > 1.0f) depthMax = 1.0f;
|
||||
if (vpAndScissor.dirtyDepth) {
|
||||
gstate_c.Dirty(DIRTY_DEPTHRANGE);
|
||||
}
|
||||
}
|
||||
|
@ -429,13 +429,13 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr
|
||||
const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor;
|
||||
|
||||
TexCacheEntry::Status alphaStatus = CheckAlpha(clutBuf_, getClutDestFormatVulkan(clutFormat), clutTotalColors, clutTotalColors, 1);
|
||||
gstate_c.textureFullAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL;
|
||||
gstate_c.textureSimpleAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE;
|
||||
gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL);
|
||||
gstate_c.SetTextureSimpleAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE);
|
||||
} else {
|
||||
entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE;
|
||||
|
||||
gstate_c.textureFullAlpha = gstate.getTextureFormat() == GE_TFMT_5650;
|
||||
gstate_c.textureSimpleAlpha = gstate_c.textureFullAlpha;
|
||||
gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650);
|
||||
gstate_c.SetTextureSimpleAlpha(gstate_c.textureFullAlpha);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -683,8 +683,8 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
|
||||
|
||||
entry->vkTex->texture_->EndCreate();
|
||||
|
||||
gstate_c.textureFullAlpha = entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL;
|
||||
gstate_c.textureSimpleAlpha = entry->GetAlphaStatus() != TexCacheEntry::STATUS_ALPHA_UNKNOWN;
|
||||
gstate_c.SetTextureFullAlpha(entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL);
|
||||
gstate_c.SetTextureSimpleAlpha(entry->GetAlphaStatus() != TexCacheEntry::STATUS_ALPHA_UNKNOWN);
|
||||
}
|
||||
|
||||
VkFormat TextureCacheVulkan::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const {
|
||||
|
@ -557,6 +557,15 @@ enum GEPatchPrimType
|
||||
GE_PATCHPRIM_UNKNOWN = 3,
|
||||
};
|
||||
|
||||
inline GEPrimitiveType PatchPrimToPrim(GEPatchPrimType type) {
|
||||
switch (type) {
|
||||
case GE_PATCHPRIM_TRIANGLES: return GE_PRIM_TRIANGLES;
|
||||
case GE_PATCHPRIM_LINES: return GE_PRIM_LINES;
|
||||
case GE_PATCHPRIM_POINTS: return GE_PRIM_POINTS;
|
||||
case GE_PATCHPRIM_UNKNOWN: default: return GE_PRIM_KEEP_PREVIOUS; // just something
|
||||
}
|
||||
}
|
||||
|
||||
enum GEPaletteFormat
|
||||
{
|
||||
GE_CMODE_16BIT_BGR5650,
|
||||
|
Loading…
Reference in New Issue
Block a user