mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-08-20 09:57:09 +00:00
Fix gamma post-process in split-screen
The gamma shader sampled the full backbuffer texture (UV 0..1) into each player's viewport, stretching the entire screen into every split region. Extended the shader constant buffer with per-viewport UV offset and scale so each pass samples only its own portion of the backbuffer. ComputeViewportForPlayer was hardcoded to top/bottom for 2 players, ignoring the vertical split setting. Rewrote it to read each player's m_iScreenSection directly, which already accounts for the split orientation preference. Secondary players have no Graphics menu and cannot change gamma. CachePlayerGammas now reads the primary player's setting and applies it uniformly to all viewports.
This commit is contained in:
parent
da7b6a77c8
commit
a9ca3195b1
|
|
@ -51,7 +51,10 @@ private:
|
||||||
struct GammaCBData
|
struct GammaCBData
|
||||||
{
|
{
|
||||||
float gamma;
|
float gamma;
|
||||||
float pad[3];
|
float pad;
|
||||||
|
float uvOffsetX, uvOffsetY;
|
||||||
|
float uvScaleX, uvScaleY;
|
||||||
|
float pad2[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* g_gammaVSCode;
|
static const char* g_gammaVSCode;
|
||||||
|
|
|
||||||
|
|
@ -954,91 +954,70 @@ float GameRenderer::ComputeGammaFromSlider(float slider0to100)
|
||||||
|
|
||||||
void GameRenderer::CachePlayerGammas()
|
void GameRenderer::CachePlayerGammas()
|
||||||
{
|
{
|
||||||
for (int j = 0; j < XUSER_MAX_COUNT && j < NUM_LIGHT_TEXTURES; ++j)
|
const float slider = app.GetGameSettings(ProfileManager.GetPrimaryPad(), eGameSetting_Gamma);
|
||||||
{
|
const float gamma = ComputeGammaFromSlider(slider);
|
||||||
std::shared_ptr<MultiplayerLocalPlayer> player = Minecraft::GetInstance()->localplayers[j];
|
|
||||||
if (!player)
|
|
||||||
{
|
|
||||||
m_cachedGammaPerPlayer[j] = 1.0f;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float slider = app.GetGameSettings(j, eGameSetting_Gamma); // 0..100
|
for (int j = 0; j < XUSER_MAX_COUNT && j < NUM_LIGHT_TEXTURES; ++j)
|
||||||
m_cachedGammaPerPlayer[j] = ComputeGammaFromSlider(slider);
|
m_cachedGammaPerPlayer[j] = gamma;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameRenderer::ComputeViewportForPlayer(int j, D3D11_VIEWPORT &outViewport) const
|
bool GameRenderer::ComputeViewportForPlayer(int j, D3D11_VIEWPORT &outViewport) const
|
||||||
{
|
{
|
||||||
// Use the actual backbuffer dimensions so viewports adapt to window resize.
|
|
||||||
extern int g_rScreenWidth;
|
extern int g_rScreenWidth;
|
||||||
extern int g_rScreenHeight;
|
extern int g_rScreenHeight;
|
||||||
|
|
||||||
int active = 0;
|
std::shared_ptr<MultiplayerLocalPlayer> player = Minecraft::GetInstance()->localplayers[j];
|
||||||
int indexMap[NUM_LIGHT_TEXTURES] = {-1, -1, -1, -1};
|
if (!player)
|
||||||
for (int i = 0; i < XUSER_MAX_COUNT && i < NUM_LIGHT_TEXTURES; ++i)
|
|
||||||
{
|
|
||||||
if (Minecraft::GetInstance()->localplayers[i])
|
|
||||||
indexMap[active++] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (active <= 1)
|
|
||||||
{
|
|
||||||
outViewport.TopLeftX = 0.0f;
|
|
||||||
outViewport.TopLeftY = 0.0f;
|
|
||||||
outViewport.Width = static_cast<FLOAT>(g_rScreenWidth);
|
|
||||||
outViewport.Height = static_cast<FLOAT>(g_rScreenHeight);
|
|
||||||
outViewport.MinDepth = 0.0f;
|
|
||||||
outViewport.MaxDepth = 1.0f;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int k = -1;
|
|
||||||
for (int ord = 0; ord < active; ++ord)
|
|
||||||
if (indexMap[ord] == j)
|
|
||||||
{
|
|
||||||
k = ord;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (k < 0)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const float width = static_cast<float>(g_rScreenWidth);
|
const float w = static_cast<float>(g_rScreenWidth);
|
||||||
const float height = static_cast<float>(g_rScreenHeight);
|
const float h = static_cast<float>(g_rScreenHeight);
|
||||||
|
const float halfW = w * 0.5f;
|
||||||
|
const float halfH = h * 0.5f;
|
||||||
|
|
||||||
if (active == 2)
|
outViewport.MinDepth = 0.0f;
|
||||||
|
outViewport.MaxDepth = 1.0f;
|
||||||
|
|
||||||
|
switch (static_cast<C4JRender::eViewportType>(player->m_iScreenSection))
|
||||||
{
|
{
|
||||||
const float halfH = height * 0.5f;
|
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
|
||||||
outViewport.TopLeftX = 0.0f;
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = 0;
|
||||||
outViewport.Width = width;
|
outViewport.Width = w; outViewport.Height = halfH;
|
||||||
outViewport.MinDepth = 0.0f;
|
break;
|
||||||
outViewport.MaxDepth = 1.0f;
|
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
|
||||||
if (k == 0)
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = halfH;
|
||||||
{
|
outViewport.Width = w; outViewport.Height = halfH;
|
||||||
outViewport.TopLeftY = 0.0f;
|
break;
|
||||||
outViewport.Height = halfH;
|
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
|
||||||
}
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = 0;
|
||||||
else
|
outViewport.Width = halfW; outViewport.Height = h;
|
||||||
{
|
break;
|
||||||
outViewport.TopLeftY = halfH;
|
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
|
||||||
outViewport.Height = halfH;
|
outViewport.TopLeftX = halfW; outViewport.TopLeftY = 0;
|
||||||
}
|
outViewport.Width = halfW; outViewport.Height = h;
|
||||||
return true;
|
break;
|
||||||
}
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
|
||||||
else
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = 0;
|
||||||
{
|
outViewport.Width = halfW; outViewport.Height = halfH;
|
||||||
const float halfW = width * 0.5f;
|
break;
|
||||||
const float halfH = height * 0.5f;
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
|
||||||
const int row = (k >= 2) ? 1 : 0;
|
outViewport.TopLeftX = halfW; outViewport.TopLeftY = 0;
|
||||||
const int col = (k % 2);
|
outViewport.Width = halfW; outViewport.Height = halfH;
|
||||||
outViewport.TopLeftX = col ? halfW : 0.0f;
|
break;
|
||||||
outViewport.TopLeftY = row ? halfH : 0.0f;
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
|
||||||
outViewport.Width = halfW;
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = halfH;
|
||||||
outViewport.Height = halfH;
|
outViewport.Width = halfW; outViewport.Height = halfH;
|
||||||
outViewport.MinDepth = 0.0f;
|
break;
|
||||||
outViewport.MaxDepth = 1.0f;
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
|
||||||
return true;
|
outViewport.TopLeftX = halfW; outViewport.TopLeftY = halfH;
|
||||||
|
outViewport.Width = halfW; outViewport.Height = halfH;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = 0;
|
||||||
|
outViewport.Width = w; outViewport.Height = h;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GameRenderer::BuildPlayerViewports(D3D11_VIEWPORT *outViewports, float *outGammas, UINT maxCount) const
|
uint32_t GameRenderer::BuildPlayerViewports(D3D11_VIEWPORT *outViewports, float *outGammas, UINT maxCount) const
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,17 @@ const char* PostProcesser::g_gammaPSCode =
|
||||||
"cbuffer GammaCB : register(b0)\n"
|
"cbuffer GammaCB : register(b0)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" float gamma;\n"
|
" float gamma;\n"
|
||||||
" float3 pad;\n"
|
" float _pad;\n"
|
||||||
|
" float2 uvOffset;\n"
|
||||||
|
" float2 uvScale;\n"
|
||||||
|
" float2 _pad2;\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"Texture2D sceneTex : register(t0);\n"
|
"Texture2D sceneTex : register(t0);\n"
|
||||||
"SamplerState sceneSampler : register(s0);\n"
|
"SamplerState sceneSampler : register(s0);\n"
|
||||||
"float4 main(float4 pos : SV_Position, float2 uv : TEXCOORD0) : SV_Target\n"
|
"float4 main(float4 pos : SV_Position, float2 uv : TEXCOORD0) : SV_Target\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" float4 color = sceneTex.Sample(sceneSampler, uv);\n"
|
" float2 texUV = uvOffset + uv * uvScale;\n"
|
||||||
|
" float4 color = sceneTex.Sample(sceneSampler, texUV);\n"
|
||||||
"\n"
|
"\n"
|
||||||
" color.rgb = max(color.rgb, 0.0);\n"
|
" color.rgb = max(color.rgb, 0.0);\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
@ -158,7 +162,7 @@ void PostProcesser::Init()
|
||||||
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||||
cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
|
|
||||||
GammaCBData initData = {1.0f, {0, 0, 0}};
|
GammaCBData initData = {1.0f, 0, 0.0f, 0.0f, 1.0f, 1.0f, {0, 0}};
|
||||||
D3D11_SUBRESOURCE_DATA srData;
|
D3D11_SUBRESOURCE_DATA srData;
|
||||||
srData.pSysMem = &initData;
|
srData.pSysMem = &initData;
|
||||||
srData.SysMemPitch = 0;
|
srData.SysMemPitch = 0;
|
||||||
|
|
@ -237,6 +241,10 @@ void PostProcesser::Apply() const
|
||||||
{
|
{
|
||||||
GammaCBData *cb = static_cast<GammaCBData *>(mapped.pData);
|
GammaCBData *cb = static_cast<GammaCBData *>(mapped.pData);
|
||||||
cb->gamma = m_gamma;
|
cb->gamma = m_gamma;
|
||||||
|
cb->uvOffsetX = 0.0f;
|
||||||
|
cb->uvOffsetY = 0.0f;
|
||||||
|
cb->uvScaleX = 1.0f;
|
||||||
|
cb->uvScaleY = 1.0f;
|
||||||
ctx->Unmap(m_pGammaCB, 0);
|
ctx->Unmap(m_pGammaCB, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,27 +341,6 @@ void PostProcesser::ApplyFromCopied() const
|
||||||
|
|
||||||
ID3D11DeviceContext* ctx = g_pImmediateContext;
|
ID3D11DeviceContext* ctx = g_pImmediateContext;
|
||||||
|
|
||||||
D3D11_MAPPED_SUBRESOURCE mapped;
|
|
||||||
const D3D11_MAP mapType = m_wineMode ? D3D11_MAP_WRITE_NO_OVERWRITE : D3D11_MAP_WRITE_DISCARD;
|
|
||||||
const HRESULT hr = ctx->Map(m_pGammaCB, 0, mapType, 0, &mapped);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
const auto cb = static_cast<GammaCBData*>(mapped.pData);
|
|
||||||
cb->gamma = m_gamma;
|
|
||||||
ctx->Unmap(m_pGammaCB, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D11RenderTargetView* oldRTV = nullptr;
|
|
||||||
ID3D11DepthStencilView* oldDSV = nullptr;
|
|
||||||
ctx->OMGetRenderTargets(1, &oldRTV, &oldDSV);
|
|
||||||
|
|
||||||
UINT numViewports = 1;
|
|
||||||
D3D11_VIEWPORT oldViewport = {};
|
|
||||||
ctx->RSGetViewports(&numViewports, &oldViewport);
|
|
||||||
|
|
||||||
ID3D11RenderTargetView* bbRTV = g_pRenderTargetView;
|
|
||||||
ctx->OMSetRenderTargets(1, &bbRTV, nullptr);
|
|
||||||
|
|
||||||
D3D11_VIEWPORT vp;
|
D3D11_VIEWPORT vp;
|
||||||
if (m_useCustomViewport)
|
if (m_useCustomViewport)
|
||||||
{
|
{
|
||||||
|
|
@ -369,6 +356,33 @@ void PostProcesser::ApplyFromCopied() const
|
||||||
vp.TopLeftY = 0;
|
vp.TopLeftY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
D3D11_MAPPED_SUBRESOURCE mapped;
|
||||||
|
const D3D11_MAP mapType = m_wineMode ? D3D11_MAP_WRITE_NO_OVERWRITE : D3D11_MAP_WRITE_DISCARD;
|
||||||
|
const HRESULT hr = ctx->Map(m_pGammaCB, 0, mapType, 0, &mapped);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
const auto cb = static_cast<GammaCBData*>(mapped.pData);
|
||||||
|
cb->gamma = m_gamma;
|
||||||
|
const float texW = static_cast<float>(m_gammaTexWidth);
|
||||||
|
const float texH = static_cast<float>(m_gammaTexHeight);
|
||||||
|
cb->uvOffsetX = vp.TopLeftX / texW;
|
||||||
|
cb->uvOffsetY = vp.TopLeftY / texH;
|
||||||
|
cb->uvScaleX = vp.Width / texW;
|
||||||
|
cb->uvScaleY = vp.Height / texH;
|
||||||
|
ctx->Unmap(m_pGammaCB, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D11RenderTargetView* oldRTV = nullptr;
|
||||||
|
ID3D11DepthStencilView* oldDSV = nullptr;
|
||||||
|
ctx->OMGetRenderTargets(1, &oldRTV, &oldDSV);
|
||||||
|
|
||||||
|
UINT numViewports = 1;
|
||||||
|
D3D11_VIEWPORT oldViewport = {};
|
||||||
|
ctx->RSGetViewports(&numViewports, &oldViewport);
|
||||||
|
|
||||||
|
ID3D11RenderTargetView* bbRTV = g_pRenderTargetView;
|
||||||
|
ctx->OMSetRenderTargets(1, &bbRTV, nullptr);
|
||||||
|
|
||||||
ctx->RSSetViewports(1, &vp);
|
ctx->RSSetViewports(1, &vp);
|
||||||
|
|
||||||
ctx->IASetInputLayout(nullptr);
|
ctx->IASetInputLayout(nullptr);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue