cnq3/code/renderer/grp_blit.cpp
2024-11-04 00:23:09 +01:00

147 lines
4.1 KiB
C++

/*
===========================================================================
Copyright (C) 2024 Gian 'myT' Schellenbaum
This file is part of Challenge Quake 3 (CNQ3).
Challenge Quake 3 is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Challenge Quake 3 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
===========================================================================
*/
// Gameplay Rendering Pipeline - blitting
#include "grp_local.h"
#include "compshaders/grp/blit.h"
#pragma pack(push, 4)
struct BlitVertexRC
{
float scaleX;
float scaleY;
};
#pragma pack(pop)
void Blitter::Init()
{
if(!srp.firstInit)
{
return;
}
{
RootSignatureDesc desc("blitter");
desc.usingVertexBuffers = false;
desc.constants[ShaderStage::Vertex].byteCount = sizeof(BlitVertexRC);
desc.samplerCount = 1;
desc.samplerVisibility = ShaderStages::PixelBit;
desc.AddRange(DescriptorType::Texture, 0, 1);
desc.genericVisibility = ShaderStages::PixelBit;
rootSignature = CreateRootSignature(desc);
}
{
DescriptorTableDesc desc("blitter", rootSignature);
descriptorTable = CreateDescriptorTable(desc);
DescriptorTableUpdate update;
update.SetSamplers(1, &grp.samplers[GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Linear)]);
UpdateDescriptorTable(descriptorTable, update);
}
{
GraphicsPipelineDesc desc("blitter", rootSignature);
desc.vertexShader = ShaderByteCode(g_blit_vs);
desc.pixelShader = ShaderByteCode(g_blit_ps);
desc.depthStencil.DisableDepth();
desc.rasterizer.cullMode = CT_TWO_SIDED;
desc.AddRenderTarget(0, TextureFormat::R8G8B8A8_UNorm);
pipeline = CreateGraphicsPipeline(desc);
}
}
void Blitter::Blit(HTexture renderTarget)
{
SCOPED_RENDER_PASS("Blit to Swap Chain", 0.125f, 0.125f, 0.5f);
CmdBeginBarrier();
CmdTextureBarrier(grp.renderTarget, ResourceStates::PixelShaderAccessBit);
CmdTextureBarrier(renderTarget, ResourceStates::RenderTargetBit);
CmdEndBarrier();
float vsX = 1.0f; // vertex shader scale factors
float vsY = 1.0f;
float srX = 1.0f; // scissor rectangle scale factors
float srY = 1.0f;
if(r_fullscreen->integer == 1 && r_mode->integer == VIDEOMODE_UPSCALE)
{
if(r_blitMode->integer == BLITMODE_CENTERED)
{
vsX = (float)glConfig.vidWidth / (float)glInfo.winWidth;
vsY = (float)glConfig.vidHeight / (float)glInfo.winHeight;
}
else if(r_blitMode->integer == BLITMODE_ASPECT)
{
const float ars = (float)glConfig.vidWidth / (float)glConfig.vidHeight;
const float ard = (float)glInfo.winWidth / (float)glInfo.winHeight;
if(ard > ars)
{
vsX = ars / ard;
vsY = 1.0f;
srX = (float)glInfo.winHeight / (float)glConfig.vidHeight;
srY = srX;
}
else
{
vsX = 1.0f;
vsY = ard / ars;
srX = (float)glInfo.winWidth / (float)glConfig.vidWidth;
srY = srX;
}
}
}
if(vsX != 1.0f || vsY != 1.0f)
{
CmdClearColorTarget(renderTarget, colorBlack);
const int x = (glInfo.winWidth - glInfo.winWidth * vsX) / 2.0f;
const int y = (glInfo.winHeight - glInfo.winHeight * vsY) / 2.0f;
CmdSetViewport(0, 0, glInfo.winWidth, glInfo.winHeight);
CmdSetScissor(x, y, glConfig.vidWidth * srX, glConfig.vidHeight * srY);
}
else
{
CmdSetViewportAndScissor(0, 0, glInfo.winWidth, glInfo.winHeight);
}
BlitVertexRC vertexRC = {};
vertexRC.scaleX = vsX;
vertexRC.scaleY = vsY;
CmdBindRenderTargets(1, &renderTarget, NULL);
CmdBindPipeline(pipeline);
CmdBindRootSignature(rootSignature);
CmdBindDescriptorTable(rootSignature, descriptorTable);
CmdSetRootConstants(rootSignature, ShaderStage::Vertex, &vertexRC);
CmdDraw(3, 0);
}
void Blitter::SetInputTexture(HTexture source)
{
DescriptorTableUpdate update;
update.SetTextures(1, &source);
UpdateDescriptorTable(descriptorTable, update);
}