Play-/Source/gs/GSH_Vulkan/GSH_VulkanDraw.cpp

323 lines
10 KiB
C++
Raw Permalink Normal View History

2019-10-01 12:31:49 -04:00
#include "GSH_VulkanDraw.h"
2019-11-22 17:59:32 -05:00
#include "GSH_VulkanMemoryUtils.h"
2019-10-01 12:31:49 -04:00
#include "MemStream.h"
#include "vulkan/StructDefs.h"
2019-10-03 18:06:59 -04:00
#include "vulkan/Utils.h"
2019-10-01 12:31:49 -04:00
#include "nuanceur/Builder.h"
#include "nuanceur/generators/SpirvShaderGenerator.h"
2019-11-28 20:17:10 -05:00
#include "../GSHandler.h"
2019-12-06 09:23:32 -05:00
#include "../GsPixelFormats.h"
2019-10-01 12:31:49 -04:00
using namespace GSH_Vulkan;
2019-11-21 13:16:48 -05:00
#define VERTEX_ATTRIB_LOCATION_POSITION 0
#define VERTEX_ATTRIB_LOCATION_DEPTH 1
#define VERTEX_ATTRIB_LOCATION_COLOR 2
#define VERTEX_ATTRIB_LOCATION_TEXCOORD 3
2020-02-02 11:33:34 -05:00
#define VERTEX_ATTRIB_LOCATION_FOG 4
2019-11-21 13:16:48 -05:00
#define MAX_VERTEX_COUNT 1024 * 512
2019-10-01 12:31:49 -04:00
CDraw::CDraw(const ContextPtr& context, const FrameCommandBufferPtr& frameCommandBuffer)
2019-12-13 23:21:59 -05:00
: m_context(context)
, m_frameCommandBuffer(frameCommandBuffer)
, m_pipelineCache(context->device)
2019-10-01 12:31:49 -04:00
{
for(auto& frame : m_frames)
{
frame.vertexBuffer = Framework::Vulkan::CBuffer(
2020-01-31 09:34:48 -05:00
m_context->device, m_context->physicalDeviceMemoryProperties,
2021-03-29 17:04:29 -04:00
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
sizeof(PRIM_VERTEX) * MAX_VERTEX_COUNT);
2019-12-13 23:21:59 -05:00
auto result = m_context->device.vkMapMemory(m_context->device, frame.vertexBuffer.GetMemory(),
2020-01-31 09:34:48 -05:00
0, VK_WHOLE_SIZE, 0, reinterpret_cast<void**>(&frame.vertexBufferPtr));
CHECKVULKANERROR(result);
}
2019-11-18 20:01:11 -05:00
2019-11-21 13:16:48 -05:00
m_pipelineCaps <<= 0;
2019-10-01 12:31:49 -04:00
}
CDraw::~CDraw()
{
for(auto& frame : m_frames)
{
m_context->device.vkUnmapMemory(m_context->device, frame.vertexBuffer.GetMemory());
}
2019-10-01 12:31:49 -04:00
}
2019-11-21 13:16:48 -05:00
void CDraw::SetPipelineCaps(const PIPELINE_CAPS& caps)
2019-11-16 11:27:23 -05:00
{
2019-11-21 13:16:48 -05:00
bool changed = static_cast<uint64>(caps) != static_cast<uint64>(m_pipelineCaps);
if(!changed) return;
if(caps.textureUseMemoryCopy)
{
FlushRenderPass();
}
2019-11-21 13:16:48 -05:00
FlushVertices();
m_pipelineCaps = caps;
}
2020-01-07 13:09:58 -05:00
void CDraw::SetFramebufferParams(uint32 addr, uint32 width, uint32 writeMask)
2019-11-21 13:16:48 -05:00
{
2019-12-13 23:21:59 -05:00
bool changed =
(m_pushConstants.fbBufAddr != addr) ||
2020-01-07 13:09:58 -05:00
(m_pushConstants.fbBufWidth != width) ||
(m_pushConstants.fbWriteMask != writeMask);
2019-11-21 13:16:48 -05:00
if(!changed) return;
FlushVertices();
m_pushConstants.fbBufAddr = addr;
m_pushConstants.fbBufWidth = width;
2020-01-07 13:09:58 -05:00
m_pushConstants.fbWriteMask = writeMask;
2019-11-16 11:27:23 -05:00
}
2019-12-22 16:34:47 -05:00
void CDraw::SetDepthbufferParams(uint32 addr, uint32 width)
{
bool changed =
(m_pushConstants.depthBufAddr != addr) ||
(m_pushConstants.depthBufWidth != width);
if(!changed) return;
FlushVertices();
m_pushConstants.depthBufAddr = addr;
m_pushConstants.depthBufWidth = width;
}
2020-01-09 13:06:41 -05:00
void CDraw::SetTextureParams(uint32 bufAddr, uint32 bufWidth, uint32 width, uint32 height, uint32 csa)
{
2019-12-13 23:21:59 -05:00
bool changed =
(m_pushConstants.texBufAddr != bufAddr) ||
(m_pushConstants.texBufWidth != bufWidth) ||
(m_pushConstants.texWidth != width) ||
2020-01-09 13:06:41 -05:00
(m_pushConstants.texHeight != height) ||
(m_pushConstants.texCsa != csa);
if(!changed) return;
FlushVertices();
m_pushConstants.texBufAddr = bufAddr;
m_pushConstants.texBufWidth = bufWidth;
m_pushConstants.texWidth = width;
m_pushConstants.texHeight = height;
2020-01-09 13:06:41 -05:00
m_pushConstants.texCsa = csa;
}
void CDraw::SetClutBufferOffset(uint32 clutBufferOffset)
{
bool changed = m_clutBufferOffset != clutBufferOffset;
if(!changed) return;
FlushVertices();
m_clutBufferOffset = clutBufferOffset;
}
2020-01-14 13:25:09 -05:00
void CDraw::SetTextureAlphaParams(uint32 texA0, uint32 texA1)
{
bool changed =
(m_pushConstants.texA0 != texA0) ||
(m_pushConstants.texA1 != texA1);
if(!changed) return;
FlushVertices();
m_pushConstants.texA0 = texA0;
m_pushConstants.texA1 = texA1;
}
2020-01-20 12:53:09 -05:00
void CDraw::SetTextureClampParams(uint32 clampMinU, uint32 clampMinV, uint32 clampMaxU, uint32 clampMaxV)
{
bool changed =
(m_pushConstants.clampMin[0] != clampMinU) ||
(m_pushConstants.clampMin[1] != clampMinV) ||
(m_pushConstants.clampMax[0] != clampMaxU) ||
(m_pushConstants.clampMax[1] != clampMaxV);
if(!changed) return;
FlushVertices();
m_pushConstants.clampMin[0] = clampMinU;
m_pushConstants.clampMin[1] = clampMinV;
m_pushConstants.clampMax[0] = clampMaxU;
m_pushConstants.clampMax[1] = clampMaxV;
}
2020-02-02 11:33:34 -05:00
void CDraw::SetFogParams(float fogR, float fogG, float fogB)
{
bool changed =
(m_pushConstants.fogColor[0] != fogR) ||
(m_pushConstants.fogColor[1] != fogG) ||
(m_pushConstants.fogColor[2] != fogB);
if(!changed) return;
FlushVertices();
m_pushConstants.fogColor[0] = fogR;
m_pushConstants.fogColor[1] = fogG;
m_pushConstants.fogColor[2] = fogB;
m_pushConstants.fogColor[3] = 0;
}
void CDraw::SetAlphaTestParams(uint32 alphaRef)
{
bool changed = (m_pushConstants.alphaRef != alphaRef);
if(!changed) return;
FlushVertices();
m_pushConstants.alphaRef = alphaRef;
}
2020-01-08 12:51:47 -05:00
void CDraw::SetAlphaBlendingParams(uint32 alphaFix)
{
bool changed =
2020-01-31 09:34:48 -05:00
(m_pushConstants.alphaFix != alphaFix);
2020-01-08 12:51:47 -05:00
if(!changed) return;
FlushVertices();
m_pushConstants.alphaFix = alphaFix;
}
2019-12-12 13:24:06 -05:00
void CDraw::SetScissor(uint32 scissorX, uint32 scissorY, uint32 scissorWidth, uint32 scissorHeight)
{
2019-12-13 23:21:59 -05:00
bool changed =
(m_scissorX != scissorX) ||
(m_scissorY != scissorY) ||
(m_scissorWidth != scissorWidth) ||
(m_scissorHeight != scissorHeight);
2019-12-12 13:24:06 -05:00
if(!changed) return;
FlushVertices();
m_scissorX = scissorX;
m_scissorY = scissorY;
m_scissorWidth = scissorWidth;
m_scissorHeight = scissorHeight;
}
2021-04-12 15:39:33 -04:00
void CDraw::SetMemoryCopyParams(uint32 memoryCopyAddress, uint32 memoryCopySize)
{
bool changed =
(memoryCopyAddress != m_memoryCopyAddress) ||
(memoryCopySize != m_memoryCopySize);
if(!changed) return;
FlushRenderPass();
2021-04-12 15:39:33 -04:00
m_memoryCopyAddress = memoryCopyAddress;
m_memoryCopySize = memoryCopySize;
}
2019-10-01 12:31:49 -04:00
void CDraw::AddVertices(const PRIM_VERTEX* vertexBeginPtr, const PRIM_VERTEX* vertexEndPtr)
{
2019-10-03 18:06:59 -04:00
auto amount = vertexEndPtr - vertexBeginPtr;
2019-11-18 20:01:11 -05:00
if((m_passVertexEnd + amount) > MAX_VERTEX_COUNT)
2019-10-04 09:21:26 -04:00
{
m_frameCommandBuffer->Flush();
assert((m_passVertexEnd + amount) <= MAX_VERTEX_COUNT);
2019-10-04 09:21:26 -04:00
}
if(m_pipelineCaps.textureUseMemoryCopy)
{
//Check if sprite we are about to add overlaps with current region
//Some games use tiny sprites to do full screen effects that requires
//to keep a copy of RAM for texture sampling:
//- Metal Gear Solid 3
//- MK: Shaolin Monks
//- Tales of Legendia
const auto topLeftCorner = vertexBeginPtr;
const auto bottomRightCorner = vertexBeginPtr + 5;
CGsSpriteRect rect(topLeftCorner->x, topLeftCorner->y, bottomRightCorner->x, bottomRightCorner->y);
if(m_memoryCopyRegion.Intersects(rect))
{
FlushRenderPass();
}
else
{
m_memoryCopyRegion.Insert(rect);
}
}
auto& frame = m_frames[m_frameCommandBuffer->GetCurrentFrame()];
memcpy(frame.vertexBufferPtr + m_passVertexEnd, vertexBeginPtr, amount * sizeof(PRIM_VERTEX));
m_passVertexEnd += amount;
2019-10-01 12:31:49 -04:00
}
2020-01-30 12:58:06 -05:00
void CDraw::PreFlushFrameCommandBuffer()
{
FlushRenderPass();
}
2019-11-18 20:01:11 -05:00
void CDraw::PostFlushFrameCommandBuffer()
{
2019-11-18 20:01:11 -05:00
m_passVertexStart = m_passVertexEnd = 0;
2019-10-01 12:31:49 -04:00
}
std::vector<VkVertexInputAttributeDescription> CDraw::GetVertexAttributes()
2019-11-16 11:27:23 -05:00
{
2019-10-01 12:31:49 -04:00
std::vector<VkVertexInputAttributeDescription> vertexAttributes;
{
2019-10-04 09:21:26 -04:00
VkVertexInputAttributeDescription vertexAttributeDesc = {};
vertexAttributeDesc.format = VK_FORMAT_R32G32_SFLOAT;
vertexAttributeDesc.offset = offsetof(PRIM_VERTEX, x);
2019-11-21 13:16:48 -05:00
vertexAttributeDesc.location = VERTEX_ATTRIB_LOCATION_POSITION;
2019-10-04 09:21:26 -04:00
vertexAttributes.push_back(vertexAttributeDesc);
}
{
VkVertexInputAttributeDescription vertexAttributeDesc = {};
vertexAttributeDesc.format = VK_FORMAT_R32_UINT;
vertexAttributeDesc.offset = offsetof(PRIM_VERTEX, z);
2019-11-21 13:16:48 -05:00
vertexAttributeDesc.location = VERTEX_ATTRIB_LOCATION_DEPTH;
2019-10-04 09:21:26 -04:00
vertexAttributes.push_back(vertexAttributeDesc);
2019-10-01 12:31:49 -04:00
}
{
2019-10-04 09:21:26 -04:00
VkVertexInputAttributeDescription vertexAttributeDesc = {};
vertexAttributeDesc.format = VK_FORMAT_R8G8B8A8_UNORM;
vertexAttributeDesc.offset = offsetof(PRIM_VERTEX, color);
2019-11-21 13:16:48 -05:00
vertexAttributeDesc.location = VERTEX_ATTRIB_LOCATION_COLOR;
vertexAttributes.push_back(vertexAttributeDesc);
}
{
VkVertexInputAttributeDescription vertexAttributeDesc = {};
vertexAttributeDesc.format = VK_FORMAT_R32G32B32_SFLOAT;
vertexAttributeDesc.offset = offsetof(PRIM_VERTEX, s);
vertexAttributeDesc.location = VERTEX_ATTRIB_LOCATION_TEXCOORD;
2019-10-04 09:21:26 -04:00
vertexAttributes.push_back(vertexAttributeDesc);
2019-10-01 12:31:49 -04:00
}
2020-02-02 11:33:34 -05:00
{
VkVertexInputAttributeDescription vertexAttributeDesc = {};
vertexAttributeDesc.format = VK_FORMAT_R32_SFLOAT;
vertexAttributeDesc.offset = offsetof(PRIM_VERTEX, f);
vertexAttributeDesc.location = VERTEX_ATTRIB_LOCATION_FOG;
vertexAttributes.push_back(vertexAttributeDesc);
}
2021-09-16 13:55:50 -04:00
return vertexAttributes;
2019-10-01 12:31:49 -04:00
}
2021-07-14 14:07:46 -04:00
Framework::Vulkan::CShaderModule CDraw::CreateVertexShader(const PIPELINE_CAPS& caps)
2019-10-01 12:31:49 -04:00
{
using namespace Nuanceur;
2019-12-13 23:21:59 -05:00
2019-10-01 12:31:49 -04:00
auto b = CShaderBuilder();
2019-12-13 23:21:59 -05:00
2019-10-01 12:31:49 -04:00
{
2019-10-03 18:06:59 -04:00
//Vertex Inputs
2019-10-01 12:31:49 -04:00
auto inputPosition = CFloat4Lvalue(b.CreateInput(Nuanceur::SEMANTIC_POSITION));
2019-12-24 17:17:54 -05:00
auto inputDepth = CUint4Lvalue(b.CreateInputUint(Nuanceur::SEMANTIC_TEXCOORD, VERTEX_ATTRIB_LOCATION_DEPTH - 1));
2019-11-21 13:16:48 -05:00
auto inputColor = CFloat4Lvalue(b.CreateInput(Nuanceur::SEMANTIC_TEXCOORD, VERTEX_ATTRIB_LOCATION_COLOR - 1));
auto inputTexCoord = CFloat4Lvalue(b.CreateInput(Nuanceur::SEMANTIC_TEXCOORD, VERTEX_ATTRIB_LOCATION_TEXCOORD - 1));
2020-02-02 11:33:34 -05:00
auto inputFog = CFloat4Lvalue(b.CreateInput(Nuanceur::SEMANTIC_TEXCOORD, VERTEX_ATTRIB_LOCATION_FOG - 1));
2019-10-04 09:21:26 -04:00
2019-10-03 18:06:59 -04:00
//Outputs
2019-10-01 12:31:49 -04:00
auto outputPosition = CFloat4Lvalue(b.CreateOutput(Nuanceur::SEMANTIC_SYSTEM_POSITION));
2021-07-14 14:07:46 -04:00
auto outputPointSize = CFloatLvalue(b.CreateOutput(Nuanceur::SEMANTIC_SYSTEM_POINTSIZE));
2019-12-24 17:17:54 -05:00
auto outputDepth = CFloat4Lvalue(b.CreateOutput(Nuanceur::SEMANTIC_TEXCOORD, 1));
auto outputColor = CFloat4Lvalue(b.CreateOutput(Nuanceur::SEMANTIC_TEXCOORD, 2));
auto outputTexCoord = CFloat4Lvalue(b.CreateOutput(Nuanceur::SEMANTIC_TEXCOORD, 3));
2020-02-02 11:33:34 -05:00
auto outputFog = CFloat4Lvalue(b.CreateOutput(Nuanceur::SEMANTIC_TEXCOORD, 4));
2019-10-03 18:06:59 -04:00
auto position = ((inputPosition->xy() + NewFloat2(b, 0.5f, 0.5f)) * NewFloat2(b, 2.f / DRAW_AREA_SIZE, 2.f / DRAW_AREA_SIZE) + NewFloat2(b, -1, -1));
2019-10-03 18:06:59 -04:00
outputPosition = NewFloat4(position, NewFloat2(b, 0.f, 1.f));
2021-07-14 14:07:46 -04:00
if(caps.primitiveType == PIPELINE_PRIMITIVE_POINT)
{
outputPointSize = NewFloat(b, 1.0f);
}
2019-12-24 17:17:54 -05:00
outputDepth = ToFloat(inputDepth) / NewFloat4(b, DEPTH_MAX, DEPTH_MAX, DEPTH_MAX, DEPTH_MAX);
2019-10-04 09:21:26 -04:00
outputColor = inputColor->xyzw();
2019-11-21 13:16:48 -05:00
outputTexCoord = inputTexCoord->xyzw();
2020-02-02 11:33:34 -05:00
outputFog = inputFog->xyzw();
2019-10-01 12:31:49 -04:00
}
2019-12-13 23:21:59 -05:00
2019-10-01 12:31:49 -04:00
Framework::CMemStream shaderStream;
Nuanceur::CSpirvShaderGenerator::Generate(shaderStream, b, Nuanceur::CSpirvShaderGenerator::SHADER_TYPE_VERTEX);
shaderStream.Seek(0, Framework::STREAM_SEEK_SET);
2019-11-21 13:16:48 -05:00
return Framework::Vulkan::CShaderModule(m_context->device, shaderStream);
2019-10-01 12:31:49 -04:00
}