mirror of
https://github.com/libretro/ppsspp.git
synced 2025-02-21 09:21:02 +00:00
Initial vulkan code.
This was squashed from nine commits but using old versions of Vulkan.
This commit is contained in:
parent
538d801f17
commit
c64064024d
@ -50,10 +50,14 @@ enum BufferFilter {
|
||||
enum class GPUBackend {
|
||||
OPENGL = 0,
|
||||
DIRECT3D9 = 1,
|
||||
DIRECT3D11 = 2,
|
||||
VULKAN = 3,
|
||||
};
|
||||
enum {
|
||||
GPU_BACKEND_OPENGL = (int)GPUBackend::OPENGL,
|
||||
GPU_BACKEND_DIRECT3D9 = (int)GPUBackend::DIRECT3D9,
|
||||
GPU_BACKEND_DIRECT3D11 = (int)GPUBackend::DIRECT3D11,
|
||||
GPU_BACKEND_VULKAN = (int)GPUBackend::VULKAN,
|
||||
};
|
||||
|
||||
enum AudioBackendType {
|
||||
|
@ -34,6 +34,7 @@
|
||||
#ifdef _WIN32
|
||||
#include "Windows/GPU/WindowsGLContext.h"
|
||||
#include "Windows/GPU/D3D9Context.h"
|
||||
#include "Windows/GPU/WindowsVulkanContext.h"
|
||||
#include "Windows/InputDevice.h"
|
||||
#endif
|
||||
|
||||
|
@ -31,6 +31,8 @@ enum GPUCore {
|
||||
GPU_GLES,
|
||||
GPU_SOFTWARE,
|
||||
GPU_DIRECTX9,
|
||||
GPU_DIRECTX11,
|
||||
GPU_VULKAN,
|
||||
};
|
||||
|
||||
class FileLoader;
|
||||
|
@ -22,6 +22,7 @@ enum DebugShaderType {
|
||||
SHADER_TYPE_FRAGMENT = 1,
|
||||
SHADER_TYPE_GEOMETRY = 2,
|
||||
SHADER_TYPE_VERTEXLOADER = 3, // Not really a shader, but might as well re-use this mechanism
|
||||
SHADER_TYPE_PIPELINE = 4, // Vulkan and DX12 combines a bunch of state into pipeline objects. Might as well make them inspectable.
|
||||
};
|
||||
|
||||
enum DebugShaderStringType {
|
||||
|
@ -24,6 +24,9 @@
|
||||
#include "GPU/Common/GPUDebugInterface.h"
|
||||
#include "Common/MemoryUtil.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
enum TextureFiltering {
|
||||
TEX_FILTER_AUTO = 1,
|
||||
TEX_FILTER_NEAREST = 2,
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "GPU/GPU.h"
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "GPU/GLES/GLES_GPU.h"
|
||||
#include "GPU/Vulkan/GPU_Vulkan.h"
|
||||
#include "GPU/Null/NullGpu.h"
|
||||
#include "GPU/Software/SoftGpu.h"
|
||||
|
||||
@ -57,6 +58,9 @@ bool GPU_Init(GraphicsContext *ctx) {
|
||||
SetGPU(new DIRECTX9_GPU(ctx));
|
||||
#endif
|
||||
break;
|
||||
case GPU_VULKAN:
|
||||
SetGPU(new GPU_Vulkan());
|
||||
break;
|
||||
}
|
||||
|
||||
return gpu != NULL;
|
||||
|
@ -244,6 +244,16 @@
|
||||
<ClInclude Include="Software\SoftGpu.h" />
|
||||
<ClInclude Include="Software\TransformUnit.h" />
|
||||
<ClInclude Include="Common\TextureDecoder.h" />
|
||||
<ClInclude Include="Vulkan\DrawEngineVulkan.h" />
|
||||
<ClInclude Include="Vulkan\FragmentShaderGeneratorVulkan.h" />
|
||||
<ClInclude Include="Vulkan\FramebufferVulkan.h" />
|
||||
<ClInclude Include="Vulkan\GPU_Vulkan.h" />
|
||||
<ClInclude Include="Vulkan\PipelineManagerVulkan.h" />
|
||||
<ClInclude Include="Vulkan\ShaderCompiler.h" />
|
||||
<ClInclude Include="Vulkan\ShaderManagerVulkan.h" />
|
||||
<ClInclude Include="Vulkan\TextureCacheVulkan.h" />
|
||||
<ClInclude Include="Vulkan\VertexShaderGeneratorVulkan.h" />
|
||||
<ClInclude Include="Vulkan\VulkanUtil.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\ext\xbrz\xbrz.cpp" />
|
||||
@ -322,6 +332,15 @@
|
||||
<ClCompile Include="Software\SoftGpu.cpp" />
|
||||
<ClCompile Include="Software\TransformUnit.cpp" />
|
||||
<ClCompile Include="Common\TextureDecoder.cpp" />
|
||||
<ClCompile Include="Vulkan\DrawEngineVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\FragmentShaderGeneratorVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\FramebufferVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\GPU_Vulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\PipelineManagerVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\ShaderCompiler.cpp" />
|
||||
<ClCompile Include="Vulkan\ShaderManagerVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\StateMappingVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\VertexShaderGeneratorVulkan.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\Common.vcxproj">
|
||||
|
@ -201,6 +201,16 @@
|
||||
<ClInclude Include="Common\ShaderId.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Vulkan\GPU_Vulkan.h" />
|
||||
<ClInclude Include="Vulkan\DrawEngineVulkan.h" />
|
||||
<ClInclude Include="Vulkan\TextureCacheVulkan.h" />
|
||||
<ClInclude Include="Vulkan\FramebufferVulkan.h" />
|
||||
<ClInclude Include="Vulkan\PipelineManagerVulkan.h" />
|
||||
<ClInclude Include="Vulkan\VulkanUtil.h" />
|
||||
<ClInclude Include="Vulkan\VertexShaderGeneratorVulkan.h" />
|
||||
<ClInclude Include="Vulkan\FragmentShaderGeneratorVulkan.h" />
|
||||
<ClInclude Include="Vulkan\ShaderManagerVulkan.h" />
|
||||
<ClInclude Include="Vulkan\ShaderCompiler.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Math3D.cpp">
|
||||
@ -386,5 +396,14 @@
|
||||
<ClCompile Include="Common\ShaderId.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vulkan\GPU_Vulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\StateMappingVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\PipelineManagerVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\VertexShaderGeneratorVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\DrawEngineVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\FramebufferVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\FragmentShaderGeneratorVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\ShaderManagerVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\ShaderCompiler.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
466
GPU/Vulkan/DrawEngineVulkan.cpp
Normal file
466
GPU/Vulkan/DrawEngineVulkan.cpp
Normal file
@ -0,0 +1,466 @@
|
||||
#include "GPU/Vulkan/DrawEngineVulkan.h"
|
||||
|
||||
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/timeutil.h"
|
||||
|
||||
#include "Common/MemoryUtil.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
|
||||
#include "GPU/Math3D.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/ge_constants.h"
|
||||
|
||||
#include "GPU/Common/TextureDecoder.h"
|
||||
#include "GPU/Common/SplineCommon.h"
|
||||
#include "GPU/Common/TransformCommon.h"
|
||||
#include "GPU/Common/VertexDecoderCommon.h"
|
||||
#include "GPU/Common/SoftwareTransformCommon.h"
|
||||
#include "GPU/Common/DrawEngineCommon.h"
|
||||
#include "GPU/Vulkan/DrawEngineVulkan.h"
|
||||
#include "GPU/Vulkan/TextureCacheVulkan.h"
|
||||
#include "GPU/Vulkan/ShaderManagerVulkan.h"
|
||||
#include "GPU/Vulkan/PipelineManagerVulkan.h"
|
||||
#include "GPU/Vulkan/GPU_Vulkan.h"
|
||||
|
||||
const VkPrimitiveTopology prim[8] = {
|
||||
VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
|
||||
VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
|
||||
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
|
||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
|
||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
|
||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // Vulkan doesn't do quads. We could do strips with restart-index though. We could also do RECT primitives in the geometry shader.
|
||||
};
|
||||
|
||||
enum {
|
||||
TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof(TransformedVertex)
|
||||
};
|
||||
|
||||
DrawEngineVulkan::DrawEngineVulkan()
|
||||
: decodedVerts_(0),
|
||||
prevPrim_(GE_PRIM_INVALID),
|
||||
lastVType_(-1),
|
||||
pipelineManager_(nullptr),
|
||||
textureCache_(nullptr),
|
||||
framebufferManager_(nullptr),
|
||||
numDrawCalls(0),
|
||||
vertexCountInDrawCalls(0),
|
||||
decodeCounter_(0),
|
||||
dcid_(0),
|
||||
fboTexNeedBind_(false),
|
||||
fboTexBound_(false) {
|
||||
|
||||
memset(&decOptions_, 0, sizeof(decOptions_));
|
||||
decOptions_.expandAllUVtoFloat = true;
|
||||
decOptions_.expandAllWeightsToFloat = true;
|
||||
decOptions_.expand8BitNormalsToFloat = true;
|
||||
|
||||
// Allocate nicely aligned memory. Maybe graphics drivers will
|
||||
// appreciate it.
|
||||
// All this is a LOT of memory, need to see if we can cut down somehow.
|
||||
decoded = (u8 *)AllocateMemoryPages(DECODED_VERTEX_BUFFER_SIZE);
|
||||
decIndex = (u16 *)AllocateMemoryPages(DECODED_INDEX_BUFFER_SIZE);
|
||||
splineBuffer = (u8 *)AllocateMemoryPages(SPLINE_BUFFER_SIZE);
|
||||
transformed = (TransformedVertex *)AllocateMemoryPages(TRANSFORMED_VERTEX_BUFFER_SIZE);
|
||||
transformedExpanded = (TransformedVertex *)AllocateMemoryPages(3 * TRANSFORMED_VERTEX_BUFFER_SIZE);
|
||||
|
||||
indexGen.Setup(decIndex);
|
||||
}
|
||||
|
||||
DrawEngineVulkan::~DrawEngineVulkan() {
|
||||
FreeMemoryPages(decoded, DECODED_VERTEX_BUFFER_SIZE);
|
||||
FreeMemoryPages(decIndex, DECODED_INDEX_BUFFER_SIZE);
|
||||
FreeMemoryPages(splineBuffer, SPLINE_BUFFER_SIZE);
|
||||
FreeMemoryPages(transformed, TRANSFORMED_VERTEX_BUFFER_SIZE);
|
||||
FreeMemoryPages(transformedExpanded, 3 * TRANSFORMED_VERTEX_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
VertexDecoder *DrawEngineVulkan::GetVertexDecoder(u32 vtype) {
|
||||
auto iter = decoderMap_.find(vtype);
|
||||
if (iter != decoderMap_.end())
|
||||
return iter->second;
|
||||
VertexDecoder *dec = new VertexDecoder();
|
||||
dec->SetVertexType(vtype, decOptions_, decJitCache_);
|
||||
decoderMap_[vtype] = dec;
|
||||
return dec;
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::SetupVertexDecoder(u32 vertType) {
|
||||
SetupVertexDecoderInternal(vertType);
|
||||
}
|
||||
|
||||
inline void DrawEngineVulkan::SetupVertexDecoderInternal(u32 vertType) {
|
||||
// As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it
|
||||
// into the top of the verttype where there are unused bits.
|
||||
const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24);
|
||||
|
||||
// If vtype has changed, setup the vertex decoder.
|
||||
if (vertTypeID != lastVType_) {
|
||||
dec_ = GetVertexDecoder(vertTypeID);
|
||||
lastVType_ = vertTypeID;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) {
|
||||
if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawCalls >= MAX_DEFERRED_DRAW_CALLS || vertexCountInDrawCalls + vertexCount > VERTEX_BUFFER_MAX)
|
||||
Flush(cmd_);
|
||||
|
||||
// TODO: Is this the right thing to do?
|
||||
if (prim == GE_PRIM_KEEP_PREVIOUS) {
|
||||
prim = prevPrim_ != GE_PRIM_INVALID ? prevPrim_ : GE_PRIM_POINTS;
|
||||
} else {
|
||||
prevPrim_ = prim;
|
||||
}
|
||||
|
||||
SetupVertexDecoderInternal(vertType);
|
||||
|
||||
*bytesRead = vertexCount * dec_->VertexSize();
|
||||
|
||||
if ((vertexCount < 2 && prim > 0) || (vertexCount < 3 && prim > 2 && prim != GE_PRIM_RECTANGLES))
|
||||
return;
|
||||
|
||||
DeferredDrawCall &dc = drawCalls[numDrawCalls];
|
||||
dc.verts = verts;
|
||||
dc.inds = inds;
|
||||
dc.vertType = vertType;
|
||||
dc.indexType = (vertType & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT;
|
||||
dc.prim = prim;
|
||||
dc.vertexCount = vertexCount;
|
||||
|
||||
u32 dhash = dcid_;
|
||||
dhash ^= (u32)(uintptr_t)verts;
|
||||
dhash = __rotl(dhash, 13);
|
||||
dhash ^= (u32)(uintptr_t)inds;
|
||||
dhash = __rotl(dhash, 13);
|
||||
dhash ^= (u32)vertType;
|
||||
dhash = __rotl(dhash, 13);
|
||||
dhash ^= (u32)vertexCount;
|
||||
dhash = __rotl(dhash, 13);
|
||||
dhash ^= (u32)prim;
|
||||
dcid_ = dhash;
|
||||
|
||||
if (inds) {
|
||||
GetIndexBounds(inds, vertexCount, vertType, &dc.indexLowerBound, &dc.indexUpperBound);
|
||||
} else {
|
||||
dc.indexLowerBound = 0;
|
||||
dc.indexUpperBound = vertexCount - 1;
|
||||
}
|
||||
|
||||
numDrawCalls++;
|
||||
vertexCountInDrawCalls += vertexCount;
|
||||
|
||||
if (g_Config.bSoftwareSkinning && (vertType & GE_VTYPE_WEIGHT_MASK)) {
|
||||
DecodeVertsStep();
|
||||
decodeCounter_++;
|
||||
}
|
||||
|
||||
if (prim == GE_PRIM_RECTANGLES && (gstate.getTextureAddress(0) & 0x3FFFFFFF) == (gstate.getFrameBufAddress() & 0x3FFFFFFF)) {
|
||||
// Rendertarget == texture?
|
||||
if (!g_Config.bDisableSlowFramebufEffects) {
|
||||
gstate_c.textureChanged |= TEXCHANGE_PARAMSONLY;
|
||||
Flush(cmd_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::DecodeVerts() {
|
||||
for (; decodeCounter_ < numDrawCalls; decodeCounter_++) {
|
||||
DecodeVertsStep();
|
||||
}
|
||||
// Sanity check
|
||||
if (indexGen.Prim() < 0) {
|
||||
ERROR_LOG_REPORT(G3D, "DecodeVerts: Failed to deduce prim: %i", indexGen.Prim());
|
||||
// Force to points (0)
|
||||
indexGen.AddPrim(GE_PRIM_POINTS, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::DecodeVertsStep() {
|
||||
const int i = decodeCounter_;
|
||||
|
||||
const DeferredDrawCall &dc = drawCalls[i];
|
||||
|
||||
indexGen.SetIndex(decodedVerts_);
|
||||
int indexLowerBound = dc.indexLowerBound, indexUpperBound = dc.indexUpperBound;
|
||||
|
||||
u32 indexType = dc.indexType;
|
||||
void *inds = dc.inds;
|
||||
if (indexType == GE_VTYPE_IDX_NONE >> GE_VTYPE_IDX_SHIFT) {
|
||||
// Decode the verts and apply morphing. Simple.
|
||||
dec_->DecodeVerts(decoded + decodedVerts_ * (int)dec_->GetDecVtxFmt().stride,
|
||||
dc.verts, indexLowerBound, indexUpperBound);
|
||||
decodedVerts_ += indexUpperBound - indexLowerBound + 1;
|
||||
indexGen.AddPrim(dc.prim, dc.vertexCount);
|
||||
} else {
|
||||
// It's fairly common that games issue long sequences of PRIM calls, with differing
|
||||
// inds pointer but the same base vertex pointer. We'd like to reuse vertices between
|
||||
// these as much as possible, so we make sure here to combine as many as possible
|
||||
// into one nice big drawcall, sharing data.
|
||||
|
||||
// 1. Look ahead to find the max index, only looking as "matching" drawcalls.
|
||||
// Expand the lower and upper bounds as we go.
|
||||
int lastMatch = i;
|
||||
const int total = numDrawCalls;
|
||||
for (int j = i + 1; j < total; ++j) {
|
||||
if (drawCalls[j].verts != dc.verts)
|
||||
break;
|
||||
|
||||
indexLowerBound = std::min(indexLowerBound, (int)drawCalls[j].indexLowerBound);
|
||||
indexUpperBound = std::max(indexUpperBound, (int)drawCalls[j].indexUpperBound);
|
||||
lastMatch = j;
|
||||
}
|
||||
|
||||
// 2. Loop through the drawcalls, translating indices as we go.
|
||||
switch (indexType) {
|
||||
case GE_VTYPE_IDX_8BIT >> GE_VTYPE_IDX_SHIFT:
|
||||
for (int j = i; j <= lastMatch; j++) {
|
||||
indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u8 *)drawCalls[j].inds, indexLowerBound);
|
||||
}
|
||||
break;
|
||||
case GE_VTYPE_IDX_16BIT >> GE_VTYPE_IDX_SHIFT:
|
||||
for (int j = i; j <= lastMatch; j++) {
|
||||
indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u16 *)drawCalls[j].inds, indexLowerBound);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
const int vertexCount = indexUpperBound - indexLowerBound + 1;
|
||||
|
||||
// This check is a workaround for Pangya Fantasy Golf, which sends bogus index data when switching items in "My Room" sometimes.
|
||||
if (decodedVerts_ + vertexCount > VERTEX_BUFFER_MAX) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Decode that range of vertex data.
|
||||
dec_->DecodeVerts(decoded + decodedVerts_ * (int)dec_->GetDecVtxFmt().stride,
|
||||
dc.verts, indexLowerBound, indexUpperBound);
|
||||
decodedVerts_ += vertexCount;
|
||||
|
||||
// 4. Advance indexgen vertex counter.
|
||||
indexGen.Advance(vertexCount);
|
||||
decodeCounter_ = lastMatch;
|
||||
}
|
||||
}
|
||||
|
||||
inline u32 ComputeMiniHashRange(const void *ptr, size_t sz) {
|
||||
// Switch to u32 units.
|
||||
const u32 *p = (const u32 *)ptr;
|
||||
sz >>= 2;
|
||||
|
||||
if (sz > 100) {
|
||||
size_t step = sz / 4;
|
||||
u32 hash = 0;
|
||||
for (size_t i = 0; i < sz; i += step) {
|
||||
hash += DoReliableHash32(p + i, 100, 0x3A44B9C4);
|
||||
}
|
||||
return hash;
|
||||
} else {
|
||||
return p[0] + p[sz - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// The inline wrapper in the header checks for numDrawCalls == 0
|
||||
void DrawEngineVulkan::DoFlush(VkCommandBuffer cmd) {
|
||||
gpuStats.numFlushes++;
|
||||
|
||||
// This is not done on every drawcall, we should collect vertex data
|
||||
// until critical state changes. That's when we draw (flush).
|
||||
|
||||
GEPrimitiveType prim = prevPrim_;
|
||||
// ApplyDrawState(prim);
|
||||
|
||||
VulkanVertexShader *vshader;
|
||||
VulkanFragmentShader *fshader;
|
||||
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader);
|
||||
|
||||
if (vshader->UseHWTransform()) {
|
||||
int vertexCount = 0;
|
||||
int maxIndex = 0;
|
||||
bool useElements = true;
|
||||
|
||||
DecodeVerts();
|
||||
gpuStats.numUncachedVertsDrawn += indexGen.VertexCount();
|
||||
useElements = !indexGen.SeenOnlyPurePrims();
|
||||
vertexCount = indexGen.VertexCount();
|
||||
maxIndex = indexGen.MaxIndex();
|
||||
if (!useElements && indexGen.PureCount()) {
|
||||
vertexCount = indexGen.PureCount();
|
||||
}
|
||||
prim = indexGen.Prim();
|
||||
|
||||
VERBOSE_LOG(G3D, "Flush prim %i! %i verts in one go", prim, vertexCount);
|
||||
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
|
||||
if (gstate.isModeThrough()) {
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
|
||||
} else {
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
|
||||
}
|
||||
|
||||
VkBuffer buf[1] = {};
|
||||
VkDeviceSize offsets[1] = { 0 };
|
||||
if (useElements) {
|
||||
// TODO: Avoid rebinding if the vertex size stays the same by using the offset arguments
|
||||
vkCmdBindVertexBuffers(cmd_, 0, 1, buf, offsets);
|
||||
vkCmdBindIndexBuffer(cmd_, buf[0], 0, VK_INDEX_TYPE_UINT16);
|
||||
vkCmdDrawIndexed(cmd_, maxIndex + 1, 1, 0, 0, 0);
|
||||
} else {
|
||||
vkCmdBindVertexBuffers(cmd_, 0, 1, buf, offsets);
|
||||
vkCmdDraw(cmd_, vertexCount, 1, 0, 0);
|
||||
}
|
||||
} else {
|
||||
DecodeVerts();
|
||||
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
|
||||
if (gstate.isModeThrough()) {
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
|
||||
} else {
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
|
||||
}
|
||||
|
||||
gpuStats.numUncachedVertsDrawn += indexGen.VertexCount();
|
||||
prim = indexGen.Prim();
|
||||
// Undo the strip optimization, not supported by the SW code yet.
|
||||
if (prim == GE_PRIM_TRIANGLE_STRIP)
|
||||
prim = GE_PRIM_TRIANGLES;
|
||||
VERBOSE_LOG(G3D, "Flush prim %i SW! %i verts in one go", prim, indexGen.VertexCount());
|
||||
|
||||
int numTrans = 0;
|
||||
bool drawIndexed = false;
|
||||
u16 *inds = decIndex;
|
||||
TransformedVertex *drawBuffer = NULL;
|
||||
SoftwareTransformResult result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
|
||||
int maxIndex = indexGen.MaxIndex();
|
||||
SoftwareTransform(
|
||||
prim, decoded, indexGen.VertexCount(),
|
||||
dec_->VertexType(), inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(),
|
||||
maxIndex, framebufferManager_, textureCache_, transformed, transformedExpanded, drawBuffer, numTrans, drawIndexed, &result, 1.0f);
|
||||
|
||||
// ApplyDrawStateLate();
|
||||
|
||||
if (result.action == SW_DRAW_PRIMITIVES) {
|
||||
if (result.setStencil) {
|
||||
// dxstate.stencilFunc.set(D3DCMP_ALWAYS, result.stencilValue, 255);
|
||||
}
|
||||
|
||||
VkBuffer buf[1] = {};
|
||||
VkDeviceSize offsets[1] = { 0 };
|
||||
if (drawIndexed) {
|
||||
// TODO: Have a buffer per frame, use a walking buffer pointer
|
||||
// TODO: Avoid rebinding if the vertex size stays the same by using the offset arguments
|
||||
vkCmdBindVertexBuffers(cmd_, 0, 1, buf, offsets);
|
||||
vkCmdBindIndexBuffer(cmd_, buf[0], 0, VK_INDEX_TYPE_UINT16);
|
||||
vkCmdDrawIndexed(cmd_, numTrans, 1, 0, 0, 0);
|
||||
// pD3Ddevice->DrawIndexedPrimitiveUP(glprim[prim], 0, maxIndex, D3DPrimCount(glprim[prim], numTrans), inds, D3DFMT_INDEX16, drawBuffer, sizeof(TransformedVertex));
|
||||
} else {
|
||||
// TODO: Avoid rebinding if the vertex size stays the same by using the offset arguments
|
||||
vkCmdBindVertexBuffers(cmd_, 0, 1, buf, offsets);
|
||||
vkCmdDraw(cmd_, numTrans, 1, 0, 0);
|
||||
// pD3Ddevice->DrawPrimitiveUP(glprim[prim], D3DPrimCount(glprim[prim], numTrans), drawBuffer, sizeof(TransformedVertex));
|
||||
}
|
||||
} else if (result.action == SW_CLEAR) {
|
||||
// TODO: Support clearing only color and not alpha, or vice versa. This is not supported (probably for good reason) by vkCmdClearColorAttachment
|
||||
// so we will have to simply draw a rectangle instead. Accordingly,
|
||||
|
||||
int mask = gstate.isClearModeColorMask() ? 1 : 0;
|
||||
if (gstate.isClearModeAlphaMask()) mask |= 2;
|
||||
if (gstate.isClearModeDepthMask()) mask |= 4;
|
||||
|
||||
VkClearValue value;
|
||||
value.color.float32[0] = (result.color & 0xFF) * (1.0f / 255.0f);
|
||||
value.color.float32[1] = ((result.color >> 8) & 0xFF) * (1.0f / 255.0f);
|
||||
value.color.float32[2] = ((result.color >> 16) & 0xFF) * (1.0f / 255.0f);
|
||||
value.color.float32[3] = ((result.color >> 24) & 0xFF) * (1.0f / 255.0f);
|
||||
value.depthStencil.depth = result.depth;
|
||||
value.depthStencil.stencil = (result.color >> 24) & 0xFF;
|
||||
|
||||
VkClearRect rect;
|
||||
rect.baseArrayLayer = 0;
|
||||
rect.layerCount = 1;
|
||||
rect.rect.offset.x = 0;
|
||||
rect.rect.offset.y = 0;
|
||||
rect.rect.extent.width = gstate_c.curRTRenderWidth;
|
||||
rect.rect.extent.height = gstate_c.curRTRenderHeight;
|
||||
|
||||
int count = 0;
|
||||
VkClearAttachment attach[2];
|
||||
if (mask & 3) {
|
||||
attach[count].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
attach[count].clearValue = value;
|
||||
attach[count].colorAttachment = 0;
|
||||
count++;
|
||||
}
|
||||
if (mask & 4) {
|
||||
attach[count].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
attach[count].clearValue = value;
|
||||
attach[count].colorAttachment = 0;
|
||||
}
|
||||
vkCmdClearAttachments(cmd_, count, attach, 1, &rect);
|
||||
|
||||
if (mask & 1) {
|
||||
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
|
||||
}
|
||||
if (mask & 4) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gpuStats.numDrawCalls += numDrawCalls;
|
||||
gpuStats.numVertsSubmitted += vertexCountInDrawCalls;
|
||||
|
||||
indexGen.Reset();
|
||||
decodedVerts_ = 0;
|
||||
numDrawCalls = 0;
|
||||
vertexCountInDrawCalls = 0;
|
||||
decodeCounter_ = 0;
|
||||
dcid_ = 0;
|
||||
prevPrim_ = GE_PRIM_INVALID;
|
||||
gstate_c.vertexFullAlpha = true;
|
||||
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
|
||||
|
||||
// Now seems as good a time as any to reset the min/max coords, which we may examine later.
|
||||
gstate_c.vertBounds.minU = 512;
|
||||
gstate_c.vertBounds.minV = 512;
|
||||
gstate_c.vertBounds.maxU = 0;
|
||||
gstate_c.vertBounds.maxV = 0;
|
||||
|
||||
host->GPUNotifyDraw();
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::Resized() {
|
||||
decJitCache_->Clear();
|
||||
lastVType_ = -1;
|
||||
dec_ = NULL;
|
||||
for (auto iter = decoderMap_.begin(); iter != decoderMap_.end(); iter++) {
|
||||
delete iter->second;
|
||||
}
|
||||
decoderMap_.clear();
|
||||
}
|
||||
|
||||
bool DrawEngineVulkan::IsCodePtrVertexDecoder(const u8 *ptr) const {
|
||||
return decJitCache_->IsInSpace(ptr);
|
||||
}
|
194
GPU/Vulkan/DrawEngineVulkan.h
Normal file
194
GPU/Vulkan/DrawEngineVulkan.h
Normal file
@ -0,0 +1,194 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GPU/Common/DrawEngineCommon.h"
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/Common/GPUDebugInterface.h"
|
||||
#include "GPU/Common/IndexGenerator.h"
|
||||
#include "GPU/Common/VertexDecoderCommon.h"
|
||||
#include "GPU/Common/DrawEngineCommon.h"
|
||||
#include "GPU/Common/GPUStateUtils.h"
|
||||
|
||||
struct DecVtxFormat;
|
||||
struct UVScale;
|
||||
|
||||
class ShaderManagerVulkan;
|
||||
class PipelineManagerVulkan;
|
||||
class TextureCacheVulkan;
|
||||
class FramebufferManagerVulkan;
|
||||
|
||||
// Avoiding the full include of TextureDecoder.h.
|
||||
#if (defined(_M_SSE) && defined(_M_X64)) || defined(ARM64)
|
||||
typedef u64 ReliableHashType;
|
||||
#else
|
||||
typedef u32 ReliableHashType;
|
||||
#endif
|
||||
|
||||
// Handles transform, lighting and drawing.
|
||||
class DrawEngineVulkan : public DrawEngineCommon {
|
||||
public:
|
||||
DrawEngineVulkan();
|
||||
virtual ~DrawEngineVulkan();
|
||||
|
||||
void SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead);
|
||||
|
||||
void SetShaderManager(ShaderManagerVulkan *shaderManager) {
|
||||
shaderManager_ = shaderManager;
|
||||
}
|
||||
void SetPipelineManager(PipelineManagerVulkan *pipelineManager) {
|
||||
pipelineManager_ = pipelineManager;
|
||||
}
|
||||
void SetTextureCache(TextureCacheVulkan *textureCache) {
|
||||
textureCache_ = textureCache;
|
||||
}
|
||||
void SetFramebufferManager(FramebufferManagerVulkan *fbManager) {
|
||||
framebufferManager_ = fbManager;
|
||||
}
|
||||
|
||||
void Resized(); // TODO: Call
|
||||
|
||||
void SetupVertexDecoder(u32 vertType);
|
||||
void SetupVertexDecoderInternal(u32 vertType);
|
||||
|
||||
// This requires a SetupVertexDecoder call first.
|
||||
int EstimatePerVertexCost() {
|
||||
// TODO: This is transform cost, also account for rasterization cost somehow... although it probably
|
||||
// runs in parallel with transform.
|
||||
|
||||
// Also, this is all pure guesswork. If we can find a way to do measurements, that would be great.
|
||||
|
||||
// GTA wants a low value to run smooth, GoW wants a high value (otherwise it thinks things
|
||||
// went too fast and starts doing all the work over again).
|
||||
|
||||
int cost = 20;
|
||||
if (gstate.isLightingEnabled()) {
|
||||
cost += 10;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (gstate.isLightChanEnabled(i))
|
||||
cost += 10;
|
||||
}
|
||||
}
|
||||
|
||||
if (gstate.getUVGenMode() != GE_TEXMAP_TEXTURE_COORDS) {
|
||||
cost += 20;
|
||||
}
|
||||
if (dec_ && dec_->morphcount > 1) {
|
||||
cost += 5 * dec_->morphcount;
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
// So that this can be inlined
|
||||
void Flush(VkCommandBuffer cmd) {
|
||||
if (!numDrawCalls)
|
||||
return;
|
||||
DoFlush(cmd);
|
||||
}
|
||||
|
||||
void FinishDeferred() {
|
||||
if (!numDrawCalls)
|
||||
return;
|
||||
DecodeVerts();
|
||||
}
|
||||
|
||||
bool IsCodePtrVertexDecoder(const u8 *ptr) const;
|
||||
|
||||
void DispatchFlush() override { Flush(cmd_); }
|
||||
void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) override {
|
||||
SubmitPrim(verts, inds, prim, vertexCount, vertType, bytesRead);
|
||||
}
|
||||
|
||||
void SetCmdBuffer(VkCommandBuffer cmd) {
|
||||
cmd_ = cmd;
|
||||
}
|
||||
|
||||
private:
|
||||
void DecodeVerts();
|
||||
void DecodeVertsStep();
|
||||
void DoFlush(VkCommandBuffer cmd);
|
||||
|
||||
VertexDecoder *GetVertexDecoder(u32 vtype);
|
||||
|
||||
// Defer all vertex decoding to a "Flush" (except when software skinning)
|
||||
struct DeferredDrawCall {
|
||||
void *verts;
|
||||
void *inds;
|
||||
u32 vertType;
|
||||
u8 indexType;
|
||||
s8 prim;
|
||||
u32 vertexCount;
|
||||
u16 indexLowerBound;
|
||||
u16 indexUpperBound;
|
||||
};
|
||||
|
||||
VkCommandBuffer cmd_;
|
||||
|
||||
// Vertex collector state
|
||||
IndexGenerator indexGen;
|
||||
int decodedVerts_;
|
||||
GEPrimitiveType prevPrim_;
|
||||
|
||||
u32 lastVType_;
|
||||
|
||||
TransformedVertex *transformed;
|
||||
TransformedVertex *transformedExpanded;
|
||||
|
||||
// Other
|
||||
ShaderManagerVulkan *shaderManager_;
|
||||
PipelineManagerVulkan *pipelineManager_;
|
||||
TextureCacheVulkan *textureCache_;
|
||||
FramebufferManagerVulkan *framebufferManager_;
|
||||
|
||||
enum { MAX_DEFERRED_DRAW_CALLS = 128 };
|
||||
|
||||
DeferredDrawCall drawCalls[MAX_DEFERRED_DRAW_CALLS];
|
||||
int numDrawCalls;
|
||||
int vertexCountInDrawCalls;
|
||||
|
||||
int decodeCounter_;
|
||||
u32 dcid_;
|
||||
|
||||
bool fboTexNeedBind_;
|
||||
bool fboTexBound_;
|
||||
};
|
543
GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp
Normal file
543
GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp
Normal file
@ -0,0 +1,543 @@
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#if !defined(USING_GLES2)
|
||||
// SDL 1.2 on Apple does not have support for OpenGL 3 and hence needs
|
||||
// special treatment in the shader generator.
|
||||
#if defined(__APPLE__)
|
||||
#define FORCE_OPENGL_2_0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
|
||||
#include "Common/StringUtils.h"
|
||||
#include "base/logging.h"
|
||||
#include "gfx_es2/gpu_features.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/Config.h"
|
||||
#include "GPU/Common/GPUStateUtils.h"
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
#include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h"
|
||||
#include "GPU/Vulkan/FramebufferVulkan.h"
|
||||
#include "GPU/Vulkan/PipelineManagerVulkan.h"
|
||||
|
||||
#include "GPU/ge_constants.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
#define WRITE p+=sprintf
|
||||
|
||||
// #define DEBUG_SHADER
|
||||
|
||||
// Missing: Z depth range
|
||||
bool GenerateVulkanGLSLFragmentShader(const ShaderID &id, char *buffer) {
|
||||
char *p = buffer;
|
||||
|
||||
const char *lastFragData = nullptr;
|
||||
|
||||
WRITE(p, "#version 140\n"); // GLSL ES
|
||||
WRITE(p, "#extension GL_ARB_separate_shader_objects : enable\n");
|
||||
WRITE(p, "#extension GL_ARB_shading_language_420pack : enable\n");
|
||||
|
||||
// PowerVR needs highp to do the fog in MHU correctly.
|
||||
// Others don't.
|
||||
bool highpFog = (gl_extensions.bugs & BUG_PVR_SHADER_PRECISION_BAD) ? true : false;
|
||||
bool highpTexcoord = highpFog;
|
||||
|
||||
WRITE(p, "precision lowp float;\n");
|
||||
|
||||
bool lmode = id.Bit(FS_BIT_LMODE);
|
||||
bool doTexture = id.Bit(FS_BIT_DO_TEXTURE);
|
||||
bool enableFog = id.Bit(FS_BIT_ENABLE_FOG);
|
||||
bool enableAlphaTest = id.Bit(FS_BIT_ALPHA_TEST);
|
||||
|
||||
bool alphaTestAgainstZero = id.Bit(FS_BIT_ALPHA_AGAINST_ZERO);
|
||||
bool enableColorTest = id.Bit(FS_BIT_COLOR_TEST);
|
||||
bool colorTestAgainstZero = id.Bit(FS_BIT_COLOR_AGAINST_ZERO);
|
||||
bool enableColorDoubling = id.Bit(FS_BIT_COLOR_DOUBLE);
|
||||
bool doTextureProjection = id.Bit(FS_BIT_DO_TEXTURE_PROJ);
|
||||
bool doTextureAlpha = id.Bit(FS_BIT_TEXALPHA);
|
||||
bool doFlatShading = id.Bit(FS_BIT_FLATSHADE);
|
||||
|
||||
GEComparison alphaTestFunc = (GEComparison)id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3);
|
||||
GEComparison colorTestFunc = (GEComparison)id.Bits(FS_BIT_COLOR_TEST_FUNC, 2);
|
||||
bool needShaderTexClamp = id.Bit(FS_BIT_SHADER_TEX_CLAMP);
|
||||
|
||||
GETexFunc texFunc = (GETexFunc)id.Bits(FS_BIT_TEXFUNC, 3);
|
||||
bool textureAtOffset = id.Bit(FS_BIT_TEXTURE_AT_OFFSET);
|
||||
|
||||
ReplaceBlendType replaceBlend = static_cast<ReplaceBlendType>(id.Bits(FS_BIT_REPLACE_BLEND, 3));
|
||||
ReplaceAlphaType stencilToAlpha = static_cast<ReplaceAlphaType>(id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2));
|
||||
|
||||
GEBlendSrcFactor replaceBlendFuncA = (GEBlendSrcFactor)id.Bits(FS_BIT_BLENDFUNC_A, 4);
|
||||
GEBlendDstFactor replaceBlendFuncB = (GEBlendDstFactor)id.Bits(FS_BIT_BLENDFUNC_B, 4);
|
||||
GEBlendMode replaceBlendEq = (GEBlendMode)id.Bits(FS_BIT_BLENDEQ, 3);
|
||||
|
||||
bool isModeClear = id.Bit(FS_BIT_CLEARMODE);
|
||||
|
||||
const char *shading = doFlatShading ? "flat" : "";
|
||||
|
||||
if (doTexture) {
|
||||
WRITE(p, "layout (binding = 1) uniform sampler2D tex;\n");
|
||||
}
|
||||
|
||||
if (!isModeClear && replaceBlend > REPLACE_BLEND_STANDARD) {
|
||||
if (replaceBlend == REPLACE_BLEND_COPY_FBO) {
|
||||
WRITE(p, "layout (binding = 2) uniform sampler2D fbotex;\n");
|
||||
}
|
||||
if (replaceBlendFuncA == GE_SRCBLEND_FIXA) {
|
||||
WRITE(p, "uniform vec3 u_blendFixA;\n");
|
||||
}
|
||||
if (replaceBlendFuncB == GE_DSTBLEND_FIXB) {
|
||||
WRITE(p, "uniform vec3 u_blendFixB;\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (needShaderTexClamp && doTexture) {
|
||||
WRITE(p, "uniform vec4 u_texclamp;\n");
|
||||
if (id.Bit(FS_BIT_TEXTURE_AT_OFFSET)) {
|
||||
WRITE(p, "uniform vec2 u_texclampoff;\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (enableAlphaTest || enableColorTest) {
|
||||
WRITE(p, "uniform vec4 u_alphacolorref;\n");
|
||||
if (((enableColorTest && !colorTestAgainstZero) || (enableAlphaTest && !alphaTestAgainstZero))) {
|
||||
WRITE(p, "uniform ivec4 u_alphacolormask;\n");
|
||||
}
|
||||
}
|
||||
|
||||
StencilValueType replaceAlphaWithStencilType = (StencilValueType)id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4);
|
||||
if (stencilToAlpha && replaceAlphaWithStencilType == STENCIL_VALUE_UNIFORM) {
|
||||
WRITE(p, "uniform float u_stencilReplaceValue;\n");
|
||||
}
|
||||
if (doTexture && texFunc == GE_TEXFUNC_BLEND)
|
||||
WRITE(p, "uniform vec3 u_texenv;\n");
|
||||
|
||||
if (enableFog) {
|
||||
WRITE(p, "uniform vec3 u_fogcolor;\n");
|
||||
}
|
||||
|
||||
WRITE(p, "layout (location = 1) %s in vec4 v_color0;\n", shading);
|
||||
if (lmode)
|
||||
WRITE(p, "layout (location = 2) %s in vec3 v_color1;\n", shading);
|
||||
if (enableFog) {
|
||||
WRITE(p, "layout (location = 3) %s float v_fogdepth;\n", highpFog ? "highp" : "mediump");
|
||||
}
|
||||
if (doTexture) {
|
||||
if (doTextureProjection)
|
||||
WRITE(p, "layout (location = 0) %s vec3 v_texcoord;\n", highpTexcoord ? "highp" : "mediump");
|
||||
else
|
||||
WRITE(p, "layout (location = 0) %s vec2 v_texcoord;\n", highpTexcoord ? "highp" : "mediump");
|
||||
}
|
||||
|
||||
if (!g_Config.bFragmentTestCache) {
|
||||
if (enableAlphaTest && !alphaTestAgainstZero) {
|
||||
WRITE(p, "int roundAndScaleTo255i(in float x) { return int(floor(x * 255.0 + 0.5)); }\n");
|
||||
}
|
||||
if (enableColorTest && !colorTestAgainstZero) {
|
||||
WRITE(p, "ivec3 roundAndScaleTo255iv(in vec3 x) { return ivec3(floor(x * 255.0 + 0.5)); }\n");
|
||||
}
|
||||
}
|
||||
|
||||
WRITE(p, "layout (location = 0) out vec4 fragColor0;\n");
|
||||
if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE) {
|
||||
WRITE(p, "layout (location = 1) out vec4 fragColor1;\n");
|
||||
}
|
||||
|
||||
// PowerVR needs a custom modulo function. For some reason, this has far higher precision than the builtin one.
|
||||
if ((gl_extensions.bugs & BUG_PVR_SHADER_PRECISION_BAD) && needShaderTexClamp) {
|
||||
WRITE(p, "float mymod(float a, float b) { return a - b * floor(a / b); }\n");
|
||||
}
|
||||
|
||||
WRITE(p, "void main() {\n");
|
||||
|
||||
if (isModeClear) {
|
||||
// Clear mode does not allow any fancy shading.
|
||||
WRITE(p, " vec4 v = v_color0;\n");
|
||||
} else {
|
||||
const char *secondary = "";
|
||||
// Secondary color for specular on top of texture
|
||||
if (lmode) {
|
||||
WRITE(p, " vec4 s = vec4(v_color1, 0.0);\n");
|
||||
secondary = " + s";
|
||||
} else {
|
||||
secondary = "";
|
||||
}
|
||||
|
||||
if (doTexture) {
|
||||
const char *texcoord = "v_texcoord";
|
||||
// TODO: Not sure the right way to do this for projection.
|
||||
// This path destroys resolution on older PowerVR no matter what I do, so we disable it on SGX 540 and lesser, and live with the consequences.
|
||||
if (needShaderTexClamp && !(gl_extensions.bugs & BUG_PVR_SHADER_PRECISION_TERRIBLE)) {
|
||||
// We may be clamping inside a larger surface (tex = 64x64, buffer=480x272).
|
||||
// We may also be wrapping in such a surface, or either one in a too-small surface.
|
||||
// Obviously, clamping to a smaller surface won't work. But better to clamp to something.
|
||||
std::string ucoord = "v_texcoord.x";
|
||||
std::string vcoord = "v_texcoord.y";
|
||||
if (doTextureProjection) {
|
||||
ucoord = "(v_texcoord.x / v_texcoord.z)";
|
||||
vcoord = "(v_texcoord.y / v_texcoord.z)";
|
||||
}
|
||||
|
||||
std::string modulo = (gl_extensions.bugs & BUG_PVR_SHADER_PRECISION_BAD) ? "mymod" : "mod";
|
||||
|
||||
if (id.Bit(FS_BIT_CLAMP_S)) {
|
||||
ucoord = "clamp(" + ucoord + ", u_texclamp.z, u_texclamp.x - u_texclamp.z)";
|
||||
} else {
|
||||
ucoord = modulo + "(" + ucoord + ", u_texclamp.x)";
|
||||
}
|
||||
if (id.Bit(FS_BIT_CLAMP_T)) {
|
||||
vcoord = "clamp(" + vcoord + ", u_texclamp.w, u_texclamp.y - u_texclamp.w)";
|
||||
} else {
|
||||
vcoord = modulo + "(" + vcoord + ", u_texclamp.y)";
|
||||
}
|
||||
if (textureAtOffset) {
|
||||
ucoord = "(" + ucoord + " + u_texclampoff.x)";
|
||||
vcoord = "(" + vcoord + " + u_texclampoff.y)";
|
||||
}
|
||||
|
||||
WRITE(p, " vec2 fixedcoord = vec2(%s, %s);\n", ucoord.c_str(), vcoord.c_str());
|
||||
texcoord = "fixedcoord";
|
||||
// We already projected it.
|
||||
doTextureProjection = false;
|
||||
}
|
||||
|
||||
if (doTextureProjection) {
|
||||
WRITE(p, " vec4 t = textureProj(tex, %s);\n", texcoord);
|
||||
} else {
|
||||
WRITE(p, " vec4 t = texture(tex, %s);\n", texcoord);
|
||||
}
|
||||
WRITE(p, " vec4 p = v_color0;\n");
|
||||
|
||||
if (doTextureAlpha) { // texfmt == RGBA
|
||||
switch (texFunc) {
|
||||
case GE_TEXFUNC_MODULATE:
|
||||
WRITE(p, " vec4 v = p * t%s;\n", secondary);
|
||||
break;
|
||||
|
||||
case GE_TEXFUNC_DECAL:
|
||||
WRITE(p, " vec4 v = vec4(mix(p.rgb, t.rgb, t.a), p.a)%s;\n", secondary);
|
||||
break;
|
||||
|
||||
case GE_TEXFUNC_BLEND:
|
||||
WRITE(p, " vec4 v = vec4(mix(p.rgb, u_texenv.rgb, t.rgb), p.a * t.a)%s;\n", secondary);
|
||||
break;
|
||||
|
||||
case GE_TEXFUNC_REPLACE:
|
||||
WRITE(p, " vec4 v = t%s;\n", secondary);
|
||||
break;
|
||||
|
||||
case GE_TEXFUNC_ADD:
|
||||
case GE_TEXFUNC_UNKNOWN1:
|
||||
case GE_TEXFUNC_UNKNOWN2:
|
||||
case GE_TEXFUNC_UNKNOWN3:
|
||||
WRITE(p, " vec4 v = vec4(p.rgb + t.rgb, p.a * t.a)%s;\n", secondary);
|
||||
break;
|
||||
default:
|
||||
WRITE(p, " vec4 v = p;\n"); break;
|
||||
}
|
||||
} else { // texfmt == RGB
|
||||
switch (texFunc) {
|
||||
case GE_TEXFUNC_MODULATE:
|
||||
WRITE(p, " vec4 v = vec4(t.rgb * p.rgb, p.a)%s;\n", secondary);
|
||||
break;
|
||||
|
||||
case GE_TEXFUNC_DECAL:
|
||||
WRITE(p, " vec4 v = vec4(t.rgb, p.a)%s;\n", secondary);
|
||||
break;
|
||||
|
||||
case GE_TEXFUNC_BLEND:
|
||||
WRITE(p, " vec4 v = vec4(mix(p.rgb, u_texenv.rgb, t.rgb), p.a)%s;\n", secondary);
|
||||
break;
|
||||
|
||||
case GE_TEXFUNC_REPLACE:
|
||||
WRITE(p, " vec4 v = vec4(t.rgb, p.a)%s;\n", secondary);
|
||||
break;
|
||||
|
||||
case GE_TEXFUNC_ADD:
|
||||
case GE_TEXFUNC_UNKNOWN1:
|
||||
case GE_TEXFUNC_UNKNOWN2:
|
||||
case GE_TEXFUNC_UNKNOWN3:
|
||||
WRITE(p, " vec4 v = vec4(p.rgb + t.rgb, p.a)%s;\n", secondary); break;
|
||||
default:
|
||||
WRITE(p, " vec4 v = p;\n"); break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No texture mapping
|
||||
WRITE(p, " vec4 v = v_color0 %s;\n", secondary);
|
||||
}
|
||||
|
||||
// Texture access is at half texels [0.5/256, 255.5/256], but colors are normalized [0, 255].
|
||||
// So we have to scale to account for the difference.
|
||||
std::string alphaTestXCoord = "0";
|
||||
if (g_Config.bFragmentTestCache) {
|
||||
if (enableColorTest && !colorTestAgainstZero) {
|
||||
WRITE(p, " vec4 vScale256 = v * %f + %f;\n", 255.0 / 256.0, 0.5 / 256.0);
|
||||
alphaTestXCoord = "vScale256.a";
|
||||
} else if (enableAlphaTest && !alphaTestAgainstZero) {
|
||||
char temp[64];
|
||||
snprintf(temp, sizeof(temp), "v.a * %f + %f", 255.0 / 256.0, 0.5 / 256.0);
|
||||
alphaTestXCoord = temp;
|
||||
}
|
||||
}
|
||||
|
||||
if (enableAlphaTest) {
|
||||
if (alphaTestAgainstZero) {
|
||||
// When testing against 0 (extremely common), we can avoid some math.
|
||||
// 0.002 is approximately half of 1.0 / 255.0.
|
||||
if (alphaTestFunc == GE_COMP_NOTEQUAL || alphaTestFunc == GE_COMP_GREATER) {
|
||||
WRITE(p, " if (v.a < 0.002) discard;\n");
|
||||
} else if (alphaTestFunc != GE_COMP_NEVER) {
|
||||
// Anything else is a test for == 0. Happens sometimes, actually...
|
||||
WRITE(p, " if (v.a > 0.002) discard;\n");
|
||||
} else {
|
||||
// NEVER has been logged as used by games, although it makes little sense - statically failing.
|
||||
// Maybe we could discard the drawcall, but it's pretty rare. Let's just statically discard here.
|
||||
WRITE(p, " discard;\n");
|
||||
}
|
||||
} else if (g_Config.bFragmentTestCache) {
|
||||
WRITE(p, " float aResult = texture(testtex, vec2(%s, 0)).a;\n", alphaTestXCoord.c_str());
|
||||
WRITE(p, " if (aResult < 0.5) discard;\n");
|
||||
} else {
|
||||
const char *alphaTestFuncs[] = { "#", "#", " != ", " == ", " >= ", " > ", " <= ", " < " };
|
||||
if (alphaTestFuncs[alphaTestFunc][0] != '#') {
|
||||
WRITE(p, " if ((roundAndScaleTo255i(v.a) & u_alphacolormask.a) %s int(u_alphacolorref.a)) discard;\n", alphaTestFuncs[alphaTestFunc]);
|
||||
} else {
|
||||
// This means NEVER. See above.
|
||||
WRITE(p, " discard;\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enableColorTest) {
|
||||
if (colorTestAgainstZero) {
|
||||
// When testing against 0 (common), we can avoid some math.
|
||||
// 0.002 is approximately half of 1.0 / 255.0.
|
||||
if (colorTestFunc == GE_COMP_NOTEQUAL) {
|
||||
WRITE(p, " if (v.r < 0.002 && v.g < 0.002 && v.b < 0.002) discard;\n");
|
||||
} else if (colorTestFunc != GE_COMP_NEVER) {
|
||||
// Anything else is a test for == 0.
|
||||
WRITE(p, " if (v.r > 0.002 || v.g > 0.002 || v.b > 0.002) discard;\n");
|
||||
} else {
|
||||
// NEVER has been logged as used by games, although it makes little sense - statically failing.
|
||||
// Maybe we could discard the drawcall, but it's pretty rare. Let's just statically discard here.
|
||||
WRITE(p, " discard;\n");
|
||||
}
|
||||
} else if (g_Config.bFragmentTestCache) {
|
||||
// texelFetch may make more sense, actually, and we should process colors as integers.
|
||||
WRITE(p, " float rResult = texture(testtex, vec2(vScale256.r, 0)).r;\n");
|
||||
WRITE(p, " float gResult = texture(testtex, vec2(vScale256.g, 0)).g;\n");
|
||||
WRITE(p, " float bResult = texture(testtex, vec2(vScale256.b, 0)).b;\n");
|
||||
if (colorTestFunc == GE_COMP_EQUAL) {
|
||||
// Equal means all parts must be equal.
|
||||
WRITE(p, " if (rResult < 0.5 || gResult < 0.5 || bResult < 0.5) discard;\n");
|
||||
} else {
|
||||
// Not equal means any part must be not equal.
|
||||
WRITE(p, " if (rResult < 0.5 && gResult < 0.5 && bResult < 0.5) discard;\n");
|
||||
}
|
||||
} else {
|
||||
const char *colorTestFuncs[] = { "#", "#", " != ", " == " };
|
||||
if (colorTestFuncs[colorTestFunc][0] != '#') {
|
||||
// Apparently GLES3 does not support vector bitwise ops.
|
||||
WRITE(p, " ivec3 v_scaled = roundAndScaleTo255iv(v.rgb);\n");
|
||||
const char *maskedFragColor = "ivec3(v_scaled.r & u_alphacolormask.r, v_scaled.g & u_alphacolormask.g, v_scaled.b & u_alphacolormask.b)";
|
||||
const char *maskedColorRef = "ivec3(int(u_alphacolorref.r) & u_alphacolormask.r, int(u_alphacolorref.g) & u_alphacolormask.g, int(u_alphacolorref.b) & u_alphacolormask.b)";
|
||||
WRITE(p, " if (%s %s %s) discard;\n", maskedFragColor, colorTestFuncs[colorTestFunc], maskedColorRef);
|
||||
} else {
|
||||
WRITE(p, " discard;\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Color doubling happens after the color test.
|
||||
if (enableColorDoubling && replaceBlend == REPLACE_BLEND_2X_SRC) {
|
||||
WRITE(p, " v.rgb = v.rgb * 4.0;\n");
|
||||
} else if (enableColorDoubling || replaceBlend == REPLACE_BLEND_2X_SRC) {
|
||||
WRITE(p, " v.rgb = v.rgb * 2.0;\n");
|
||||
}
|
||||
|
||||
if (enableFog) {
|
||||
WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n");
|
||||
WRITE(p, " v = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n");
|
||||
// WRITE(p, " v.x = v_depth;\n");
|
||||
}
|
||||
|
||||
if (replaceBlend == REPLACE_BLEND_PRE_SRC || replaceBlend == REPLACE_BLEND_PRE_SRC_2X_ALPHA) {
|
||||
const char *srcFactor = "ERROR";
|
||||
switch (replaceBlendFuncA) {
|
||||
case GE_SRCBLEND_DSTCOLOR: srcFactor = "ERROR"; break;
|
||||
case GE_SRCBLEND_INVDSTCOLOR: srcFactor = "ERROR"; break;
|
||||
case GE_SRCBLEND_SRCALPHA: srcFactor = "vec3(v.a)"; break;
|
||||
case GE_SRCBLEND_INVSRCALPHA: srcFactor = "vec3(1.0 - v.a)"; break;
|
||||
case GE_SRCBLEND_DSTALPHA: srcFactor = "ERROR"; break;
|
||||
case GE_SRCBLEND_INVDSTALPHA: srcFactor = "ERROR"; break;
|
||||
case GE_SRCBLEND_DOUBLESRCALPHA: srcFactor = "vec3(v.a * 2.0)"; break;
|
||||
case GE_SRCBLEND_DOUBLEINVSRCALPHA: srcFactor = "vec3(1.0 - v.a * 2.0)"; break;
|
||||
case GE_SRCBLEND_DOUBLEDSTALPHA: srcFactor = "ERROR"; break;
|
||||
case GE_SRCBLEND_DOUBLEINVDSTALPHA: srcFactor = "ERROR"; break;
|
||||
case GE_SRCBLEND_FIXA: srcFactor = "u_blendFixA"; break;
|
||||
}
|
||||
|
||||
WRITE(p, " v.rgb = v.rgb * %s;\n", srcFactor);
|
||||
}
|
||||
|
||||
if (replaceBlend == REPLACE_BLEND_COPY_FBO) {
|
||||
WRITE(p, " lowp vec4 destColor = texelFetch(fbotex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);\n");
|
||||
|
||||
const char *srcFactor = "vec3(1.0)";
|
||||
const char *dstFactor = "vec3(0.0)";
|
||||
|
||||
switch (replaceBlendFuncA) {
|
||||
case GE_SRCBLEND_DSTCOLOR: srcFactor = "destColor.rgb"; break;
|
||||
case GE_SRCBLEND_INVDSTCOLOR: srcFactor = "(vec3(1.0) - destColor.rgb)"; break;
|
||||
case GE_SRCBLEND_SRCALPHA: srcFactor = "vec3(v.a)"; break;
|
||||
case GE_SRCBLEND_INVSRCALPHA: srcFactor = "vec3(1.0 - v.a)"; break;
|
||||
case GE_SRCBLEND_DSTALPHA: srcFactor = "vec3(destColor.a)"; break;
|
||||
case GE_SRCBLEND_INVDSTALPHA: srcFactor = "vec3(1.0 - destColor.a)"; break;
|
||||
case GE_SRCBLEND_DOUBLESRCALPHA: srcFactor = "vec3(v.a * 2.0)"; break;
|
||||
case GE_SRCBLEND_DOUBLEINVSRCALPHA: srcFactor = "vec3(1.0 - v.a * 2.0)"; break;
|
||||
case GE_SRCBLEND_DOUBLEDSTALPHA: srcFactor = "vec3(destColor.a * 2.0)"; break;
|
||||
case GE_SRCBLEND_DOUBLEINVDSTALPHA: srcFactor = "vec3(1.0 - destColor.a * 2.0)"; break;
|
||||
case GE_SRCBLEND_FIXA: srcFactor = "u_blendFixA"; break;
|
||||
}
|
||||
switch (replaceBlendFuncB) {
|
||||
case GE_DSTBLEND_SRCCOLOR: dstFactor = "v.rgb"; break;
|
||||
case GE_DSTBLEND_INVSRCCOLOR: dstFactor = "(vec3(1.0) - v.rgb)"; break;
|
||||
case GE_DSTBLEND_SRCALPHA: dstFactor = "vec3(v.a)"; break;
|
||||
case GE_DSTBLEND_INVSRCALPHA: dstFactor = "vec3(1.0 - v.a)"; break;
|
||||
case GE_DSTBLEND_DSTALPHA: dstFactor = "vec3(destColor.a)"; break;
|
||||
case GE_DSTBLEND_INVDSTALPHA: dstFactor = "vec3(1.0 - destColor.a)"; break;
|
||||
case GE_DSTBLEND_DOUBLESRCALPHA: dstFactor = "vec3(v.a * 2.0)"; break;
|
||||
case GE_DSTBLEND_DOUBLEINVSRCALPHA: dstFactor = "vec3(1.0 - v.a * 2.0)"; break;
|
||||
case GE_DSTBLEND_DOUBLEDSTALPHA: dstFactor = "vec3(destColor.a * 2.0)"; break;
|
||||
case GE_DSTBLEND_DOUBLEINVDSTALPHA: dstFactor = "vec3(1.0 - destColor.a * 2.0)"; break;
|
||||
case GE_DSTBLEND_FIXB: dstFactor = "u_blendFixB"; break;
|
||||
}
|
||||
|
||||
switch (replaceBlendEq) {
|
||||
case GE_BLENDMODE_MUL_AND_ADD:
|
||||
WRITE(p, " v.rgb = v.rgb * %s + destColor.rgb * %s;\n", srcFactor, dstFactor);
|
||||
break;
|
||||
case GE_BLENDMODE_MUL_AND_SUBTRACT:
|
||||
WRITE(p, " v.rgb = v.rgb * %s - destColor.rgb * %s;\n", srcFactor, dstFactor);
|
||||
break;
|
||||
case GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE:
|
||||
WRITE(p, " v.rgb = destColor.rgb * %s - v.rgb * %s;\n", dstFactor, srcFactor);
|
||||
break;
|
||||
case GE_BLENDMODE_MIN:
|
||||
WRITE(p, " v.rgb = min(v.rgb, destColor.rgb);\n");
|
||||
break;
|
||||
case GE_BLENDMODE_MAX:
|
||||
WRITE(p, " v.rgb = max(v.rgb, destColor.rgb);\n");
|
||||
break;
|
||||
case GE_BLENDMODE_ABSDIFF:
|
||||
WRITE(p, " v.rgb = abs(v.rgb - destColor.rgb);\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (replaceBlend == REPLACE_BLEND_2X_ALPHA || replaceBlend == REPLACE_BLEND_PRE_SRC_2X_ALPHA) {
|
||||
WRITE(p, " v.a = v.a * 2.0;\n");
|
||||
}
|
||||
}
|
||||
|
||||
std::string replacedAlpha = "0.0";
|
||||
char replacedAlphaTemp[64] = "";
|
||||
if (stencilToAlpha != REPLACE_ALPHA_NO) {
|
||||
switch (replaceAlphaWithStencilType) {
|
||||
case STENCIL_VALUE_UNIFORM:
|
||||
replacedAlpha = "u_stencilReplaceValue";
|
||||
break;
|
||||
|
||||
case STENCIL_VALUE_ZERO:
|
||||
replacedAlpha = "0.0";
|
||||
break;
|
||||
|
||||
case STENCIL_VALUE_ONE:
|
||||
case STENCIL_VALUE_INVERT:
|
||||
// In invert, we subtract by one, but we want to output one here.
|
||||
replacedAlpha = "1.0";
|
||||
break;
|
||||
|
||||
case STENCIL_VALUE_INCR_4:
|
||||
case STENCIL_VALUE_DECR_4:
|
||||
// We're adding/subtracting, just by the smallest value in 4-bit.
|
||||
snprintf(replacedAlphaTemp, sizeof(replacedAlphaTemp), "%f", 1.0 / 15.0);
|
||||
replacedAlpha = replacedAlphaTemp;
|
||||
break;
|
||||
|
||||
case STENCIL_VALUE_INCR_8:
|
||||
case STENCIL_VALUE_DECR_8:
|
||||
// We're adding/subtracting, just by the smallest value in 8-bit.
|
||||
snprintf(replacedAlphaTemp, sizeof(replacedAlphaTemp), "%f", 1.0 / 255.0);
|
||||
replacedAlpha = replacedAlphaTemp;
|
||||
break;
|
||||
|
||||
case STENCIL_VALUE_KEEP:
|
||||
// Do nothing. We'll mask out the alpha using color mask.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (stencilToAlpha) {
|
||||
case REPLACE_ALPHA_DUALSOURCE:
|
||||
WRITE(p, " fragColor0 = vec4(v.rgb, %s);\n", replacedAlpha.c_str());
|
||||
WRITE(p, " fragColor1 = vec4(0.0, 0.0, 0.0, v.a);\n");
|
||||
break;
|
||||
|
||||
case REPLACE_ALPHA_YES:
|
||||
WRITE(p, " fragColor0 = vec4(v.rgb, %s);\n", replacedAlpha.c_str());
|
||||
break;
|
||||
|
||||
case REPLACE_ALPHA_NO:
|
||||
WRITE(p, " fragColor0 = v;\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(G3D, "Bad stencil-to-alpha type, corrupt ID?");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogicOpReplaceType replaceLogicOpType = (LogicOpReplaceType)id.Bits(FS_BIT_REPLACE_LOGIC_OP_TYPE, 2);
|
||||
switch (replaceLogicOpType) {
|
||||
case LOGICOPTYPE_ONE:
|
||||
WRITE(p, " fragColor0.rgb = vec3(1.0, 1.0, 1.0);\n");
|
||||
break;
|
||||
case LOGICOPTYPE_INVERT:
|
||||
WRITE(p, " fragColor0.rgb = vec3(1.0, 1.0, 1.0) - fragColor0.rgb;\n");
|
||||
break;
|
||||
case LOGICOPTYPE_NORMAL:
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(G3D, "Bad logic op type, corrupt ID?");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, " highp float z = gl_FragCoord.z;\n");
|
||||
WRITE(p, " z = (1.0/65535.0) * floor(z * 65535.0);\n");
|
||||
WRITE(p, " gl_FragDepth = z;\n");
|
||||
}
|
||||
|
||||
WRITE(p, "}\n");
|
||||
|
||||
return true;
|
||||
}
|
25
GPU/Vulkan/FragmentShaderGeneratorVulkan.h
Normal file
25
GPU/Vulkan/FragmentShaderGeneratorVulkan.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
struct ShaderID;
|
||||
|
||||
bool GenerateVulkanGLSLFragmentShader(const ShaderID &id, char *buffer);
|
0
GPU/Vulkan/FramebufferVulkan.cpp
Normal file
0
GPU/Vulkan/FramebufferVulkan.cpp
Normal file
107
GPU/Vulkan/FramebufferVulkan.h
Normal file
107
GPU/Vulkan/FramebufferVulkan.h
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GPU/Common/FramebufferCommon.h"
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
|
||||
class FramebufferManagerVulkan : public FramebufferManagerCommon {
|
||||
public:
|
||||
// Subsequent commands will be enqueued on this buffer.
|
||||
void SetInstance(VkInstance inst) { inst_ = inst; }
|
||||
void SetCmdBuffer(VkCommandBuffer cmd) { cmd_ = cmd; }
|
||||
|
||||
virtual void ClearBuffer(bool keepState = false) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void RebindFramebuffer() override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void DrawFramebufferToOutput(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, bool applyPostShader) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void DisableState() override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void FlushBeforeCopy() override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void DecimateFBOs() override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void DestroyFramebuf(VirtualFramebuffer *vfb) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w, u16 h, bool force = false) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
virtual void NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb, bool vfbFormatChanged) override {
|
||||
throw std::logic_error("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) override {
|
||||
|
||||
}
|
||||
|
||||
bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) override {
|
||||
return false;
|
||||
}
|
||||
void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override {
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
VkInstance inst_;
|
||||
VkCommandBuffer cmd_;
|
||||
};
|
116
GPU/Vulkan/GPU_Vulkan.cpp
Normal file
116
GPU/Vulkan/GPU_Vulkan.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "GPU/Vulkan/GPU_Vulkan.h"
|
||||
|
||||
GPU_Vulkan::GPU_Vulkan() {
|
||||
|
||||
}
|
||||
|
||||
GPU_Vulkan::~GPU_Vulkan() {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::CheckGPUFeatures() {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::ReapplyGfxStateInternal() {}
|
||||
void GPU_Vulkan::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {}
|
||||
void GPU_Vulkan::CopyDisplayToOutput() {}
|
||||
void GPU_Vulkan::BeginFrame() {}
|
||||
void GPU_Vulkan::UpdateStats() {}
|
||||
void GPU_Vulkan::InvalidateCache(u32 addr, int size, GPUInvalidationType type) {}
|
||||
bool GPU_Vulkan::PerformMemoryCopy(u32 dest, u32 src, int size) { return false; }
|
||||
bool GPU_Vulkan::PerformMemorySet(u32 dest, u8 v, int size) { return false; }
|
||||
bool GPU_Vulkan::PerformMemoryDownload(u32 dest, int size) { return false; }
|
||||
bool GPU_Vulkan::PerformMemoryUpload(u32 dest, int size) { return false; }
|
||||
bool GPU_Vulkan::PerformStencilUpload(u32 dest, int size) { return false; }
|
||||
void GPU_Vulkan::ClearCacheNextFrame() {}
|
||||
void GPU_Vulkan::DeviceLost() {} // Only happens on Android. Drop all textures and shaders.
|
||||
|
||||
void GPU_Vulkan::DumpNextFrame() {}
|
||||
|
||||
void GPU_Vulkan::DoState(PointerWrap &p) {
|
||||
GPUCommon::DoState(p);
|
||||
}
|
||||
|
||||
|
||||
void GPU_Vulkan::DoBlockTransfer(u32 skipDrawReason) {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::Resized() {}
|
||||
|
||||
void GPU_Vulkan::ClearShaderCache() {}
|
||||
bool GPU_Vulkan::FramebufferDirty() { return false; }
|
||||
bool GPU_Vulkan::FramebufferReallyDirty() { return false; }
|
||||
|
||||
void GPU_Vulkan::FastRunLoop(DisplayList &list) {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::ProcessEvent(GPUEvent ev) {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::FastLoadBoneMatrix(u32 target) {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::FinishDeferred() {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::UpdateCmdInfo() {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::InitClear() {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::Reinitialize() {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::PreExecuteOp(u32 op, u32 diff) {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::Execute_Generic(u32 op, u32 diff) {
|
||||
|
||||
}
|
||||
|
||||
void GPU_Vulkan::ExecuteOp(u32 op, u32 diff) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::string> GPU_Vulkan::DebugGetShaderIDs(DebugShaderType shader) {
|
||||
std::vector<std::string> ids;
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::string GPU_Vulkan::DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) {
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
void GPU_Vulkan::NotifyVideoUpload(u32 addr, int size, int width, int format) {
|
||||
|
||||
}
|
172
GPU/Vulkan/GPU_Vulkan.h
Normal file
172
GPU/Vulkan/GPU_Vulkan.h
Normal file
@ -0,0 +1,172 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
#include "GPU/GPUCommon.h"
|
||||
#include "GPU/Vulkan/FramebufferVulkan.h"
|
||||
#include "GPU/Vulkan/DrawEngineVulkan.h"
|
||||
#include "GPU/Vulkan/PipelineManagerVulkan.h"
|
||||
#include "GPU/Vulkan/TextureCacheVulkan.h"
|
||||
|
||||
class ShaderManager;
|
||||
class LinkedShader;
|
||||
|
||||
class GPU_Vulkan : public GPUCommon {
|
||||
public:
|
||||
GPU_Vulkan();
|
||||
~GPU_Vulkan();
|
||||
|
||||
// This gets called on startup and when we get back from settings.
|
||||
void CheckGPUFeatures();
|
||||
|
||||
void InitClear() override;
|
||||
void Reinitialize() override;
|
||||
void PreExecuteOp(u32 op, u32 diff) override;
|
||||
void Execute_Generic(u32 op, u32 diff);
|
||||
void ExecuteOp(u32 op, u32 diff) override;
|
||||
|
||||
void ReapplyGfxStateInternal() override;
|
||||
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
|
||||
void CopyDisplayToOutput() override;
|
||||
void BeginFrame() override;
|
||||
void UpdateStats() override;
|
||||
void InvalidateCache(u32 addr, int size, GPUInvalidationType type) override;
|
||||
void NotifyVideoUpload(u32 addr, int size, int width, int format) override;
|
||||
bool PerformMemoryCopy(u32 dest, u32 src, int size) override;
|
||||
bool PerformMemorySet(u32 dest, u8 v, int size) override;
|
||||
bool PerformMemoryDownload(u32 dest, int size) override;
|
||||
bool PerformMemoryUpload(u32 dest, int size) override;
|
||||
bool PerformStencilUpload(u32 dest, int size) override;
|
||||
void ClearCacheNextFrame() override;
|
||||
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
|
||||
|
||||
void DumpNextFrame() override;
|
||||
void DoState(PointerWrap &p) override;
|
||||
|
||||
// Called by the window system if the window size changed. This will be reflected in PSPCoreParam.pixel*.
|
||||
void Resized() override;
|
||||
void ClearShaderCache() override;
|
||||
bool DecodeTexture(u8 *dest, const GPUgstate &state) override {
|
||||
return textureCache_.DecodeTexture(dest, state);
|
||||
}
|
||||
bool FramebufferDirty() override;
|
||||
bool FramebufferReallyDirty() override;
|
||||
|
||||
void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) override {
|
||||
primaryInfo = reportingPrimaryInfo_;
|
||||
fullInfo = reportingFullInfo_;
|
||||
}
|
||||
|
||||
typedef void (GPU_Vulkan::*CmdFunc)(u32 op, u32 diff);
|
||||
struct CommandInfo {
|
||||
u8 flags;
|
||||
GPU_Vulkan::CmdFunc func;
|
||||
};
|
||||
|
||||
/*
|
||||
void Execute_Vaddr(u32 op, u32 diff);
|
||||
void Execute_Iaddr(u32 op, u32 diff);
|
||||
void Execute_Prim(u32 op, u32 diff);
|
||||
void Execute_Bezier(u32 op, u32 diff);
|
||||
void Execute_Spline(u32 op, u32 diff);
|
||||
void Execute_BoundingBox(u32 op, u32 diff);
|
||||
void Execute_VertexType(u32 op, u32 diff);
|
||||
void Execute_VertexTypeSkinning(u32 op, u32 diff);
|
||||
void Execute_Region(u32 op, u32 diff);
|
||||
void Execute_Scissor(u32 op, u32 diff);
|
||||
void Execute_FramebufType(u32 op, u32 diff);
|
||||
void Execute_ViewportType(u32 op, u32 diff);
|
||||
void Execute_ViewportZType(u32 op, u32 diff);
|
||||
void Execute_TexScaleU(u32 op, u32 diff);
|
||||
void Execute_TexScaleV(u32 op, u32 diff);
|
||||
void Execute_TexOffsetU(u32 op, u32 diff);
|
||||
void Execute_TexOffsetV(u32 op, u32 diff);
|
||||
void Execute_TexAddr0(u32 op, u32 diff);
|
||||
void Execute_TexAddrN(u32 op, u32 diff);
|
||||
void Execute_TexBufw0(u32 op, u32 diff);
|
||||
void Execute_TexBufwN(u32 op, u32 diff);
|
||||
void Execute_TexSize0(u32 op, u32 diff);
|
||||
void Execute_TexSizeN(u32 op, u32 diff);
|
||||
void Execute_TexFormat(u32 op, u32 diff);
|
||||
void Execute_TexMapMode(u32 op, u32 diff);
|
||||
void Execute_TexParamType(u32 op, u32 diff);
|
||||
void Execute_TexEnvColor(u32 op, u32 diff);
|
||||
void Execute_TexLevel(u32 op, u32 diff);
|
||||
void Execute_LoadClut(u32 op, u32 diff);
|
||||
void Execute_ClutFormat(u32 op, u32 diff);
|
||||
void Execute_Ambient(u32 op, u32 diff);
|
||||
void Execute_MaterialDiffuse(u32 op, u32 diff);
|
||||
void Execute_MaterialEmissive(u32 op, u32 diff);
|
||||
void Execute_MaterialAmbient(u32 op, u32 diff);
|
||||
void Execute_MaterialSpecular(u32 op, u32 diff);
|
||||
void Execute_Light0Param(u32 op, u32 diff);
|
||||
void Execute_Light1Param(u32 op, u32 diff);
|
||||
void Execute_Light2Param(u32 op, u32 diff);
|
||||
void Execute_Light3Param(u32 op, u32 diff);
|
||||
void Execute_FogColor(u32 op, u32 diff);
|
||||
void Execute_FogCoef(u32 op, u32 diff);
|
||||
void Execute_ColorTestMask(u32 op, u32 diff);
|
||||
void Execute_AlphaTest(u32 op, u32 diff);
|
||||
void Execute_StencilTest(u32 op, u32 diff);
|
||||
void Execute_ColorRef(u32 op, u32 diff);
|
||||
void Execute_WorldMtxNum(u32 op, u32 diff);
|
||||
void Execute_WorldMtxData(u32 op, u32 diff);
|
||||
void Execute_ViewMtxNum(u32 op, u32 diff);
|
||||
void Execute_ViewMtxData(u32 op, u32 diff);
|
||||
void Execute_ProjMtxNum(u32 op, u32 diff);
|
||||
void Execute_ProjMtxData(u32 op, u32 diff);
|
||||
void Execute_TgenMtxNum(u32 op, u32 diff);
|
||||
void Execute_TgenMtxData(u32 op, u32 diff);
|
||||
void Execute_BoneMtxNum(u32 op, u32 diff);
|
||||
void Execute_BoneMtxData(u32 op, u32 diff);
|
||||
void Execute_BlockTransferStart(u32 op, u32 diff);
|
||||
*/
|
||||
|
||||
// Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
|
||||
std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override;
|
||||
std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override;
|
||||
|
||||
protected:
|
||||
void FastRunLoop(DisplayList &list) override;
|
||||
void ProcessEvent(GPUEvent ev) override;
|
||||
void FastLoadBoneMatrix(u32 target) override;
|
||||
void FinishDeferred() override;
|
||||
|
||||
private:
|
||||
void DoBlockTransfer(u32 skipDrawReason);
|
||||
|
||||
void UpdateCmdInfo();
|
||||
|
||||
static CommandInfo cmdInfo_[256];
|
||||
|
||||
FramebufferManagerVulkan framebufferManager_;
|
||||
TextureCacheVulkan textureCache_;
|
||||
// DepalShaderCache depalShaderCache_;
|
||||
DrawEngineVulkan transformDraw_;
|
||||
// FragmentTestCache fragmentTestCache_;
|
||||
PipelineManagerVulkan *pipelineManager_;
|
||||
|
||||
bool resized_;
|
||||
int lastVsync_;
|
||||
|
||||
std::string reportingPrimaryInfo_;
|
||||
std::string reportingFullInfo_;
|
||||
};
|
221
GPU/Vulkan/PipelineManagerVulkan.cpp
Normal file
221
GPU/Vulkan/PipelineManagerVulkan.cpp
Normal file
@ -0,0 +1,221 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
#include "GPU/Vulkan/PipelineManagerVulkan.h"
|
||||
|
||||
struct DeclTypeInfo {
|
||||
VkFormat type;
|
||||
const char * name;
|
||||
};
|
||||
|
||||
static const DeclTypeInfo VComp[] = {
|
||||
{ VK_FORMAT_UNDEFINED, "NULL" }, // DEC_NONE,
|
||||
{ VK_FORMAT_R32_SFLOAT, "R32_SFLOAT " }, // DEC_FLOAT_1,
|
||||
{ VK_FORMAT_R32G32_SFLOAT, "R32G32_SFLOAT " }, // DEC_FLOAT_2,
|
||||
{ VK_FORMAT_R32G32B32_SFLOAT, "R32G32B32_SFLOAT " }, // DEC_FLOAT_3,
|
||||
{ VK_FORMAT_R32G32B32A32_SFLOAT, "R32G32B32A32_SFLOAT " }, // DEC_FLOAT_4,
|
||||
|
||||
{ VK_FORMAT_UNDEFINED, "UNDEFINED" }, // DEC_S8_3,
|
||||
|
||||
{ VK_FORMAT_R16G16B16A16_SNORM, "R16G16B16A16_SNORM " }, // DEC_S16_3,
|
||||
{ VK_FORMAT_R8G8B8A8_SNORM, "R8G8B8A8_SNORM " }, // DEC_U8_1,
|
||||
{ VK_FORMAT_R8G8B8A8_SNORM, "R8G8B8A8_SNORM " }, // DEC_U8_2,
|
||||
{ VK_FORMAT_R8G8B8A8_SNORM, "R8G8B8A8_SNORM " }, // DEC_U8_3,
|
||||
{ VK_FORMAT_R8G8B8A8_SNORM, "R8G8B8A8_SNORM " }, // DEC_U8_4,
|
||||
{ VK_FORMAT_R16G16_UNORM, "R16G16_UNORM" }, // DEC_U16_1,
|
||||
{ VK_FORMAT_R16G16_UNORM, "R16G16_UNORM" }, // DEC_U16_2,
|
||||
{ VK_FORMAT_R16G16B16A16_UNORM, "R16G16B16A16_UNORM " }, // DEC_U16_3,
|
||||
{ VK_FORMAT_R16G16B16A16_UNORM, "R16G16B16A16_UNORM " }, // DEC_U16_4,
|
||||
// Not supported in regular DX9 so faking, will cause graphics bugs until worked around
|
||||
{ VK_FORMAT_R8G8_UINT, "VK_FORMAT_UNDEFINED" }, // DEC_U8A_2,
|
||||
{ VK_FORMAT_R16G16_UINT, "VK_FORMAT_UNDEFINED" }, // DEC_U16A_2,
|
||||
};
|
||||
|
||||
void VertexAttribSetup(VkVertexInputAttributeDescription *attr, int fmt, int offset, PspAttributeLocation location) {
|
||||
attr->location = (uint32_t)location;
|
||||
attr->binding = 0;
|
||||
attr->format = VComp[fmt].type;
|
||||
attr->offset = offset;
|
||||
}
|
||||
|
||||
// Returns the number of attributes that were set.
|
||||
// We could cache these AttributeDescription arrays (with pspFmt as the key), but hardly worth bothering
|
||||
// as we will only call this code when we need to create a new VkPipeline.
|
||||
int SetupVertexAttribs(VkVertexInputAttributeDescription attrs[], const DecVtxFormat &decFmt) {
|
||||
int count = 0;
|
||||
if (decFmt.w0fmt != 0) {
|
||||
VertexAttribSetup(&attrs[count++], decFmt.w0fmt, decFmt.w0off, PspAttributeLocation::W1);
|
||||
}
|
||||
if (decFmt.w1fmt != 0) {
|
||||
VertexAttribSetup(&attrs[count++], decFmt.w1fmt, decFmt.w1off, PspAttributeLocation::W2);
|
||||
}
|
||||
if (decFmt.uvfmt != 0) {
|
||||
VertexAttribSetup(&attrs[count++], decFmt.uvfmt, decFmt.uvoff, PspAttributeLocation::TEXCOORD);
|
||||
}
|
||||
if (decFmt.c0fmt != 0) {
|
||||
VertexAttribSetup(&attrs[count++], decFmt.c0fmt, decFmt.c0off, PspAttributeLocation::COLOR0);
|
||||
}
|
||||
if (decFmt.c1fmt != 0) {
|
||||
VertexAttribSetup(&attrs[count++], decFmt.c1fmt, decFmt.c1off, PspAttributeLocation::COLOR1);
|
||||
}
|
||||
if (decFmt.nrmfmt != 0) {
|
||||
VertexAttribSetup(&attrs[count++], decFmt.nrmfmt, decFmt.nrmoff, PspAttributeLocation::NORMAL);
|
||||
}
|
||||
// Position is always there.
|
||||
VertexAttribSetup(&attrs[count++], decFmt.posfmt, decFmt.posoff, PspAttributeLocation::POSITION);
|
||||
return count;
|
||||
}
|
||||
|
||||
int SetupVertexAttribsPretransformed(VkVertexInputAttributeDescription attrs[]) {
|
||||
VertexAttribSetup(&attrs[0], DEC_FLOAT_4, 0, PspAttributeLocation::POSITION);
|
||||
VertexAttribSetup(&attrs[1], DEC_FLOAT_3, 16, PspAttributeLocation::TEXCOORD);
|
||||
VertexAttribSetup(&attrs[2], DEC_U8_4, 28, PspAttributeLocation::COLOR0);
|
||||
VertexAttribSetup(&attrs[3], DEC_U8_4, 32, PspAttributeLocation::COLOR1);
|
||||
return 4;
|
||||
}
|
||||
|
||||
static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pipelineCache, const VulkanPipelineRasterStateKey &key, const DecVtxFormat &vfmt, VkShaderModule vshader, VkShaderModule fshader, bool useHwTransform) {
|
||||
VkPipelineColorBlendAttachmentState blend0;
|
||||
blend0.blendEnable = key.blendEnable;
|
||||
if (key.blendEnable) {
|
||||
blend0.colorBlendOp = key.blendOpColor;
|
||||
blend0.alphaBlendOp = key.blendOpAlpha;
|
||||
blend0.srcColorBlendFactor = key.srcColor;
|
||||
blend0.srcAlphaBlendFactor = key.srcAlpha;
|
||||
blend0.dstColorBlendFactor = key.destColor;
|
||||
blend0.dstAlphaBlendFactor = key.destAlpha;
|
||||
}
|
||||
blend0.colorWriteMask = key.colorWriteMask;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo cbs;
|
||||
cbs.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
cbs.pNext = nullptr;
|
||||
cbs.pAttachments = &blend0;
|
||||
cbs.attachmentCount = 1;
|
||||
cbs.logicOpEnable = key.logicOpEnable;
|
||||
if (key.logicOpEnable)
|
||||
cbs.logicOp = key.logicOp;
|
||||
else
|
||||
cbs.logicOp = VK_LOGIC_OP_COPY;
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo dss;
|
||||
dss.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
dss.depthBoundsTestEnable = false;
|
||||
dss.stencilTestEnable = key.stencilTestEnable;
|
||||
if (key.stencilTestEnable) {
|
||||
dss.front.compareOp = key.stencilCompareOp;
|
||||
dss.front.passOp = key.stencilPassOp;
|
||||
dss.front.failOp = key.stencilFailOp;
|
||||
dss.front.depthFailOp = key.stencilDepthFailOp;
|
||||
// Back stencil is always the same as front on PSP.
|
||||
memcpy(&dss.back, &dss.front, sizeof(dss.front));
|
||||
}
|
||||
dss.depthTestEnable = key.depthTestEnable;
|
||||
if (key.depthTestEnable) {
|
||||
dss.depthCompareOp = key.depthCompareOp;
|
||||
dss.depthWriteEnable = key.depthWriteEnable;
|
||||
}
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipe;
|
||||
pipe.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipe.pNext = nullptr;
|
||||
|
||||
pipe.pColorBlendState = &cbs;
|
||||
if (key.depthTestEnable || key.stencilTestEnable) {
|
||||
pipe.pDepthStencilState = &dss;
|
||||
} else {
|
||||
pipe.pDepthStencilState = nullptr;
|
||||
}
|
||||
|
||||
VkDynamicState dynamicStates[8];
|
||||
int numDyn = 0;
|
||||
if (key.blendEnable) {
|
||||
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS;
|
||||
}
|
||||
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_SCISSOR;
|
||||
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_VIEWPORT;
|
||||
if (key.stencilTestEnable) {
|
||||
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK;
|
||||
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE;
|
||||
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_STENCIL_WRITE_MASK;
|
||||
}
|
||||
|
||||
VkPipelineDynamicStateCreateInfo ds;
|
||||
ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
ds.pNext = nullptr;
|
||||
ds.pDynamicStates = dynamicStates;
|
||||
ds.dynamicStateCount = numDyn;
|
||||
|
||||
pipe.pDynamicState = &ds;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rs;
|
||||
rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rs.pNext = nullptr;
|
||||
rs.depthBiasEnable = false;
|
||||
rs.cullMode = key.cullMode;
|
||||
rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||
rs.lineWidth = 1.0f;
|
||||
rs.rasterizerDiscardEnable = false;
|
||||
rs.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rs.depthClampEnable = false;
|
||||
|
||||
pipe.pRasterizationState = &rs;
|
||||
|
||||
// We will use dynamic viewport state.
|
||||
pipe.pViewportState = nullptr;
|
||||
|
||||
VkPipelineShaderStageCreateInfo ss[2];
|
||||
ss[0].sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
ss[0].pNext = nullptr;
|
||||
ss[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
ss[0].pSpecializationInfo = nullptr;
|
||||
ss[0].module = vshader;
|
||||
ss[0].pName = "main";
|
||||
ss[0].flags = 0;
|
||||
ss[1].sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
ss[1].pNext = nullptr;
|
||||
ss[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
ss[1].pSpecializationInfo = nullptr;
|
||||
ss[1].module = fshader;
|
||||
ss[1].pName = "main";
|
||||
ss[1].flags = 0;
|
||||
pipe.stageCount = 2;
|
||||
pipe.pStages = ss;
|
||||
pipe.basePipelineIndex = 0;
|
||||
|
||||
int vertexStride = 0;
|
||||
|
||||
int offset = 0;
|
||||
VkVertexInputAttributeDescription attrs[8];
|
||||
int attributeCount;
|
||||
if (useHwTransform) {
|
||||
attributeCount = SetupVertexAttribs(attrs, vfmt);
|
||||
} else {
|
||||
attributeCount = SetupVertexAttribsPretransformed(attrs);
|
||||
}
|
||||
|
||||
VkVertexInputBindingDescription ibd;
|
||||
ibd.binding = 0;
|
||||
ibd.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
ibd.stride = vertexStride;
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vis;
|
||||
vis.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vis.pNext = nullptr;
|
||||
vis.vertexBindingDescriptionCount = 1;
|
||||
vis.pVertexBindingDescriptions = &ibd;
|
||||
vis.vertexAttributeDescriptionCount = attributeCount;
|
||||
vis.pVertexAttributeDescriptions = attrs;
|
||||
|
||||
VkPipeline pipeline;
|
||||
VkResult result = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipe, nullptr, &pipeline);
|
||||
if (result != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VulkanPipeline *vulkanPipeline = new VulkanPipeline();
|
||||
vulkanPipeline->pipeline = pipeline;
|
||||
return vulkanPipeline;
|
||||
}
|
106
GPU/Vulkan/PipelineManagerVulkan.h
Normal file
106
GPU/Vulkan/PipelineManagerVulkan.h
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GPU/Common/VertexDecoderCommon.h"
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
|
||||
// The Descriptor Set used for the majority of PSP rendering looks like this:
|
||||
//
|
||||
// * binding 0: Vertex Data (up to 7 locations as defined in PspAttributeLocation)
|
||||
// * binding 1: Texture Sampler (the PSP texture)
|
||||
// * binding 2: Secondary texture sampler for shader blending or depal palettes
|
||||
// * binding 3: Vertex Uniform Buffer
|
||||
// * binding 4: Fragment Uniform Buffer
|
||||
//
|
||||
// All shaders conform to this layout, so they are all compatible with the same descriptor set.
|
||||
// The format of the various uniform buffers may vary though - vertex shaders that don't skin
|
||||
// won't get any bone data, etc.
|
||||
|
||||
enum class PspAttributeLocation {
|
||||
POSITION = 0,
|
||||
TEXCOORD = 1,
|
||||
NORMAL = 2,
|
||||
W1 = 3,
|
||||
W2 = 4,
|
||||
COLOR0 = 5,
|
||||
COLOR1 = 6,
|
||||
|
||||
COUNT
|
||||
};
|
||||
|
||||
// Let's pack this tight using bitfields.
|
||||
// If an enable flag is set to 0, all the data fields for that section should
|
||||
// also be set to 0.
|
||||
// ~54 bits.
|
||||
struct VulkanPipelineRasterStateKey {
|
||||
// Blend
|
||||
bool blendEnable : 1;
|
||||
VkBlendFactor srcColor : 5;
|
||||
VkBlendFactor destColor : 5;
|
||||
VkBlendFactor srcAlpha : 5;
|
||||
VkBlendFactor destAlpha : 5;
|
||||
VkBlendOp blendOpColor : 3;
|
||||
VkBlendOp blendOpAlpha : 3;
|
||||
bool logicOpEnable : 1;
|
||||
VkLogicOp logicOp : 4;
|
||||
int colorWriteMask : 4;
|
||||
|
||||
// Depth/Stencil
|
||||
bool depthTestEnable : 1;
|
||||
bool depthWriteEnable : 1;
|
||||
VkCompareOp depthCompareOp : 3;
|
||||
bool stencilTestEnable : 1;
|
||||
VkCompareOp stencilCompareOp : 4;
|
||||
VkStencilOp stencilPassOp : 4;
|
||||
VkStencilOp stencilFailOp : 4;
|
||||
VkStencilOp stencilDepthFailOp : 4;
|
||||
// We'll use dynamic state for writemask, reference and comparemask to start with.
|
||||
|
||||
// Rasterizer
|
||||
VkCullModeFlagBits cullMode : 2;
|
||||
};
|
||||
|
||||
// All the information needed. All PSP rendering (except full screen clears?) will make use of a single
|
||||
// render pass definition.
|
||||
struct VulkanPipelineKey {
|
||||
VulkanPipelineRasterStateKey raster;
|
||||
int prim;
|
||||
bool pretransformed;
|
||||
uint32_t vertType;
|
||||
ShaderID vShaderId;
|
||||
ShaderID fShaderId;
|
||||
};
|
||||
|
||||
enum {
|
||||
UB_VS_BASICTRANSFORM = (1 << 0),
|
||||
UB_VS_BONES = (1 << 1),
|
||||
UB_VS_LIGHTS = (1 << 2),
|
||||
};
|
||||
|
||||
// Simply wraps a Vulkan pipeline, providing some metadata.
|
||||
struct VulkanPipeline {
|
||||
VkPipeline pipeline;
|
||||
int uniformBlocks; // UB_ enum above.
|
||||
};
|
||||
|
||||
class PipelineManagerVulkan {
|
||||
public:
|
||||
|
||||
};
|
23
GPU/Vulkan/ShaderCompiler.cpp
Normal file
23
GPU/Vulkan/ShaderCompiler.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
#include "GPU/Vulkan/ShaderCompiler.h"
|
||||
|
||||
bool CompileGLSLVulkan(const char *code, std::vector<uint32_t> &spirv, std::string &errorMessage) {
|
||||
return false;
|
||||
}
|
27
GPU/Vulkan/ShaderCompiler.h
Normal file
27
GPU/Vulkan/ShaderCompiler.h
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
|
||||
// Wrapper around the GLSL compiler library. Compiles GLSL into SPIR-V consumable by Vulkan.
|
||||
bool CompileGLSLVulkan(const char *code, std::vector<uint32_t> &spirv, std::string &errorMessage);
|
||||
|
||||
// TODO: Compute shaders
|
||||
|
612
GPU/Vulkan/ShaderManagerVulkan.cpp
Normal file
612
GPU/Vulkan/ShaderManagerVulkan.cpp
Normal file
@ -0,0 +1,612 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SHADERLOG
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "math/lin/matrix4x4.h"
|
||||
#include "math/math_util.h"
|
||||
#include "math/dataconv.h"
|
||||
#include "util/text/utf8.h"
|
||||
#include "thin3d/vulkan_utils.h"
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "GPU/Math3D.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/ge_constants.h"
|
||||
#include "GPU/Vulkan/ShaderManagerVulkan.h"
|
||||
#include "GPU/Vulkan/DrawEngineVulkan.h"
|
||||
#include "GPU/Vulkan/FramebufferVulkan.h"
|
||||
#include "GPU/Vulkan/ShaderCompiler.h"
|
||||
#include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h"
|
||||
#include "GPU/Vulkan/VertexShaderGeneratorVulkan.h"
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
|
||||
VulkanFragmentShader::VulkanFragmentShader(VkDevice device, ShaderID id, const char *code, bool useHWTransform)
|
||||
: device_(device), id_(id), failed_(false), useHWTransform_(useHWTransform), module_(nullptr) {
|
||||
source_ = code;
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugString(ConvertUTF8ToWString(code).c_str());
|
||||
#endif
|
||||
|
||||
std::string errorMessage;
|
||||
std::vector<uint32_t> spirv;
|
||||
bool success = CompileGLSLVulkan(code, spirv, errorMessage);
|
||||
if (!errorMessage.empty()) {
|
||||
if (success) {
|
||||
ERROR_LOG(G3D, "Warnings in shader compilation!");
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Error in shader compilation!");
|
||||
}
|
||||
ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str());
|
||||
ERROR_LOG(G3D, "Shader source:\n%s", code);
|
||||
OutputDebugStringUTF8("Messages:\n");
|
||||
OutputDebugStringUTF8(errorMessage.c_str());
|
||||
Reporting::ReportMessage("Vulkan error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);
|
||||
} else {
|
||||
success = CreateShaderModule(device_, spirv, &module_);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
failed_ = true;
|
||||
return;
|
||||
} else {
|
||||
DEBUG_LOG(G3D, "Compiled shader:\n%s\n", (const char *)code);
|
||||
}
|
||||
}
|
||||
|
||||
VulkanFragmentShader::~VulkanFragmentShader() {
|
||||
if (module_) {
|
||||
vkDestroyShaderModule(device_, module_, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::string VulkanFragmentShader::GetShaderString(DebugShaderStringType type) const {
|
||||
switch (type) {
|
||||
case SHADER_STRING_SOURCE_CODE:
|
||||
return source_;
|
||||
case SHADER_STRING_SHORT_DESC:
|
||||
return FragmentShaderDesc(id_);
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
VulkanVertexShader::VulkanVertexShader(VkDevice device, ShaderID id, const char *code, int vertType, bool useHWTransform)
|
||||
: device_(device), id_(id), failed_(false), useHWTransform_(useHWTransform), module_(nullptr) {
|
||||
source_ = code;
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugString(ConvertUTF8ToWString(code).c_str());
|
||||
#endif
|
||||
std::string errorMessage;
|
||||
std::vector<uint32_t> spirv;
|
||||
bool success = CompileGLSLVulkan(code, spirv, errorMessage);
|
||||
if (!errorMessage.empty()) {
|
||||
if (success) {
|
||||
ERROR_LOG(G3D, "Warnings in shader compilation!");
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Error in shader compilation!");
|
||||
}
|
||||
ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str());
|
||||
ERROR_LOG(G3D, "Shader source:\n%s", code);
|
||||
OutputDebugStringUTF8("Messages:\n");
|
||||
OutputDebugStringUTF8(errorMessage.c_str());
|
||||
Reporting::ReportMessage("Vulkan error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);
|
||||
} else {
|
||||
success = CreateShaderModule(device_, spirv, &module_);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
failed_ = true;
|
||||
module_ = nullptr;
|
||||
return;
|
||||
} else {
|
||||
DEBUG_LOG(G3D, "Compiled shader:\n%s\n", (const char *)code);
|
||||
}
|
||||
}
|
||||
|
||||
VulkanVertexShader::~VulkanVertexShader() {
|
||||
if (module_) {
|
||||
vkDestroyShaderModule(device_, module_, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::string VulkanVertexShader::GetShaderString(DebugShaderStringType type) const {
|
||||
switch (type) {
|
||||
case SHADER_STRING_SOURCE_CODE:
|
||||
return source_;
|
||||
case SHADER_STRING_SHORT_DESC:
|
||||
return VertexShaderDesc(id_);
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Utility
|
||||
void ShaderManagerVulkan::VSSetMatrix4x3(int creg, const float *m4x3) {
|
||||
float m4x4[16];
|
||||
ConvertMatrix4x3To4x4Transposed(m4x4, m4x3);
|
||||
pD3Ddevice->SetVertexShaderConstantF(creg, m4x4, 4);
|
||||
}
|
||||
|
||||
void ShaderManagerVulkan::VSSetMatrix4x3_3(int creg, const float *m4x3) {
|
||||
float m3x4[16];
|
||||
ConvertMatrix4x3To3x4Transposed(m3x4, m4x3);
|
||||
pD3Ddevice->SetVertexShaderConstantF(creg, m3x4, 3);
|
||||
}
|
||||
|
||||
void ShaderManagerVulkan::VSSetMatrix(int creg, const float* pMatrix) {
|
||||
float transp[16];
|
||||
Transpose4x4(transp, pMatrix);
|
||||
pD3Ddevice->SetVertexShaderConstantF(creg, transp, 4);
|
||||
}
|
||||
*/
|
||||
|
||||
// Depth in ogl is between -1;1 we need between 0;1 and optionally reverse it
|
||||
static void ConvertProjMatrixToVulkan(Matrix4x4 &in, bool invertedX, bool invertedY, bool invertedZ) {
|
||||
// Half pixel offset hack
|
||||
float xoff = 0.5f / gstate_c.curRTRenderWidth;
|
||||
xoff = gstate_c.vpXOffset + (invertedX ? xoff : -xoff);
|
||||
float yoff = -0.5f / gstate_c.curRTRenderHeight;
|
||||
yoff = gstate_c.vpYOffset + (invertedY ? yoff : -yoff);
|
||||
|
||||
if (invertedX)
|
||||
xoff = -xoff;
|
||||
if (invertedY)
|
||||
yoff = -yoff;
|
||||
|
||||
in.translateAndScale(Vec3(xoff, yoff, 0.5f), Vec3(gstate_c.vpWidthScale, gstate_c.vpHeightScale, invertedZ ? -0.5 : 0.5f));
|
||||
}
|
||||
|
||||
static void ConvertProjMatrixToVulkanThrough(Matrix4x4 &in) {
|
||||
float xoff = -0.5f / gstate_c.curRTRenderWidth;
|
||||
float yoff = 0.5f / gstate_c.curRTRenderHeight;
|
||||
in.translateAndScale(Vec3(xoff, yoff, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
|
||||
}
|
||||
|
||||
void ShaderManagerVulkan::PSUpdateUniforms(int dirtyUniforms) {
|
||||
if (dirtyUniforms & DIRTY_TEXENV) {
|
||||
Uint8x3ToFloat4(ub_fragment.texEnvColor, gstate.texenvcolor);
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_ALPHACOLORREF) {
|
||||
Uint8x3ToFloat4_Alpha(ub_fragment.alphaColorRef, gstate.getColorTestRef(), (float)gstate.getAlphaTestRef());
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_ALPHACOLORMASK) {
|
||||
Uint8x3ToFloat4(ub_fragment.colorTestMask, gstate.colortestmask);
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_FOGCOLOR) {
|
||||
Uint8x3ToFloat4(ub_fragment.fogColor, gstate.fogcolor);
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_STENCILREPLACEVALUE) {
|
||||
Uint8x1ToFloat4(ub_fragment.stencilReplace, gstate.getStencilTestRef());
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_SHADERBLEND) {
|
||||
Uint8x3ToFloat4(ub_fragment.blendFixA, gstate.getFixA());
|
||||
Uint8x3ToFloat4(ub_fragment.blendFixB, gstate.getFixB());
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_TEXCLAMP) {
|
||||
const float invW = 1.0f / (float)gstate_c.curTextureWidth;
|
||||
const float invH = 1.0f / (float)gstate_c.curTextureHeight;
|
||||
const int w = gstate.getTextureWidth(0);
|
||||
const int h = gstate.getTextureHeight(0);
|
||||
const float widthFactor = (float)w * invW;
|
||||
const float heightFactor = (float)h * invH;
|
||||
|
||||
// First wrap xy, then half texel xy (for clamp.)
|
||||
const float texclamp[4] = {
|
||||
widthFactor,
|
||||
heightFactor,
|
||||
invW * 0.5f,
|
||||
invH * 0.5f,
|
||||
};
|
||||
const float texclampoff[2] = {
|
||||
gstate_c.curTextureXOffset * invW,
|
||||
gstate_c.curTextureYOffset * invH,
|
||||
};
|
||||
CopyFloat4(ub_fragment.texClamp, texclamp);
|
||||
CopyFloat2(ub_fragment.texClampOffset, texclampoff);
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderManagerVulkan::VSUpdateUniforms(int dirtyUniforms) {
|
||||
// Update any dirty uniforms before we draw
|
||||
if (dirtyUniforms & DIRTY_PROJMATRIX) {
|
||||
Matrix4x4 flippedMatrix;
|
||||
memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float));
|
||||
|
||||
const bool invertedY = gstate_c.vpHeight < 0;
|
||||
if (!invertedY) {
|
||||
flippedMatrix[1] = -flippedMatrix[1];
|
||||
flippedMatrix[5] = -flippedMatrix[5];
|
||||
flippedMatrix[9] = -flippedMatrix[9];
|
||||
flippedMatrix[13] = -flippedMatrix[13];
|
||||
}
|
||||
const bool invertedX = gstate_c.vpWidth < 0;
|
||||
if (invertedX) {
|
||||
flippedMatrix[0] = -flippedMatrix[0];
|
||||
flippedMatrix[4] = -flippedMatrix[4];
|
||||
flippedMatrix[8] = -flippedMatrix[8];
|
||||
flippedMatrix[12] = -flippedMatrix[12];
|
||||
}
|
||||
|
||||
const bool invertedZ = gstate_c.vpDepthScale < 0;
|
||||
ConvertProjMatrixToVulkan(flippedMatrix, invertedX, invertedY, invertedZ);
|
||||
|
||||
CopyMatrix4x4(ub_transformCommon.proj, flippedMatrix.getReadPtr());
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) {
|
||||
Matrix4x4 proj_through;
|
||||
proj_through.setOrtho(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0, 0, 1);
|
||||
ConvertProjMatrixToVulkanThrough(proj_through);
|
||||
CopyMatrix4x4(ub_transformCommon.proj, proj_through.getReadPtr());
|
||||
}
|
||||
|
||||
// Transform
|
||||
if (dirtyUniforms & DIRTY_WORLDMATRIX) {
|
||||
ConvertMatrix4x3To4x4(ub_transformCommon.world, gstate.worldMatrix);
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_VIEWMATRIX) {
|
||||
ConvertMatrix4x3To4x4(ub_transformCommon.view, gstate.viewMatrix);
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_TEXMATRIX) {
|
||||
ConvertMatrix4x3To4x4(ub_transformCommon.tex, gstate.tgenMatrix);
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_FOGCOEF) {
|
||||
float fogcoef[2] = {
|
||||
getFloat24(gstate.fog1),
|
||||
getFloat24(gstate.fog2),
|
||||
};
|
||||
if (my_isinf(fogcoef[1])) {
|
||||
// not really sure what a sensible value might be.
|
||||
fogcoef[1] = fogcoef[1] < 0.0f ? -10000.0f : 10000.0f;
|
||||
} else if (my_isnan(fogcoef[1])) {
|
||||
// Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988
|
||||
// Just put the fog far away at a large finite distance.
|
||||
// Infinities and NaNs are rather unpredictable in shaders on many GPUs
|
||||
// so it's best to just make it a sane calculation.
|
||||
fogcoef[0] = 100000.0f;
|
||||
fogcoef[1] = 1.0f;
|
||||
}
|
||||
#ifndef MOBILE_DEVICE
|
||||
else if (my_isnanorinf(fogcoef[1]) || my_isnanorinf(fogcoef[0])) {
|
||||
ERROR_LOG_REPORT_ONCE(fognan, G3D, "Unhandled fog NaN/INF combo: %f %f", fogcoef[0], fogcoef[1]);
|
||||
}
|
||||
#endif
|
||||
CopyFloat2(ub_transformCommon.fogCoef, fogcoef);
|
||||
}
|
||||
// TODO: Could even set all bones in one go if they're all dirty.
|
||||
#ifdef USE_BONE_ARRAY
|
||||
if (u_bone != 0) {
|
||||
float allBones[8 * 16];
|
||||
|
||||
bool allDirty = true;
|
||||
for (int i = 0; i < numBones; i++) {
|
||||
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
|
||||
ConvertMatrix4x3To4x4(allBones + 16 * i, gstate.boneMatrix + 12 * i);
|
||||
} else {
|
||||
allDirty = false;
|
||||
}
|
||||
}
|
||||
if (allDirty) {
|
||||
// Set them all with one call
|
||||
//glUniformMatrix4fv(u_bone, numBones, GL_FALSE, allBones);
|
||||
} else {
|
||||
// Set them one by one. Could try to coalesce two in a row etc but too lazy.
|
||||
for (int i = 0; i < numBones; i++) {
|
||||
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
|
||||
//glUniformMatrix4fv(u_bone + i, 1, GL_FALSE, allBones + 16 * i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
|
||||
ConvertMatrix4x3To4x4(ub_bones.bones[i], gstate.boneMatrix + 12 * i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Texturing
|
||||
if (dirtyUniforms & DIRTY_UVSCALEOFFSET) {
|
||||
const float invW = 1.0f / (float)gstate_c.curTextureWidth;
|
||||
const float invH = 1.0f / (float)gstate_c.curTextureHeight;
|
||||
const int w = gstate.getTextureWidth(0);
|
||||
const int h = gstate.getTextureHeight(0);
|
||||
const float widthFactor = (float)w * invW;
|
||||
const float heightFactor = (float)h * invH;
|
||||
|
||||
float uvscaleoff[4];
|
||||
switch (gstate.getUVGenMode()) {
|
||||
case GE_TEXMAP_TEXTURE_COORDS:
|
||||
// Not sure what GE_TEXMAP_UNKNOWN is, but seen in Riviera. Treating the same as GE_TEXMAP_TEXTURE_COORDS works.
|
||||
case GE_TEXMAP_UNKNOWN:
|
||||
uvscaleoff[0] = gstate_c.uv.uScale * widthFactor;
|
||||
uvscaleoff[1] = gstate_c.uv.vScale * heightFactor;
|
||||
uvscaleoff[2] = gstate_c.uv.uOff * widthFactor;
|
||||
uvscaleoff[3] = gstate_c.uv.vOff * heightFactor;
|
||||
break;
|
||||
|
||||
// These two work the same whether or not we prescale UV.
|
||||
|
||||
case GE_TEXMAP_TEXTURE_MATRIX:
|
||||
// We cannot bake the UV coord scale factor in here, as we apply a matrix multiplication
|
||||
// before this is applied, and the matrix multiplication may contain translation. In this case
|
||||
// the translation will be scaled which breaks faces in Hexyz Force for example.
|
||||
// So I've gone back to applying the scale factor in the shader.
|
||||
uvscaleoff[0] = widthFactor;
|
||||
uvscaleoff[1] = heightFactor;
|
||||
uvscaleoff[2] = 0.0f;
|
||||
uvscaleoff[3] = 0.0f;
|
||||
break;
|
||||
|
||||
case GE_TEXMAP_ENVIRONMENT_MAP:
|
||||
// In this mode we only use uvscaleoff to scale to the texture size.
|
||||
uvscaleoff[0] = widthFactor;
|
||||
uvscaleoff[1] = heightFactor;
|
||||
uvscaleoff[2] = 0.0f;
|
||||
uvscaleoff[3] = 0.0f;
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG_REPORT(G3D, "Unexpected UV gen mode: %d", gstate.getUVGenMode());
|
||||
}
|
||||
CopyFloat4(ub_transformCommon.uvScaleOffset, uvscaleoff);
|
||||
}
|
||||
|
||||
if (dirtyUniforms & DIRTY_DEPTHRANGE) {
|
||||
float viewZScale = gstate.getViewportZScale();
|
||||
float viewZCenter = gstate.getViewportZCenter();
|
||||
|
||||
// Given the way we do the rounding, the integer part of the offset is probably mostly irrelevant as we cancel
|
||||
// it afterwards anyway.
|
||||
// It seems that we should adjust for D3D projection matrix. We got squashed up to only 0-1, so we divide
|
||||
// the scale factor by 2, and add an offset. But, this doesn't work! I get near-perfect results not doing it.
|
||||
// viewZScale *= 2.0f;
|
||||
|
||||
// Need to take the possibly inverted proj matrix into account.
|
||||
if (gstate_c.vpDepthScale < 0.0)
|
||||
viewZScale *= -1.0f;
|
||||
viewZCenter -= 32767.5f;
|
||||
float viewZInvScale;
|
||||
if (viewZScale != 0.0) {
|
||||
viewZInvScale = 1.0f / viewZScale;
|
||||
} else {
|
||||
viewZInvScale = 0.0;
|
||||
}
|
||||
|
||||
float data[4] = { viewZScale, viewZCenter, viewZCenter, viewZInvScale };
|
||||
CopyFloat4(ub_transformCommon.depthRange, data);
|
||||
}
|
||||
|
||||
// Lighting
|
||||
if (dirtyUniforms & DIRTY_AMBIENT) {
|
||||
Uint8x3ToFloat4_AlphaUint8(ub_lightGlobal.ambientColor, gstate.ambientcolor, gstate.getAmbientA());
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_MATAMBIENTALPHA) {
|
||||
// Note - this one is not in lighting but in transformCommon as it has uses beyond lighting
|
||||
Uint8x3ToFloat4_AlphaUint8(ub_transformCommon.matAmbient, gstate.materialambient, gstate.getMaterialAmbientA());
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_MATDIFFUSE) {
|
||||
Uint8x3ToFloat4(ub_lightGlobal.materialDiffuse, gstate.materialdiffuse);
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_MATEMISSIVE) {
|
||||
Uint8x3ToFloat4(ub_lightGlobal.materialEmissive, gstate.materialemissive);
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_MATSPECULAR) {
|
||||
Uint8x3ToFloat4_Alpha(ub_lightGlobal.materialEmissive, gstate.materialspecular, getFloat24(gstate.materialspecularcoef));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (dirtyUniforms & (DIRTY_LIGHT0 << i)) {
|
||||
if (gstate.isDirectionalLight(i)) {
|
||||
// Prenormalize
|
||||
float x = getFloat24(gstate.lpos[i * 3 + 0]);
|
||||
float y = getFloat24(gstate.lpos[i * 3 + 1]);
|
||||
float z = getFloat24(gstate.lpos[i * 3 + 2]);
|
||||
float len = sqrtf(x*x + y*y + z*z);
|
||||
if (len == 0.0f)
|
||||
len = 1.0f;
|
||||
else
|
||||
len = 1.0f / len;
|
||||
float vec[3] = { x * len, y * len, z * len };
|
||||
CopyFloat3To4(ub_lights.lpos[i], vec);
|
||||
} else {
|
||||
ExpandFloat24x3ToFloat4(ub_lights.lpos[i], &gstate.lpos[i * 3]);
|
||||
}
|
||||
ExpandFloat24x3ToFloat4(ub_lights.ldir[i], &gstate.ldir[i * 3]);
|
||||
ExpandFloat24x3ToFloat4(ub_lights.latt[i], &gstate.latt[i * 3]);
|
||||
CopyFloat1To4(ub_lights.lightAngle[i], getFloat24(gstate.lcutoff[i]));
|
||||
CopyFloat1To4(ub_lights.lightSpotCoef[i], getFloat24(gstate.lconv[i]));
|
||||
Uint8x3ToFloat4(ub_lights.lightAmbient[i], gstate.lcolor[i * 3]);
|
||||
Uint8x3ToFloat4(ub_lights.lightDiffuse[i], gstate.lcolor[i * 3 + 1]);
|
||||
Uint8x3ToFloat4(ub_lights.lightSpecular[i], gstate.lcolor[i * 3 + 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShaderManagerVulkan::ShaderManagerVulkan(VkDevice device) : device_(device), lastVShader_(nullptr), lastFShader_(nullptr), globalDirty_(0xFFFFFFFF) {
|
||||
codeBuffer_ = new char[16384];
|
||||
}
|
||||
|
||||
ShaderManagerVulkan::~ShaderManagerVulkan() {
|
||||
delete [] codeBuffer_;
|
||||
}
|
||||
|
||||
void ShaderManagerVulkan::Clear() {
|
||||
for (auto iter = fsCache_.begin(); iter != fsCache_.end(); ++iter) {
|
||||
delete iter->second;
|
||||
}
|
||||
for (auto iter = vsCache_.begin(); iter != vsCache_.end(); ++iter) {
|
||||
delete iter->second;
|
||||
}
|
||||
fsCache_.clear();
|
||||
vsCache_.clear();
|
||||
globalDirty_ = 0xFFFFFFFF;
|
||||
lastFSID_.clear();
|
||||
lastVSID_.clear();
|
||||
DirtyShader();
|
||||
}
|
||||
|
||||
void ShaderManagerVulkan::ClearCache(bool deleteThem) {
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
void ShaderManagerVulkan::DirtyShader() {
|
||||
// Forget the last shader ID
|
||||
lastFSID_.clear();
|
||||
lastVSID_.clear();
|
||||
lastVShader_ = nullptr;
|
||||
lastFShader_ = nullptr;
|
||||
globalDirty_ = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
void ShaderManagerVulkan::DirtyLastShader() { // disables vertex arrays
|
||||
lastVShader_ = nullptr;
|
||||
lastFShader_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader) {
|
||||
bool useHWTransform = CanUseHardwareTransform(prim);
|
||||
|
||||
ShaderID VSID;
|
||||
ComputeVertexShaderID(&VSID, vertType, useHWTransform);
|
||||
ShaderID FSID;
|
||||
ComputeFragmentShaderID(&FSID);
|
||||
|
||||
// Just update uniforms if this is the same shader as last time.
|
||||
if (lastVShader_ != nullptr && lastFShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) {
|
||||
if (globalDirty_) {
|
||||
PSUpdateUniforms(globalDirty_);
|
||||
VSUpdateUniforms(globalDirty_);
|
||||
globalDirty_ = 0;
|
||||
}
|
||||
*vshader = lastVShader_;
|
||||
*fshader = lastFShader_;
|
||||
// Already all set, no need to look up in shader maps.
|
||||
return;
|
||||
}
|
||||
|
||||
VSCache::iterator vsIter = vsCache_.find(VSID);
|
||||
VulkanVertexShader *vs;
|
||||
if (vsIter == vsCache_.end()) {
|
||||
// Vertex shader not in cache. Let's compile it.
|
||||
GenerateVulkanGLSLVertexShader(VSID, codeBuffer_);
|
||||
vs = new VulkanVertexShader(device_, VSID, codeBuffer_, vertType, useHWTransform);
|
||||
|
||||
if (vs->Failed()) {
|
||||
ERROR_LOG(HLE, "Shader compilation failed, falling back to software transform");
|
||||
osm.Show("hardware transform error - falling back to software", 2.5f, 0xFF3030FF, -1, true);
|
||||
delete vs;
|
||||
|
||||
ComputeVertexShaderID(&VSID, vertType, false);
|
||||
|
||||
// TODO: Look for existing shader with the appropriate ID, use that instead of generating a new one - however, need to make sure
|
||||
// that that shader ID is not used when computing the linked shader ID below, because then IDs won't match
|
||||
// next time and we'll do this over and over...
|
||||
|
||||
// Can still work with software transform.
|
||||
GenerateVulkanGLSLVertexShader(VSID, codeBuffer_);
|
||||
vs = new VulkanVertexShader(device_, VSID, codeBuffer_, vertType, false);
|
||||
}
|
||||
|
||||
vsCache_[VSID] = vs;
|
||||
} else {
|
||||
vs = vsIter->second;
|
||||
}
|
||||
lastVSID_ = VSID;
|
||||
|
||||
FSCache::iterator fsIter = fsCache_.find(FSID);
|
||||
VulkanFragmentShader *fs;
|
||||
if (fsIter == fsCache_.end()) {
|
||||
// Fragment shader not in cache. Let's compile it.
|
||||
GenerateVulkanGLSLFragmentShader(FSID, codeBuffer_);
|
||||
fs = new VulkanFragmentShader(device_, FSID, codeBuffer_, useHWTransform);
|
||||
fsCache_[FSID] = fs;
|
||||
} else {
|
||||
fs = fsIter->second;
|
||||
}
|
||||
|
||||
lastFSID_ = FSID;
|
||||
|
||||
if (globalDirty_) {
|
||||
PSUpdateUniforms(globalDirty_);
|
||||
VSUpdateUniforms(globalDirty_);
|
||||
globalDirty_ = 0;
|
||||
}
|
||||
*vshader = vs;
|
||||
*fshader = fs;
|
||||
}
|
||||
|
||||
std::vector<std::string> ShaderManagerVulkan::DebugGetShaderIDs(DebugShaderType type) {
|
||||
std::string id;
|
||||
std::vector<std::string> ids;
|
||||
switch (type) {
|
||||
case SHADER_TYPE_VERTEX:
|
||||
{
|
||||
for (auto iter : vsCache_) {
|
||||
iter.first.ToString(&id);
|
||||
ids.push_back(id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SHADER_TYPE_FRAGMENT:
|
||||
{
|
||||
for (auto iter : fsCache_) {
|
||||
iter.first.ToString(&id);
|
||||
ids.push_back(id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::string ShaderManagerVulkan::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
|
||||
ShaderID shaderId;
|
||||
shaderId.FromString(id);
|
||||
switch (type) {
|
||||
case SHADER_TYPE_VERTEX:
|
||||
{
|
||||
auto iter = vsCache_.find(shaderId);
|
||||
if (iter == vsCache_.end()) {
|
||||
return "";
|
||||
}
|
||||
return iter->second->GetShaderString(stringType);
|
||||
}
|
||||
|
||||
case SHADER_TYPE_FRAGMENT:
|
||||
{
|
||||
auto iter = fsCache_.find(shaderId);
|
||||
if (iter == fsCache_.end()) {
|
||||
return "";
|
||||
}
|
||||
return iter->second->GetShaderString(stringType);
|
||||
}
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
261
GPU/Vulkan/ShaderManagerVulkan.h
Normal file
261
GPU/Vulkan/ShaderManagerVulkan.h
Normal file
@ -0,0 +1,261 @@
|
||||
#pragma once
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "Globals.h"
|
||||
#include "GPU/Common/ShaderCommon.h"
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
#include "GPU/Vulkan/VertexShaderGeneratorVulkan.h"
|
||||
#include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h"
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
#include "math/lin/matrix4x4.h"
|
||||
|
||||
void ConvertProjMatrixToVulkan(Matrix4x4 & in);
|
||||
|
||||
// Pretty much full. Will need more bits for more fine grained dirty tracking for lights.
|
||||
enum {
|
||||
DIRTY_PROJMATRIX = (1 << 0),
|
||||
DIRTY_PROJTHROUGHMATRIX = (1 << 1),
|
||||
DIRTY_FOGCOLOR = (1 << 2),
|
||||
DIRTY_FOGCOEF = (1 << 3),
|
||||
DIRTY_TEXENV = (1 << 4),
|
||||
DIRTY_ALPHACOLORREF = (1 << 5),
|
||||
DIRTY_STENCILREPLACEVALUE = (1 << 6),
|
||||
|
||||
DIRTY_ALPHACOLORMASK = (1 << 7),
|
||||
DIRTY_LIGHT0 = (1 << 8),
|
||||
DIRTY_LIGHT1 = (1 << 9),
|
||||
DIRTY_LIGHT2 = (1 << 10),
|
||||
DIRTY_LIGHT3 = (1 << 11),
|
||||
|
||||
DIRTY_MATDIFFUSE = (1 << 12),
|
||||
DIRTY_MATSPECULAR = (1 << 13),
|
||||
DIRTY_MATEMISSIVE = (1 << 14),
|
||||
DIRTY_AMBIENT = (1 << 15),
|
||||
DIRTY_MATAMBIENTALPHA = (1 << 16),
|
||||
DIRTY_SHADERBLEND = (1 << 17), // Used only for in-shader blending.
|
||||
DIRTY_UVSCALEOFFSET = (1 << 18), // this will be dirtied ALL THE TIME... maybe we'll need to do "last value with this shader compares"
|
||||
DIRTY_TEXCLAMP = (1 << 19),
|
||||
|
||||
DIRTY_DEPTHRANGE = (1 << 20),
|
||||
|
||||
DIRTY_WORLDMATRIX = (1 << 21),
|
||||
DIRTY_VIEWMATRIX = (1 << 22), // Maybe we'll fold this into projmatrix eventually
|
||||
DIRTY_TEXMATRIX = (1 << 23),
|
||||
DIRTY_BONEMATRIX0 = (1 << 24),
|
||||
DIRTY_BONEMATRIX1 = (1 << 25),
|
||||
DIRTY_BONEMATRIX2 = (1 << 26),
|
||||
DIRTY_BONEMATRIX3 = (1 << 27),
|
||||
DIRTY_BONEMATRIX4 = (1 << 28),
|
||||
DIRTY_BONEMATRIX5 = (1 << 29),
|
||||
DIRTY_BONEMATRIX6 = (1 << 30),
|
||||
DIRTY_BONEMATRIX7 = (1 << 31),
|
||||
|
||||
DIRTY_ALL = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
struct UB_VS_TransformCommon {
|
||||
float proj[16];
|
||||
float view[16];
|
||||
float world[16];
|
||||
float tex[16]; // not that common, may want to break out
|
||||
float uvScaleOffset[4];
|
||||
float depthRange[4];
|
||||
float fogCoef[4];
|
||||
float matAmbient[4];
|
||||
};
|
||||
|
||||
static const char *ub_vs_transformCommonStr =
|
||||
R"(matrix4x4 proj;
|
||||
matrix4x4 view;
|
||||
matrix4x4 world;
|
||||
matrix4x4 tex;
|
||||
vec4 uvScaleOffset;
|
||||
vec4 depthRange;
|
||||
vec2 fogCoef;
|
||||
vec4 matAmbient;
|
||||
)";
|
||||
|
||||
struct UB_VS_Lights {
|
||||
float lpos[4][4];
|
||||
float ldir[4][4];
|
||||
float latt[4][4];
|
||||
float lightAngle[4][4]; // TODO: Merge with lightSpotCoef, use .xy
|
||||
float lightSpotCoef[4][4];
|
||||
float lightAmbient[4][4];
|
||||
float lightDiffuse[4][4];
|
||||
float lightSpecular[4][4];
|
||||
};
|
||||
|
||||
static const char *ub_vs_lightsStr =
|
||||
R"(vec3 lpos[4];
|
||||
vec3 ldir[4];
|
||||
vec3 latt[4];
|
||||
float lightAngle[4];
|
||||
float lightSpotCoef[4];
|
||||
vec3 lightAmbient[4];
|
||||
vec3 lightDiffuse[4];
|
||||
vec3 lightSpecular[4];
|
||||
)";
|
||||
|
||||
struct UB_VS_LightGlobal {
|
||||
float ambientColor[4];
|
||||
float materialDiffuse[4];
|
||||
float materialSpecular[4];
|
||||
float materialEmissive[4];
|
||||
};
|
||||
|
||||
static const char *ub_vs_lightsGlobalStr =
|
||||
R"(vec3 ambientColor;
|
||||
vec3 materialDiffuse;
|
||||
vec4 materialSpecular;
|
||||
vec3 materialEmissive;
|
||||
)";
|
||||
|
||||
struct UB_VS_Bones {
|
||||
float bones[8][16];
|
||||
};
|
||||
|
||||
static const char *ub_vs_bonesStr =
|
||||
R"(matrix4x4 bone[8];
|
||||
)";
|
||||
|
||||
// Let's not bother splitting this, we'll just upload the lot for every draw call.
|
||||
struct UB_FS_All {
|
||||
float fogColor[4];
|
||||
float texEnvColor[4];
|
||||
float alphaColorRef[4];
|
||||
float colorTestMask[4];
|
||||
float stencilReplace[4]; // only first float used
|
||||
float blendFixA[4];
|
||||
float blendFixB[4];
|
||||
float texClamp[4];
|
||||
float texClampOffset[4];
|
||||
};
|
||||
|
||||
static const char *ub_fs_allStr =
|
||||
R"(
|
||||
vec3 fogColor;
|
||||
vec3 texenv;
|
||||
vec4 alphaColorRef;
|
||||
vec3 colorTestMask;
|
||||
float stencilReplace;
|
||||
vec3 blendFixA;
|
||||
vec3 blendFixB;
|
||||
vec4 texClamp;
|
||||
vec2 texClampOffset;
|
||||
)";
|
||||
|
||||
class VulkanFragmentShader {
|
||||
public:
|
||||
VulkanFragmentShader(VkDevice device, ShaderID id, const char *code, bool useHWTransform);
|
||||
~VulkanFragmentShader();
|
||||
|
||||
const std::string &source() const { return source_; }
|
||||
|
||||
bool Failed() const { return failed_; }
|
||||
bool UseHWTransform() const { return useHWTransform_; }
|
||||
|
||||
std::string GetShaderString(DebugShaderStringType type) const;
|
||||
|
||||
protected:
|
||||
VkShaderModule module_;
|
||||
|
||||
VkDevice device_;
|
||||
std::string source_;
|
||||
bool failed_;
|
||||
bool useHWTransform_;
|
||||
ShaderID id_;
|
||||
};
|
||||
|
||||
class VulkanVertexShader {
|
||||
public:
|
||||
VulkanVertexShader(VkDevice device, ShaderID id, const char *code, int vertType, bool useHWTransform);
|
||||
~VulkanVertexShader();
|
||||
|
||||
const std::string &source() const { return source_; }
|
||||
|
||||
bool Failed() const { return failed_; }
|
||||
bool UseHWTransform() const { return useHWTransform_; }
|
||||
|
||||
std::string GetShaderString(DebugShaderStringType type) const;
|
||||
|
||||
protected:
|
||||
VkShaderModule module_;
|
||||
|
||||
VkDevice device_;
|
||||
std::string source_;
|
||||
bool failed_;
|
||||
bool useHWTransform_;
|
||||
ShaderID id_;
|
||||
};
|
||||
|
||||
class ShaderManagerVulkan {
|
||||
public:
|
||||
ShaderManagerVulkan(VkDevice device);
|
||||
~ShaderManagerVulkan();
|
||||
|
||||
void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected
|
||||
void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader);
|
||||
|
||||
void DirtyShader();
|
||||
void DirtyUniform(u32 what) {
|
||||
globalDirty_ |= what;
|
||||
}
|
||||
void DirtyLastShader();
|
||||
|
||||
int NumVertexShaders() const { return (int)vsCache_.size(); }
|
||||
int NumFragmentShaders() const { return (int)fsCache_.size(); }
|
||||
|
||||
std::vector<std::string> DebugGetShaderIDs(DebugShaderType type);
|
||||
std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
|
||||
|
||||
private:
|
||||
void PSUpdateUniforms(int dirtyUniforms);
|
||||
void VSUpdateUniforms(int dirtyUniforms);
|
||||
|
||||
void Clear();
|
||||
|
||||
VkDevice device_;
|
||||
|
||||
u32 globalDirty_;
|
||||
char *codeBuffer_;
|
||||
|
||||
// Uniform block scratchpad. These (the relevant ones) are copied to the current pushbuffer at draw time.
|
||||
UB_VS_TransformCommon ub_transformCommon;
|
||||
UB_VS_LightGlobal ub_lightGlobal;
|
||||
UB_VS_Lights ub_lights;
|
||||
UB_VS_Bones ub_bones;
|
||||
UB_FS_All ub_fragment;
|
||||
|
||||
typedef std::map<ShaderID, VulkanFragmentShader *> FSCache;
|
||||
FSCache fsCache_;
|
||||
|
||||
typedef std::map<ShaderID, VulkanVertexShader *> VSCache;
|
||||
VSCache vsCache_;
|
||||
|
||||
VulkanFragmentShader *lastFShader_;
|
||||
VulkanVertexShader *lastVShader_;
|
||||
|
||||
ShaderID lastFSID_;
|
||||
ShaderID lastVSID_;
|
||||
};
|
314
GPU/Vulkan/StateMappingVulkan.cpp
Normal file
314
GPU/Vulkan/StateMappingVulkan.cpp
Normal file
@ -0,0 +1,314 @@
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#define VK_PROTOTYPES
|
||||
#include "ext/vulkan/vulkan.h"
|
||||
|
||||
#include "GPU/Math3D.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/ge_constants.h"
|
||||
#include "GPU/Common/GPUStateUtils.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/Reporting.h"
|
||||
//#include "GPU/Vulkan/StateMappingVulkan.h"
|
||||
#include "GPU/Vulkan/GPU_Vulkan.h"
|
||||
#include "GPU/Vulkan/PipelineManagerVulkan.h"
|
||||
#include "GPU/Vulkan/TextureCacheVulkan.h"
|
||||
#include "GPU/Vulkan/FramebufferVulkan.h"
|
||||
//#include "GPU/Vulkan/PixelShaderGeneratorVulkan.h"
|
||||
|
||||
static const VkBlendFactor vkBlendFactorLookup[(size_t)BlendFactor::COUNT] = {
|
||||
VK_BLEND_FACTOR_ZERO,
|
||||
VK_BLEND_FACTOR_ONE,
|
||||
VK_BLEND_FACTOR_SRC_COLOR,
|
||||
VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
|
||||
VK_BLEND_FACTOR_DST_COLOR,
|
||||
VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
|
||||
VK_BLEND_FACTOR_SRC_ALPHA,
|
||||
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
VK_BLEND_FACTOR_DST_ALPHA,
|
||||
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
|
||||
VK_BLEND_FACTOR_CONSTANT_COLOR,
|
||||
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
|
||||
VK_BLEND_FACTOR_CONSTANT_ALPHA,
|
||||
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
|
||||
VK_BLEND_FACTOR_SRC1_COLOR,
|
||||
VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
|
||||
VK_BLEND_FACTOR_MAX_ENUM,
|
||||
};
|
||||
|
||||
static const VkBlendOp vkBlendEqLookup[(size_t)BlendEq::COUNT] = {
|
||||
VK_BLEND_OP_ADD,
|
||||
VK_BLEND_OP_SUBTRACT,
|
||||
VK_BLEND_OP_REVERSE_SUBTRACT,
|
||||
VK_BLEND_OP_MIN,
|
||||
VK_BLEND_OP_MAX,
|
||||
};
|
||||
|
||||
static const VkCullModeFlagBits cullingMode[] = {
|
||||
VK_CULL_MODE_BACK_BIT,
|
||||
VK_CULL_MODE_FRONT_BIT,
|
||||
};
|
||||
|
||||
static const VkCompareOp compareOps[] = {
|
||||
VK_COMPARE_OP_NEVER,
|
||||
VK_COMPARE_OP_ALWAYS,
|
||||
VK_COMPARE_OP_EQUAL,
|
||||
VK_COMPARE_OP_NOT_EQUAL,
|
||||
VK_COMPARE_OP_LESS,
|
||||
VK_COMPARE_OP_LESS_OR_EQUAL,
|
||||
VK_COMPARE_OP_GREATER,
|
||||
VK_COMPARE_OP_GREATER_OR_EQUAL,
|
||||
};
|
||||
|
||||
static const VkStencilOp stencilOps[] = {
|
||||
VK_STENCIL_OP_KEEP,
|
||||
VK_STENCIL_OP_ZERO,
|
||||
VK_STENCIL_OP_REPLACE,
|
||||
VK_STENCIL_OP_INVERT,
|
||||
VK_STENCIL_OP_INCREMENT_AND_CLAMP,
|
||||
VK_STENCIL_OP_DECREMENT_AND_CLAMP,
|
||||
VK_STENCIL_OP_KEEP, // reserved
|
||||
VK_STENCIL_OP_KEEP, // reserved
|
||||
};
|
||||
|
||||
struct VulkanDynamicState {
|
||||
VkViewport viewport;
|
||||
VkRect2D scissor;
|
||||
bool useBlendColor;
|
||||
uint32_t blendColor;
|
||||
bool useStencil;
|
||||
uint8_t stencilRef;
|
||||
uint8_t stencilWriteMask;
|
||||
uint8_t stencilCompareMask;
|
||||
};
|
||||
|
||||
bool ApplyShaderBlending() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ResetShaderBlending() {
|
||||
//
|
||||
}
|
||||
|
||||
// TODO: Do this more progressively. No need to compute the entire state if the entire state hasn't changed.
|
||||
// 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 ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &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);
|
||||
|
||||
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) {
|
||||
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) {
|
||||
//shaderManager_->DirtyUniform(DIRTY_SHADERBLEND);
|
||||
}
|
||||
dynState.useBlendColor = blendState.useBlendColor;
|
||||
if (blendState.useBlendColor) {
|
||||
dynState.blendColor = blendState.blendColor;
|
||||
}
|
||||
} else {
|
||||
key.blendEnable = false;
|
||||
dynState.useBlendColor = false;
|
||||
}
|
||||
|
||||
dynState.useStencil = false;
|
||||
|
||||
// Set ColorMask/Stencil/Depth
|
||||
if (gstate.isModeClear()) {
|
||||
key.cullMode = VK_CULL_MODE_NONE;
|
||||
|
||||
key.depthTestEnable = true;
|
||||
key.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
key.depthWriteEnable = gstate.isClearModeDepthMask();
|
||||
if (gstate.isClearModeDepthMask()) {
|
||||
// framebufferManager_->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_A_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;
|
||||
// TODO: Are these right?
|
||||
dynState.useStencil = true;
|
||||
dynState.stencilRef = 0xFF;
|
||||
dynState.stencilCompareMask = 0xFF;
|
||||
dynState.stencilWriteMask = 0xFF;
|
||||
} else {
|
||||
key.stencilTestEnable = false;
|
||||
}
|
||||
|
||||
} 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;
|
||||
|
||||
// Depth Test
|
||||
if (gstate.isDepthTestEnabled()) {
|
||||
key.depthTestEnable = true;
|
||||
key.depthCompareOp = compareOps[gstate.getDepthTestFunction()];
|
||||
key.depthWriteEnable = gstate.isDepthWriteEnabled();
|
||||
if (gstate.isDepthWriteEnabled()) {
|
||||
// framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
} else {
|
||||
key.depthTestEnable = false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
u8 abits = (gstate.pmska >> 0) & 0xFF;
|
||||
#ifndef MOBILE_DEVICE
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Stencil Test
|
||||
if (gstate.isStencilTestEnabled()) {
|
||||
key.stencilTestEnable = true;
|
||||
key.stencilCompareOp = compareOps[gstate.getStencilTestFunction()];
|
||||
dynState.stencilRef = gstate.getStencilTestRef();
|
||||
dynState.stencilCompareMask = gstate.getStencilTestMask();
|
||||
key.stencilFailOp = stencilOps[gstate.getStencilOpSFail()]; // stencil fail
|
||||
key.stencilDepthFailOp = stencilOps[gstate.getStencilOpZFail()]; // depth fail
|
||||
key.stencilPassOp = stencilOps[gstate.getStencilOpZPass()]; // depth pass
|
||||
dynState.stencilWriteMask = ~abits;
|
||||
} else {
|
||||
key.stencilTestEnable = false;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
// shaderManager_->DirtyUniform(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 (!gstate.isModeThrough()) {
|
||||
// Direct3D can't handle negative depth ranges, so we fix it in the projection matrix.
|
||||
if (gstate_c.vpDepthScale != depthMax - depthMin) {
|
||||
gstate_c.vpDepthScale = depthMax - depthMin;
|
||||
vpAndScissor.dirtyProj = true;
|
||||
}
|
||||
if (depthMin > depthMax) {
|
||||
std::swap(depthMin, depthMax);
|
||||
}
|
||||
if (depthMin < 0.0f) depthMin = 0.0f;
|
||||
if (depthMax > 1.0f) depthMax = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
//void DrawEngineVulkan::ApplyDrawStateLate() {
|
||||
/*
|
||||
// At this point, we know if the vertices are full alpha or not.
|
||||
// TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)?
|
||||
if (!gstate.isModeClear()) {
|
||||
// TODO: Test texture?
|
||||
|
||||
textureCache_->ApplyTexture();
|
||||
|
||||
if (fboTexNeedBind_) {
|
||||
// Note that this is positions, not UVs, that we need the copy from.
|
||||
framebufferManager_->BindFramebufferColor(1, nullptr, BINDFBCOLOR_MAY_COPY);
|
||||
// If we are rendering at a higher resolution, linear is probably best for the dest color.
|
||||
pD3Ddevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
pD3Ddevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
fboTexBound_ = true;
|
||||
fboTexNeedBind_ = false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
//}
|
42
GPU/Vulkan/TextureCacheVulkan.h
Normal file
42
GPU/Vulkan/TextureCacheVulkan.h
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GPU/Common/TextureCacheCommon.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
class TextureCacheVulkan : public TextureCacheCommon {
|
||||
public:
|
||||
bool SetOffsetTexture(u32 offset) override {
|
||||
return false;
|
||||
}
|
||||
bool DecodeTexture(u8 *dest, const GPUgstate &state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset = 0) override {
|
||||
return false;
|
||||
}
|
||||
void DetachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer) override {
|
||||
|
||||
}
|
||||
|
||||
void DownloadFramebufferForClut(u32 clutAddr, u32 bytes) override {
|
||||
|
||||
}
|
||||
};
|
618
GPU/Vulkan/VertexShaderGeneratorVulkan.cpp
Normal file
618
GPU/Vulkan/VertexShaderGeneratorVulkan.cpp
Normal file
@ -0,0 +1,618 @@
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <locale.h>
|
||||
|
||||
#include "gfx_es2/gpu_features.h"
|
||||
|
||||
#if defined(_WIN32) && defined(_DEBUG)
|
||||
#include "Common/CommonWindows.h"
|
||||
#endif
|
||||
|
||||
#include "base/stringutil.h"
|
||||
#include "GPU/ge_constants.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
#include "GPU/Common/VertexDecoderCommon.h"
|
||||
#include "GPU/Vulkan/VertexShaderGeneratorVulkan.h"
|
||||
#include "GPU/Vulkan/PipelineManagerVulkan.h"
|
||||
|
||||
// "Varying" layout - must match fragment shader
|
||||
// color0 = 0
|
||||
// color1 = 1
|
||||
// texcoord = 2
|
||||
// fog = 3
|
||||
|
||||
|
||||
|
||||
|
||||
// SDL 1.2 on Apple does not have support for OpenGL 3 and hence needs
|
||||
// special treatment in the shader generator.
|
||||
#ifdef __APPLE__
|
||||
#define FORCE_OPENGL_2_0
|
||||
#endif
|
||||
|
||||
#undef WRITE
|
||||
|
||||
#define WRITE p+=sprintf
|
||||
|
||||
static const char * const boneWeightDecl[9] = {
|
||||
"#ERROR#",
|
||||
"layout(location = 0) in mediump float w1;\n",
|
||||
"layout(location = 0) in mediump vec2 w1;\n",
|
||||
"layout(location = 0) in mediump vec3 w1;\n",
|
||||
"layout(location = 0) in mediump vec4 w1;\n",
|
||||
"layout(location = 0) in mediump vec4 w1;\nin mediump float w2;\n",
|
||||
"layout(location = 0) in mediump vec4 w1;\nin mediump vec2 w2;\n",
|
||||
"layout(location = 0) in mediump vec4 w1;\nin mediump vec3 w2;\n",
|
||||
"layout(location = 0) in mediump vec4 w1, w2;\n",
|
||||
};
|
||||
|
||||
enum DoLightComputation {
|
||||
LIGHT_OFF,
|
||||
LIGHT_SHADE,
|
||||
LIGHT_FULL,
|
||||
};
|
||||
|
||||
|
||||
// Depth range and viewport
|
||||
//
|
||||
// After the multiplication with the projection matrix, we have a 4D vector in clip space.
|
||||
// In OpenGL, Z is from -1 to 1, while in D3D, Z is from 0 to 1.
|
||||
// PSP appears to use the OpenGL convention. As Z is from -1 to 1, and the viewport is represented
|
||||
// by a center and a scale, to find the final Z value, all we need to do is to multiply by ZScale and
|
||||
// add ZCenter - these are properly scaled to directly give a Z value in [0, 65535].
|
||||
//
|
||||
// z = vec.z * ViewportZScale + ViewportZCenter;
|
||||
//
|
||||
// That will give us the final value between 0 and 65535, which we can simply floor to simulate
|
||||
// the limited precision of the PSP's depth buffer. Then we convert it back:
|
||||
// z = floor(z);
|
||||
//
|
||||
// vec.z = (z - ViewportZCenter) / ViewportZScale;
|
||||
//
|
||||
// Now, the regular machinery will take over and do the calculation again.
|
||||
//
|
||||
// All this above is for full transform mode.
|
||||
// In through mode, the Z coordinate just goes straight through and there is no perspective division.
|
||||
// We simulate this of course with pretty much an identity matrix. Rounding Z becomes very easy.
|
||||
//
|
||||
// TODO: Skip all this if we can actually get a 16-bit depth buffer along with stencil, which
|
||||
// is a bit of a rare configuration, although quite common on mobile.
|
||||
|
||||
bool GenerateVulkanGLSLVertexShader(const ShaderID &id, char *buffer) {
|
||||
char *p = buffer;
|
||||
|
||||
// #define USE_FOR_LOOP
|
||||
|
||||
bool highpFog = false;
|
||||
bool highpTexcoord = false;
|
||||
|
||||
const char *attribute = "in";
|
||||
const char *varying = "out";
|
||||
|
||||
bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH);
|
||||
bool lmode = id.Bit(VS_BIT_LMODE) && !isModeThrough; // TODO: Different expression than in shaderIDgen
|
||||
bool doTexture = id.Bit(VS_BIT_DO_TEXTURE);
|
||||
bool doTextureProjection = id.Bit(VS_BIT_DO_TEXTURE_PROJ);
|
||||
|
||||
GETexMapMode uvGenMode = static_cast<GETexMapMode>(id.Bits(VS_BIT_UVGEN_MODE, 2));
|
||||
|
||||
// this is only valid for some settings of uvGenMode
|
||||
GETexProjMapMode uvProjMode = static_cast<GETexProjMapMode>(id.Bits(VS_BIT_UVPROJ_MODE, 2));
|
||||
bool doShadeMapping = uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP;
|
||||
bool doFlatShading = id.Bit(VS_BIT_FLATSHADE);
|
||||
|
||||
bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM);
|
||||
bool hasColor = id.Bit(VS_BIT_HAS_COLOR) || !useHWTransform;
|
||||
bool hasNormal = id.Bit(VS_BIT_HAS_NORMAL) && useHWTransform;
|
||||
bool hasTexcoord = id.Bit(VS_BIT_HAS_TEXCOORD) || !useHWTransform;
|
||||
bool enableFog = id.Bit(VS_BIT_ENABLE_FOG);
|
||||
bool throughmode = id.Bit(VS_BIT_IS_THROUGH);
|
||||
bool flipNormal = id.Bit(VS_BIT_NORM_REVERSE);
|
||||
int ls0 = id.Bits(VS_BIT_LS0, 2);
|
||||
int ls1 = id.Bits(VS_BIT_LS1, 2);
|
||||
bool enableBones = id.Bit(VS_BIT_ENABLE_BONES);
|
||||
bool enableLighting = id.Bit(VS_BIT_LIGHTING_ENABLE);
|
||||
int matUpdate = id.Bits(VS_BIT_MATERIAL_UPDATE, 3);
|
||||
|
||||
const char *shading = doFlatShading ? "flat " : "";
|
||||
|
||||
DoLightComputation doLight[4] = { LIGHT_OFF, LIGHT_OFF, LIGHT_OFF, LIGHT_OFF };
|
||||
if (useHWTransform) {
|
||||
int shadeLight0 = doShadeMapping ? ls0 : -1;
|
||||
int shadeLight1 = doShadeMapping ? ls1 : -1;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i == shadeLight0 || i == shadeLight1)
|
||||
doLight[i] = LIGHT_SHADE;
|
||||
if (id.Bit(VS_BIT_LIGHTING_ENABLE) && id.Bit(VS_BIT_LIGHT0_ENABLE + i))
|
||||
doLight[i] = LIGHT_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
int numBoneWeights = 0;
|
||||
int boneWeightScale = id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2);
|
||||
if (enableBones) {
|
||||
numBoneWeights = 1 + id.Bits(VS_BIT_BONES, 3);
|
||||
WRITE(p, "%s", boneWeightDecl[numBoneWeights]);
|
||||
}
|
||||
int texFmtScale = id.Bits(VS_BIT_TEXCOORD_FMTSCALE, 2);
|
||||
|
||||
if (useHWTransform)
|
||||
WRITE(p, "layout (location = %d) in vec3 position;\n", PspAttributeLocation::POSITION);
|
||||
else
|
||||
WRITE(p, "layout (location = %d) vec4 position;\n", PspAttributeLocation::POSITION); // need to pass the fog coord in w
|
||||
|
||||
if (useHWTransform && hasNormal)
|
||||
WRITE(p, "layout (location = %d) mediump vec3 normal;\n", PspAttributeLocation::NORMAL);
|
||||
|
||||
if (doTexture && hasTexcoord) {
|
||||
if (!useHWTransform && doTextureProjection && !throughmode)
|
||||
WRITE(p, "layout (location = %d) in vec3 texcoord;\n", PspAttributeLocation::TEXCOORD);
|
||||
else
|
||||
WRITE(p, "layout (location = %d) in vec2 texcoord;\n", PspAttributeLocation::TEXCOORD);
|
||||
}
|
||||
if (hasColor) {
|
||||
WRITE(p, "layout (location = %d) lowp vec4 color0;\n", PspAttributeLocation::COLOR0);
|
||||
if (lmode && !useHWTransform) // only software transform supplies color1 as vertex data
|
||||
WRITE(p, "layout (location = %d) lowp vec3 color1;\n", PspAttributeLocation::COLOR0);
|
||||
}
|
||||
|
||||
// The uniforms are passed in as three "clumps" that may or may not be present.
|
||||
// We will memcpy the parts into place in a big buffer so we can be quite dynamic about what parts
|
||||
// are present and what parts aren't, but we will not be ultra detailed about it.
|
||||
|
||||
// WRITE(p, )
|
||||
|
||||
|
||||
if (isModeThrough) {
|
||||
WRITE(p, "uniform mat4 u_proj_through;\n");
|
||||
} else {
|
||||
WRITE(p, "uniform mat4 u_proj;\n");
|
||||
// Add all the uniforms we'll need to transform properly.
|
||||
}
|
||||
|
||||
bool prescale = false;
|
||||
|
||||
if (useHWTransform) {
|
||||
// When transforming by hardware, we need a great deal more uniforms...
|
||||
WRITE(p, "uniform mat4 u_world;\n");
|
||||
WRITE(p, "uniform mat4 u_view;\n");
|
||||
if (doTextureProjection)
|
||||
WRITE(p, "uniform mediump mat4 u_texmtx;\n");
|
||||
if (enableBones) {
|
||||
#ifdef USE_BONE_ARRAY
|
||||
WRITE(p, "uniform mediump mat4 u_bone[%i];\n", numBoneWeights);
|
||||
#else
|
||||
for (int i = 0; i < numBoneWeights; i++) {
|
||||
WRITE(p, "uniform mat4 u_bone%i;\n", i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (doTexture && (!prescale || uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP || uvGenMode == GE_TEXMAP_TEXTURE_MATRIX)) {
|
||||
WRITE(p, "uniform vec4 u_uvscaleoffset;\n");
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (doLight[i] != LIGHT_OFF) {
|
||||
// This is needed for shade mapping
|
||||
WRITE(p, "uniform vec3 u_lightpos%i;\n", i);
|
||||
}
|
||||
if (doLight[i] == LIGHT_FULL) {
|
||||
GELightType type = static_cast<GELightType>(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2));
|
||||
GELightComputation comp = static_cast<GELightComputation>(id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2));
|
||||
|
||||
if (type != GE_LIGHTTYPE_DIRECTIONAL)
|
||||
WRITE(p, "uniform mediump vec3 u_lightatt%i;\n", i);
|
||||
|
||||
if (type == GE_LIGHTTYPE_SPOT || type == GE_LIGHTTYPE_UNKNOWN) {
|
||||
WRITE(p, "uniform mediump vec3 u_lightdir%i;\n", i);
|
||||
WRITE(p, "uniform mediump float u_lightangle%i;\n", i);
|
||||
WRITE(p, "uniform mediump float u_lightspotCoef%i;\n", i);
|
||||
}
|
||||
WRITE(p, "uniform lowp vec3 u_lightambient%i;\n", i);
|
||||
WRITE(p, "uniform lowp vec3 u_lightdiffuse%i;\n", i);
|
||||
|
||||
if (comp != GE_LIGHTCOMP_ONLYDIFFUSE) {
|
||||
WRITE(p, "uniform lowp vec3 u_lightspecular%i;\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (enableLighting) {
|
||||
WRITE(p, "uniform lowp vec4 u_ambient;\n");
|
||||
if ((matUpdate & 2) == 0 || !hasColor)
|
||||
WRITE(p, "uniform lowp vec3 u_matdiffuse;\n");
|
||||
WRITE(p, "uniform lowp vec4 u_matspecular;\n"); // Specular coef is contained in alpha
|
||||
WRITE(p, "uniform lowp vec3 u_matemissive;\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (useHWTransform || !hasColor)
|
||||
WRITE(p, "uniform lowp vec4 u_matambientalpha;\n"); // matambient + matalpha
|
||||
|
||||
if (enableFog) {
|
||||
WRITE(p, "uniform highp vec2 u_fogcoef;\n");
|
||||
}
|
||||
|
||||
if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, "uniform highp vec4 u_depthRange;\n");
|
||||
}
|
||||
|
||||
WRITE(p, "layout (location = 1) %s out lowp vec4 v_color0;\n", shading);
|
||||
if (lmode) {
|
||||
WRITE(p, "layout (location = 2) %s out lowp vec3 v_color1;\n", shading);
|
||||
}
|
||||
|
||||
if (doTexture) {
|
||||
if (doTextureProjection) {
|
||||
WRITE(p, "layout (location = 0) %s out vec3 v_texcoord;\n", highpTexcoord ? "highp" : "mediump");
|
||||
} else {
|
||||
WRITE(p, "layout (location = 0) %s out vec2 v_texcoord;\n", highpTexcoord ? "highp" : "mediump");
|
||||
}
|
||||
}
|
||||
|
||||
if (enableFog) {
|
||||
// See the fragment shader generator
|
||||
WRITE(p, "layout (location = 3) %s out float v_fogdepth;\n", highpFog ? "highp" : "mediump");
|
||||
}
|
||||
|
||||
// See comment above this function (GenerateVertexShader).
|
||||
if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||
// Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection.
|
||||
WRITE(p, "\nvec4 depthRoundZVP(vec4 v) {\n");
|
||||
WRITE(p, " float z = v.z / v.w;\n");
|
||||
WRITE(p, " z = z * u_depthRange.x + u_depthRange.y;\n");
|
||||
WRITE(p, " z = floor(z);\n");
|
||||
WRITE(p, " z = (z - u_depthRange.z) * u_depthRange.w;\n");
|
||||
WRITE(p, " return vec4(v.x, v.y, z * v.w, v.w);\n");
|
||||
WRITE(p, "}\n\n");
|
||||
}
|
||||
|
||||
WRITE(p, "void main() {\n");
|
||||
|
||||
if (!useHWTransform) {
|
||||
// Simple pass-through of vertex data to fragment shader
|
||||
if (doTexture) {
|
||||
if (throughmode && doTextureProjection) {
|
||||
WRITE(p, " v_texcoord = vec3(texcoord, 1.0);\n");
|
||||
} else {
|
||||
WRITE(p, " v_texcoord = texcoord;\n");
|
||||
}
|
||||
}
|
||||
if (hasColor) {
|
||||
WRITE(p, " v_color0 = color0;\n");
|
||||
if (lmode)
|
||||
WRITE(p, " v_color1 = color1;\n");
|
||||
} else {
|
||||
WRITE(p, " v_color0 = u_matambientalpha;\n");
|
||||
if (lmode)
|
||||
WRITE(p, " v_color1 = vec3(0.0);\n");
|
||||
}
|
||||
if (enableFog) {
|
||||
WRITE(p, " v_fogdepth = position.w;\n");
|
||||
}
|
||||
if (isModeThrough) {
|
||||
WRITE(p, " gl_Position = u_proj_through * vec4(position.xyz, 1.0);\n");
|
||||
} else {
|
||||
// The viewport is used in this case, so need to compensate for that.
|
||||
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, " gl_Position = depthRoundZVP(u_proj * vec4(position.xyz, 1.0));\n");
|
||||
} else {
|
||||
WRITE(p, " gl_Position = u_proj * vec4(position.xyz, 1.0);\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Step 1: World Transform / Skinning
|
||||
if (!enableBones) {
|
||||
// No skinning, just standard T&L.
|
||||
WRITE(p, " vec3 worldpos = (u_world * vec4(position.xyz, 1.0)).xyz;\n");
|
||||
if (hasNormal)
|
||||
WRITE(p, " mediump vec3 worldnormal = normalize((u_world * vec4(%snormal, 0.0)).xyz);\n", flipNormal ? "-" : "");
|
||||
else
|
||||
WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n");
|
||||
} else {
|
||||
static const char *rescale[4] = { "", " * 1.9921875", " * 1.999969482421875", "" }; // 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f};
|
||||
const char *factor = rescale[boneWeightScale];
|
||||
|
||||
static const char * const boneWeightAttr[8] = {
|
||||
"w1.x", "w1.y", "w1.z", "w1.w",
|
||||
"w2.x", "w2.y", "w2.z", "w2.w",
|
||||
};
|
||||
|
||||
#if defined(USE_FOR_LOOP) && defined(USE_BONE_ARRAY)
|
||||
|
||||
// To loop through the weights, we unfortunately need to put them in a float array.
|
||||
// GLSL ES sucks - no way to directly initialize an array!
|
||||
switch (numBoneWeights) {
|
||||
case 1: WRITE(p, " float w[1]; w[0] = w1;\n"); break;
|
||||
case 2: WRITE(p, " float w[2]; w[0] = w1.x; w[1] = w1.y;\n"); break;
|
||||
case 3: WRITE(p, " float w[3]; w[0] = w1.x; w[1] = w1.y; w[2] = w1.z;\n"); break;
|
||||
case 4: WRITE(p, " float w[4]; w[0] = w1.x; w[1] = w1.y; w[2] = w1.z; w[3] = w1.w;\n"); break;
|
||||
case 5: WRITE(p, " float w[5]; w[0] = w1.x; w[1] = w1.y; w[2] = w1.z; w[3] = w1.w; w[4] = w2;\n"); break;
|
||||
case 6: WRITE(p, " float w[6]; w[0] = w1.x; w[1] = w1.y; w[2] = w1.z; w[3] = w1.w; w[4] = w2.x; w[5] = w2.y;\n"); break;
|
||||
case 7: WRITE(p, " float w[7]; w[0] = w1.x; w[1] = w1.y; w[2] = w1.z; w[3] = w1.w; w[4] = w2.x; w[5] = w2.y; w[6] = w2.z;\n"); break;
|
||||
case 8: WRITE(p, " float w[8]; w[0] = w1.x; w[1] = w1.y; w[2] = w1.z; w[3] = w1.w; w[4] = w2.x; w[5] = w2.y; w[6] = w2.z; w[7] = w2.w;\n"); break;
|
||||
}
|
||||
|
||||
WRITE(p, " mat4 skinMatrix = w[0] * u_bone[0];\n");
|
||||
if (numBoneWeights > 1) {
|
||||
WRITE(p, " for (int i = 1; i < %i; i++) {\n", numBoneWeights);
|
||||
WRITE(p, " skinMatrix += w[i] * u_bone[i];\n");
|
||||
WRITE(p, " }\n");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef USE_BONE_ARRAY
|
||||
if (numBoneWeights == 1)
|
||||
WRITE(p, " mat4 skinMatrix = w1 * u_bone[0]");
|
||||
else
|
||||
WRITE(p, " mat4 skinMatrix = w1.x * u_bone[0]");
|
||||
for (int i = 1; i < numBoneWeights; i++) {
|
||||
const char *weightAttr = boneWeightAttr[i];
|
||||
// workaround for "cant do .x of scalar" issue
|
||||
if (numBoneWeights == 1 && i == 0) weightAttr = "w1";
|
||||
if (numBoneWeights == 5 && i == 4) weightAttr = "w2";
|
||||
WRITE(p, " + %s * u_bone[%i]", weightAttr, i);
|
||||
}
|
||||
#else
|
||||
// Uncomment this to screw up bone shaders to check the vertex shader software fallback
|
||||
// WRITE(p, "THIS SHOULD ERROR! #error");
|
||||
if (numBoneWeights == 1)
|
||||
WRITE(p, " mat4 skinMatrix = w1 * u_bone0");
|
||||
else
|
||||
WRITE(p, " mat4 skinMatrix = w1.x * u_bone0");
|
||||
for (int i = 1; i < numBoneWeights; i++) {
|
||||
const char *weightAttr = boneWeightAttr[i];
|
||||
// workaround for "cant do .x of scalar" issue
|
||||
if (numBoneWeights == 1 && i == 0) weightAttr = "w1";
|
||||
if (numBoneWeights == 5 && i == 4) weightAttr = "w2";
|
||||
WRITE(p, " + %s * u_bone%i", weightAttr, i);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
WRITE(p, ";\n");
|
||||
|
||||
// Trying to simplify this results in bugs in LBP...
|
||||
WRITE(p, " vec3 skinnedpos = (skinMatrix * vec4(position, 1.0)).xyz %s;\n", factor);
|
||||
WRITE(p, " vec3 worldpos = (u_world * vec4(skinnedpos, 1.0)).xyz;\n");
|
||||
|
||||
if (hasNormal) {
|
||||
WRITE(p, " mediump vec3 skinnednormal = (skinMatrix * vec4(%snormal, 0.0)).xyz %s;\n", flipNormal ? "-" : "", factor);
|
||||
} else {
|
||||
WRITE(p, " mediump vec3 skinnednormal = (skinMatrix * vec4(0.0, 0.0, %s1.0, 0.0)).xyz %s;\n", flipNormal ? "-" : "", factor);
|
||||
}
|
||||
WRITE(p, " mediump vec3 worldnormal = normalize((u_world * vec4(skinnednormal, 0.0)).xyz);\n");
|
||||
}
|
||||
|
||||
WRITE(p, " vec4 viewPos = u_view * vec4(worldpos, 1.0);\n");
|
||||
|
||||
// Final view and projection transforms.
|
||||
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, " gl_Position = depthRoundZVP(u_proj * viewPos);\n");
|
||||
} else {
|
||||
WRITE(p, " gl_Position = u_proj * viewPos;\n");
|
||||
}
|
||||
|
||||
// TODO: Declare variables for dots for shade mapping if needed.
|
||||
|
||||
const char *ambientStr = (matUpdate & 1) && hasColor ? "color0" : "u_matambientalpha";
|
||||
const char *diffuseStr = (matUpdate & 2) && hasColor ? "color0.rgb" : "u_matdiffuse";
|
||||
const char *specularStr = (matUpdate & 4) && hasColor ? "color0.rgb" : "u_matspecular.rgb";
|
||||
|
||||
bool diffuseIsZero = true;
|
||||
bool specularIsZero = true;
|
||||
bool distanceNeeded = false;
|
||||
|
||||
if (enableLighting) {
|
||||
WRITE(p, " lowp vec4 lightSum0 = u_ambient * %s + vec4(u_matemissive, 0.0);\n", ambientStr);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
GELightType type = static_cast<GELightType>(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2));
|
||||
GELightComputation comp = static_cast<GELightComputation>(id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2));
|
||||
if (doLight[i] != LIGHT_FULL)
|
||||
continue;
|
||||
diffuseIsZero = false;
|
||||
if (comp != GE_LIGHTCOMP_ONLYDIFFUSE)
|
||||
specularIsZero = false;
|
||||
if (type != GE_LIGHTTYPE_DIRECTIONAL)
|
||||
distanceNeeded = true;
|
||||
}
|
||||
|
||||
if (!specularIsZero) {
|
||||
WRITE(p, " lowp vec3 lightSum1 = vec3(0.0);\n");
|
||||
}
|
||||
if (!diffuseIsZero) {
|
||||
WRITE(p, " vec3 toLight;\n");
|
||||
WRITE(p, " lowp vec3 diffuse;\n");
|
||||
}
|
||||
if (distanceNeeded) {
|
||||
WRITE(p, " float distance;\n");
|
||||
WRITE(p, " lowp float lightScale;\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate lights if needed. If shade mapping is enabled, lights may need to be
|
||||
// at least partially calculated.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (doLight[i] != LIGHT_FULL)
|
||||
continue;
|
||||
|
||||
GELightType type = static_cast<GELightType>(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2));
|
||||
GELightComputation comp = static_cast<GELightComputation>(id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2));
|
||||
|
||||
if (type == GE_LIGHTTYPE_DIRECTIONAL) {
|
||||
// We prenormalize light positions for directional lights.
|
||||
WRITE(p, " toLight = u_lightpos%i;\n", i);
|
||||
} else {
|
||||
WRITE(p, " toLight = u_lightpos%i - worldpos;\n", i);
|
||||
WRITE(p, " distance = length(toLight);\n");
|
||||
WRITE(p, " toLight /= distance;\n");
|
||||
}
|
||||
|
||||
bool doSpecular = comp != GE_LIGHTCOMP_ONLYDIFFUSE;
|
||||
bool poweredDiffuse = comp == GE_LIGHTCOMP_BOTHWITHPOWDIFFUSE;
|
||||
|
||||
WRITE(p, " mediump float dot%i = max(dot(toLight, worldnormal), 0.0);\n", i);
|
||||
if (poweredDiffuse) {
|
||||
// pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0.
|
||||
// Seen in Tales of the World: Radiant Mythology (#2424.)
|
||||
WRITE(p, " if (dot%i == 0.0 && u_matspecular.a == 0.0) {\n", i);
|
||||
WRITE(p, " dot%i = 1.0;\n", i);
|
||||
WRITE(p, " } else {\n");
|
||||
WRITE(p, " dot%i = pow(dot%i, u_matspecular.a);\n", i, i);
|
||||
WRITE(p, " }\n");
|
||||
}
|
||||
|
||||
const char *timesLightScale = " * lightScale";
|
||||
|
||||
// Attenuation
|
||||
switch (type) {
|
||||
case GE_LIGHTTYPE_DIRECTIONAL:
|
||||
timesLightScale = "";
|
||||
break;
|
||||
case GE_LIGHTTYPE_POINT:
|
||||
WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0);\n", i);
|
||||
break;
|
||||
case GE_LIGHTTYPE_SPOT:
|
||||
case GE_LIGHTTYPE_UNKNOWN:
|
||||
WRITE(p, " lowp float angle%i = dot(normalize(u_lightdir%i), toLight);\n", i, i);
|
||||
WRITE(p, " if (angle%i >= u_lightangle%i) {\n", i, i);
|
||||
WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0) * pow(angle%i, u_lightspotCoef%i);\n", i, i, i);
|
||||
WRITE(p, " } else {\n");
|
||||
WRITE(p, " lightScale = 0.0;\n");
|
||||
WRITE(p, " }\n");
|
||||
break;
|
||||
default:
|
||||
// ILLEGAL
|
||||
break;
|
||||
}
|
||||
|
||||
WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * dot%i;\n", i, diffuseStr, i);
|
||||
if (doSpecular) {
|
||||
WRITE(p, " dot%i = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n", i);
|
||||
WRITE(p, " if (dot%i > 0.0)\n", i);
|
||||
WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(dot%i, u_matspecular.a) %s);\n", i, specularStr, i, timesLightScale);
|
||||
}
|
||||
WRITE(p, " lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale);
|
||||
}
|
||||
|
||||
if (enableLighting) {
|
||||
// Sum up ambient, emissive here.
|
||||
if (lmode) {
|
||||
WRITE(p, " v_color0 = clamp(lightSum0, 0.0, 1.0);\n");
|
||||
// v_color1 only exists when lmode = 1.
|
||||
if (specularIsZero) {
|
||||
WRITE(p, " v_color1 = vec3(0.0);\n");
|
||||
} else {
|
||||
WRITE(p, " v_color1 = clamp(lightSum1, 0.0, 1.0);\n");
|
||||
}
|
||||
} else {
|
||||
if (specularIsZero) {
|
||||
WRITE(p, " v_color0 = clamp(lightSum0, 0.0, 1.0);\n");
|
||||
} else {
|
||||
WRITE(p, " v_color0 = clamp(clamp(lightSum0, 0.0, 1.0) + vec4(lightSum1, 0.0), 0.0, 1.0);\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Lighting doesn't affect color.
|
||||
if (hasColor) {
|
||||
WRITE(p, " v_color0 = color0;\n");
|
||||
} else {
|
||||
WRITE(p, " v_color0 = u_matambientalpha;\n");
|
||||
}
|
||||
if (lmode)
|
||||
WRITE(p, " v_color1 = vec3(0.0);\n");
|
||||
}
|
||||
|
||||
// Step 3: UV generation
|
||||
if (doTexture) {
|
||||
switch (uvGenMode) {
|
||||
case GE_TEXMAP_TEXTURE_COORDS: // Scale-offset. Easy.
|
||||
case GE_TEXMAP_UNKNOWN: // Not sure what this is, but Riviera uses it. Treating as coords works.
|
||||
if (prescale) {
|
||||
if (hasTexcoord) {
|
||||
WRITE(p, " v_texcoord = texcoord;\n");
|
||||
} else {
|
||||
WRITE(p, " v_texcoord = vec2(0.0);\n");
|
||||
}
|
||||
} else {
|
||||
if (hasTexcoord) {
|
||||
WRITE(p, " v_texcoord = texcoord * u_uvscaleoffset.xy + u_uvscaleoffset.zw;\n");
|
||||
} else {
|
||||
WRITE(p, " v_texcoord = u_uvscaleoffset.zw;\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GE_TEXMAP_TEXTURE_MATRIX: // Projection mapping.
|
||||
{
|
||||
std::string temp_tc;
|
||||
switch (uvProjMode) {
|
||||
case GE_PROJMAP_POSITION: // Use model space XYZ as source
|
||||
temp_tc = "vec4(position.xyz, 1.0)";
|
||||
break;
|
||||
case GE_PROJMAP_UV: // Use unscaled UV as source
|
||||
{
|
||||
// prescale is false here.
|
||||
if (hasTexcoord) {
|
||||
static const char *rescaleuv[4] = { "", " * 1.9921875", " * 1.999969482421875", "" }; // 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f};
|
||||
const char *factor = rescaleuv[texFmtScale];
|
||||
temp_tc = StringFromFormat("vec4(texcoord.xy %s, 0.0, 1.0)", factor);
|
||||
} else {
|
||||
temp_tc = "vec4(0.0, 0.0, 0.0, 1.0)";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GE_PROJMAP_NORMALIZED_NORMAL: // Use normalized transformed normal as source
|
||||
if (hasNormal)
|
||||
temp_tc = flipNormal ? "vec4(normalize(-normal), 1.0)" : "vec4(normalize(normal), 1.0)";
|
||||
else
|
||||
temp_tc = "vec4(0.0, 0.0, 1.0, 1.0)";
|
||||
break;
|
||||
case GE_PROJMAP_NORMAL: // Use non-normalized transformed normal as source
|
||||
if (hasNormal)
|
||||
temp_tc = flipNormal ? "vec4(-normal, 1.0)" : "vec4(normal, 1.0)";
|
||||
else
|
||||
temp_tc = "vec4(0.0, 0.0, 1.0, 1.0)";
|
||||
break;
|
||||
}
|
||||
// Transform by texture matrix. XYZ as we are doing projection mapping.
|
||||
WRITE(p, " v_texcoord = (u_texmtx * %s).xyz * vec3(u_uvscaleoffset.xy, 1.0);\n", temp_tc.c_str());
|
||||
}
|
||||
break;
|
||||
|
||||
case GE_TEXMAP_ENVIRONMENT_MAP: // Shade mapping - use dots from light sources.
|
||||
WRITE(p, " v_texcoord = u_uvscaleoffset.xy * vec2(1.0 + dot(normalize(u_lightpos%i), worldnormal), 1.0 + dot(normalize(u_lightpos%i), worldnormal)) * 0.5;\n", ls0, ls1);
|
||||
break;
|
||||
|
||||
default:
|
||||
// ILLEGAL
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute fogdepth
|
||||
if (enableFog)
|
||||
WRITE(p, " v_fogdepth = (viewPos.z + u_fogcoef.x) * u_fogcoef.y;\n");
|
||||
}
|
||||
WRITE(p, "}\n");
|
||||
return true;
|
||||
}
|
5
GPU/Vulkan/VertexShaderGeneratorVulkan.h
Normal file
5
GPU/Vulkan/VertexShaderGeneratorVulkan.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
|
||||
bool GenerateVulkanGLSLVertexShader(const ShaderID &id, char *buffer);
|
5
GPU/Vulkan/VulkanUtil.h
Normal file
5
GPU/Vulkan/VulkanUtil.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define VK_PROTOTYPES
|
||||
#include "ext/vulkan/vulkan.h"
|
||||
|
@ -99,8 +99,19 @@ void EmuScreen::bootGame(const std::string &filename) {
|
||||
CoreParameter coreParam;
|
||||
coreParam.cpuCore = g_Config.bJit ? CPU_JIT : CPU_INTERPRETER;
|
||||
coreParam.gpuCore = GPU_GLES;
|
||||
if (GetGPUBackend() == GPUBackend::DIRECT3D9) {
|
||||
switch (GetGPUBackend()) {
|
||||
case GPUBackend::OPENGL:
|
||||
coreParam.gpuCore = GPU_GLES;
|
||||
break;
|
||||
case GPUBackend::DIRECT3D9:
|
||||
coreParam.gpuCore = GPU_DIRECTX9;
|
||||
break;
|
||||
case GPUBackend::DIRECT3D11:
|
||||
coreParam.gpuCore = GPU_DIRECTX11;
|
||||
break;
|
||||
case GPUBackend::VULKAN:
|
||||
coreParam.gpuCore = GPU_VULKAN;
|
||||
break;
|
||||
}
|
||||
if (g_Config.bSoftwareRendering) {
|
||||
coreParam.gpuCore = GPU_SOFTWARE;
|
||||
@ -956,6 +967,7 @@ void EmuScreen::render() {
|
||||
}
|
||||
|
||||
// We have no use for backbuffer depth or stencil, so let tiled renderers discard them after tiling.
|
||||
/*
|
||||
if (gl_extensions.GLES3 && glInvalidateFramebuffer != nullptr) {
|
||||
GLenum attachments[2] = { GL_DEPTH, GL_STENCIL };
|
||||
glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
|
||||
@ -969,6 +981,7 @@ void EmuScreen::render() {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void EmuScreen::deviceLost() {
|
||||
|
@ -136,7 +136,7 @@ void GameSettingsScreen::CreateViews() {
|
||||
|
||||
graphicsSettings->Add(new ItemHeader(gr->T("Rendering Mode")));
|
||||
#if defined(_WIN32)
|
||||
static const char *renderingBackend[] = { "OpenGL", "Direct3D9" };
|
||||
static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan" };
|
||||
PopupMultiChoice *renderingBackendChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, GPU_BACKEND_OPENGL, ARRAY_SIZE(renderingBackend), gr->GetName(), screenManager()));
|
||||
renderingBackendChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingBackend);
|
||||
#endif
|
||||
|
@ -383,7 +383,7 @@ void LogoScreen::Next() {
|
||||
void LogoScreen::update(InputState &input_state) {
|
||||
UIScreen::update(input_state);
|
||||
frames_++;
|
||||
if (frames_ > 180 || input_state.pointer_down[0]) {
|
||||
if (frames_ > 1800000 || input_state.pointer_down[0]) {
|
||||
Next();
|
||||
}
|
||||
}
|
||||
|
107
Windows/GPU/WindowsVulkanContext.cpp
Normal file
107
Windows/GPU/WindowsVulkanContext.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
|
||||
// Initializing a Vulkan context is quite a complex task!
|
||||
// That's not really a strange thing though - you really do have control over everything,
|
||||
// and everything needs to be specified. There are no nebulous defaults.
|
||||
|
||||
// We create a swapchain, and two framebuffers that we can point to two of the images
|
||||
// we got from the swap chain. These will be used as backbuffers.
|
||||
//
|
||||
// We also create a depth buffer. The swap chain will not allocate one for us so we need
|
||||
// to manage the memory for it ourselves.
|
||||
// The depth buffer will not really be used unless we do "non-buffered" rendering, which will happen
|
||||
// directly to one of the backbuffers.
|
||||
//
|
||||
// Render pass usage
|
||||
//
|
||||
// In normal buffered rendering mode, we do not begin the "UI" render pass until after we have rendered
|
||||
// a frame of PSP graphics. The render pass that we will use then will be the simple "uiPass" that does not
|
||||
// bother attaching the depth buffer, and discards all input (no need to even bother clearing as we will
|
||||
// draw over the whole backbuffer anyway).
|
||||
//
|
||||
// However, in non-buffered, we will have to use the depth buffer, and we must begin the rendering pass
|
||||
// before we start rendering PSP graphics, and end it only after we have completed rendering the UI on top.
|
||||
// We will also use clearing.
|
||||
//
|
||||
// So it all turns into a single rendering pass, which might be good for performance on some GPUs, but it
|
||||
// will complicate things a little.
|
||||
//
|
||||
// In a first iteration, we will not distinguish between these two cases - we will always create a depth buffer
|
||||
// and use the same render pass configuration (clear to black). However, we can later change this so we switch
|
||||
// to a non-clearing render pass in buffered mode, which might be a tiny bit faster.
|
||||
|
||||
#include <assert.h>
|
||||
#include <crtdbg.h>
|
||||
|
||||
#define VK_PROTOTYPES
|
||||
|
||||
#include "ext/vulkan/vulkan.h"
|
||||
#include "ext/native/thin3d/VulkanContext.h"
|
||||
|
||||
#include "thin3d/thin3d.h"
|
||||
#include "Windows/GPU/WindowsVulkanContext.h"
|
||||
|
||||
const bool g_validate_ = true;
|
||||
VulkanContext *g_Vulkan;
|
||||
|
||||
bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_message) {
|
||||
*error_message = "N/A";
|
||||
|
||||
if (g_Vulkan) {
|
||||
*error_message = "Already initialized";
|
||||
return false;
|
||||
}
|
||||
|
||||
g_Vulkan = new VulkanContext("PPSSPP", 0);
|
||||
|
||||
g_Vulkan->InitObjects(hInst, hWnd, true);
|
||||
|
||||
_CrtCheckMemory();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WindowsVulkanContext::Shutdown() {
|
||||
g_Vulkan->DestroyObjects();
|
||||
delete g_Vulkan;
|
||||
g_Vulkan = nullptr;
|
||||
}
|
||||
|
||||
Thin3DContext *WindowsVulkanContext::CreateThin3DContext() {
|
||||
return T3DCreateVulkanContext(g_Vulkan);
|
||||
}
|
||||
|
||||
void WindowsVulkanContext::SwapBuffers() {
|
||||
}
|
||||
|
||||
void WindowsVulkanContext::Resize() {
|
||||
/*
|
||||
g_Vulkan->DestroyObjects();
|
||||
|
||||
g_Vulkan->WaitUntilQueueIdle();
|
||||
|
||||
g_Vulkan->InitObjects(g_Vulkan)
|
||||
*/
|
||||
}
|
||||
|
||||
void WindowsVulkanContext::SwapInterval(int interval) {
|
||||
}
|
||||
|
||||
Thin3DContext *Vulkan_CreateThin3DContext() {
|
||||
return T3DCreateVulkanContext(g_Vulkan);
|
||||
}
|
36
Windows/GPU/WindowsVulkanContext.h
Normal file
36
Windows/GPU/WindowsVulkanContext.h
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/GraphicsContext.h"
|
||||
#include "Windows/GPU/WindowsGraphicsContext.h"
|
||||
#include "thin3d/thin3d.h"
|
||||
|
||||
class WindowsVulkanContext : public WindowsGraphicsContext {
|
||||
public:
|
||||
bool Init(HINSTANCE hInst, HWND window, std::string *error_message) override;
|
||||
void Shutdown() override;
|
||||
void SwapInterval(int interval) override;
|
||||
void SwapBuffers() override;
|
||||
void Resize() override;
|
||||
|
||||
Thin3DContext *CreateThin3DContext() override;
|
||||
};
|
||||
|
||||
void Vulkan_BeginSurfaceRender();
|
||||
void Vulkan_EndSurfaceRender();
|
@ -38,6 +38,7 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "native", "..\ext\native\native.vcxproj", "{C4DF647E-80EA-4111-A0A8-218B1B711E18}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34} = {F761046E-6C38-4428-A5F1-38391A37BB34}
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947} = {EDFA2E87-8AC1-4853-95D4-D7594FF81947}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPSSPPHeadless", "..\headless\Headless.vcxproj", "{EE9BD869-CAA3-447D-8328-294D90DE2C1F}"
|
||||
@ -75,18 +76,30 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang", "..\ext\glslang.v
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug CRT DLL|Win32 = Debug CRT DLL|Win32
|
||||
Debug CRT DLL|x64 = Debug CRT DLL|x64
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release CRT DLL|Win32 = Release CRT DLL|Win32
|
||||
Release CRT DLL|x64 = Release CRT DLL|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
Tests|Win32 = Tests|Win32
|
||||
Tests|x64 = Tests|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Debug|x64.Build.0 = Debug|x64
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Release|Win32.Build.0 = Release|Win32
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Release|x64.ActiveCfg = Release|x64
|
||||
@ -95,10 +108,18 @@ Global
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Tests|Win32.Build.0 = Release|Win32
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Tests|x64.ActiveCfg = Release|x64
|
||||
{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}.Tests|x64.Build.0 = Release|x64
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Debug|x64.Build.0 = Debug|x64
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Release|Win32.Build.0 = Release|Win32
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Release|x64.ActiveCfg = Release|x64
|
||||
@ -107,10 +128,18 @@ Global
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Tests|Win32.Build.0 = Release|Win32
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Tests|x64.ActiveCfg = Release|x64
|
||||
{3FCDBAE2-5103-4350-9A8E-848CE9C73195}.Tests|x64.Build.0 = Release|x64
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Debug|x64.Build.0 = Debug|x64
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Release|Win32.Build.0 = Release|Win32
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Release|x64.ActiveCfg = Release|x64
|
||||
@ -119,10 +148,18 @@ Global
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Tests|Win32.Build.0 = Release|Win32
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Tests|x64.ActiveCfg = Release|x64
|
||||
{F761046E-6C38-4428-A5F1-38391A37BB34}.Tests|x64.Build.0 = Release|x64
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Debug|x64.Build.0 = Debug|x64
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Release|Win32.Build.0 = Release|Win32
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Release|x64.ActiveCfg = Release|x64
|
||||
@ -131,10 +168,18 @@ Global
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Tests|Win32.Build.0 = Release|Win32
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Tests|x64.ActiveCfg = Release|x64
|
||||
{457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Tests|x64.Build.0 = Release|x64
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Debug|x64.Build.0 = Debug|x64
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Release|Win32.Build.0 = Release|Win32
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Release|x64.ActiveCfg = Release|x64
|
||||
@ -143,10 +188,18 @@ Global
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Tests|Win32.Build.0 = Release|Win32
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Tests|x64.ActiveCfg = Release|x64
|
||||
{533F1D30-D04D-47CC-AD71-20F658907E36}.Tests|x64.Build.0 = Release|x64
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Debug|x64.Build.0 = Debug|x64
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release|Win32.Build.0 = Release|Win32
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Release|x64.ActiveCfg = Release|x64
|
||||
@ -155,10 +208,18 @@ Global
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Tests|Win32.Build.0 = Release|Win32
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Tests|x64.ActiveCfg = Release|x64
|
||||
{C4DF647E-80EA-4111-A0A8-218B1B711E18}.Tests|x64.Build.0 = Release|x64
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Debug|x64.Build.0 = Debug|x64
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Release|Win32.Build.0 = Release|Win32
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Release|x64.ActiveCfg = Release|x64
|
||||
@ -167,10 +228,18 @@ Global
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Tests|Win32.Build.0 = Release|Win32
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Tests|x64.ActiveCfg = Release|x64
|
||||
{EE9BD869-CAA3-447D-8328-294D90DE2C1F}.Tests|x64.Build.0 = Release|x64
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Debug|x64.Build.0 = Debug|x64
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Release|Win32.Build.0 = Release|Win32
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Release|x64.ActiveCfg = Release|x64
|
||||
@ -179,10 +248,18 @@ Global
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Tests|Win32.Build.0 = Release|Win32
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Tests|x64.ActiveCfg = Release|x64
|
||||
{3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE}.Tests|x64.Build.0 = Release|x64
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Debug|x64.Build.0 = Debug|x64
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Release|Win32.Build.0 = Release|Win32
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Release|x64.ActiveCfg = Release|x64
|
||||
@ -191,10 +268,18 @@ Global
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Tests|Win32.Build.0 = Release|Win32
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Tests|x64.ActiveCfg = Release|x64
|
||||
{37CBC214-7CE7-4655-B619-F7CEE16E3313}.Tests|x64.Build.0 = Release|x64
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Debug|x64.Build.0 = Debug|x64
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Release|Win32.Build.0 = Release|Win32
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Release|x64.ActiveCfg = Release|x64
|
||||
@ -203,10 +288,18 @@ Global
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Tests|Win32.Build.0 = Release|Win32
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Tests|x64.ActiveCfg = Release|x64
|
||||
{004B8D11-2BE3-4BD9-AB40-2BE04CF2096F}.Tests|x64.Build.0 = Release|x64
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Debug|x64.Build.0 = Debug|x64
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Release|Win32.Build.0 = Release|Win32
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Release|x64.ActiveCfg = Release|x64
|
||||
@ -215,10 +308,18 @@ Global
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Tests|Win32.Build.0 = Tests|Win32
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Tests|x64.ActiveCfg = Tests|x64
|
||||
{129E5E2B-39C1-4D84-96FE-DFD22DBB4A25}.Tests|x64.Build.0 = Tests|x64
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Debug CRT DLL|Win32.ActiveCfg = Debug|Win32
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Debug CRT DLL|Win32.Build.0 = Debug|Win32
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Debug CRT DLL|x64.ActiveCfg = Debug|x64
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Debug CRT DLL|x64.Build.0 = Debug|x64
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Debug|x64.Build.0 = Debug|x64
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Release CRT DLL|Win32.ActiveCfg = Release|Win32
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Release CRT DLL|Win32.Build.0 = Release|Win32
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Release CRT DLL|x64.ActiveCfg = Release|x64
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Release CRT DLL|x64.Build.0 = Release|x64
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Release|Win32.Build.0 = Release|Win32
|
||||
{EDFA2E87-8AC1-4853-95D4-D7594FF81947}.Release|x64.ActiveCfg = Release|x64
|
||||
|
@ -125,7 +125,7 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/native/ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../ext;../common;..;../ext/native;../ext/native/ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<ForcedIncludeFiles>stdafx.h;Common/DbgNew.h</ForcedIncludeFiles>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
@ -135,7 +135,7 @@
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;dxerr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>..\ext\vulkan\vulkan-1.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;dxerr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
@ -161,7 +161,7 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/native/ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../ext;../common;..;../ext/native;../ext/native/ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<ForcedIncludeFiles>stdafx.h;Common/DbgNew.h</ForcedIncludeFiles>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
@ -172,7 +172,7 @@
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>x64\Debug\glslang.lib;..\ext\vulkan\vulkan-1.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -201,14 +201,14 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/native/ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../ext;../common;..;../ext/native;../ext/native/ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>dxerr.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>..\ext\vulkan\vulkan-1.lib;dxerr.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -246,13 +246,13 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/native/ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../ext;../common;..;../ext/native;../ext/native/ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>dxerr.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>..\ext\vulkan\vulkan-1.lib;dxerr.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -319,6 +319,7 @@
|
||||
<ClCompile Include="MainWindowMenu.cpp" />
|
||||
<ClCompile Include="RawInput.cpp" />
|
||||
<ClCompile Include="TouchInputHandler.cpp" />
|
||||
<ClCompile Include="GPU\WindowsVulkanContext.cpp" />
|
||||
<ClCompile Include="W32Util\DialogManager.cpp" />
|
||||
<ClCompile Include="W32Util\Misc.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(Filename)2.obj</ObjectFileName>
|
||||
@ -374,6 +375,7 @@
|
||||
<ClInclude Include="MainWindowMenu.h" />
|
||||
<ClInclude Include="RawInput.h" />
|
||||
<ClInclude Include="TouchInputHandler.h" />
|
||||
<ClInclude Include="GPU\WindowsVulkanContext.h" />
|
||||
<ClInclude Include="W32Util\DialogManager.h" />
|
||||
<ClInclude Include="W32Util\Misc.h" />
|
||||
<ClInclude Include="W32Util\PropertySheet.h" />
|
||||
@ -422,6 +424,9 @@
|
||||
<ProjectReference Include="..\Core\Core.vcxproj">
|
||||
<Project>{533f1d30-d04d-47cc-ad71-20f658907e36}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ext\glslang.vcxproj">
|
||||
<Project>{edfa2e87-8ac1-4853-95d4-d7594ff81947}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ext\libkirk\libkirk.vcxproj">
|
||||
<Project>{3baae095-e0ab-4b0e-b5df-ce39c8ae31de}</Project>
|
||||
</ProjectReference>
|
||||
|
@ -152,6 +152,7 @@
|
||||
<ClCompile Include="GPU\WindowsGLContext.cpp">
|
||||
<Filter>Windows\System</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GPU\WindowsVulkanContext.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Debugger\CtrlDisAsmView.h">
|
||||
@ -278,6 +279,7 @@
|
||||
<ClInclude Include="GPU\WindowsGraphicsContext.h">
|
||||
<Filter>Windows\System</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GPU\WindowsVulkanContext.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="icon1.ico">
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "Windows/WindowsHost.h"
|
||||
#include "Windows/MainWindow.h"
|
||||
#include "Windows/GPU/WindowsGLContext.h"
|
||||
#include "Windows/GPU/WindowsVulkanContext.h"
|
||||
#include "Windows/GPU/D3D9Context.h"
|
||||
|
||||
#include "Windows/Debugger/DebuggerShared.h"
|
||||
@ -110,6 +111,9 @@ bool WindowsHost::InitGraphics(std::string *error_message, GraphicsContext **ctx
|
||||
case GPU_BACKEND_DIRECT3D9:
|
||||
graphicsContext = new D3D9Context();
|
||||
break;
|
||||
case GPU_BACKEND_VULKAN:
|
||||
graphicsContext = new WindowsVulkanContext();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -114,6 +114,8 @@
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -132,6 +134,8 @@
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -140,13 +144,11 @@
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="glslang\glslang\ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="glslang\glslang\GenericCodeGen\CodeGen.cpp" />
|
||||
<ClCompile Include="glslang\glslang\GenericCodeGen\Link.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\Constant.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\glslang_tab.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\InfoSink.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\Initialize.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\Intermediate.cpp" />
|
||||
@ -191,6 +193,7 @@
|
||||
<ClInclude Include="glslang\glslang\Include\ResourceLimits.h" />
|
||||
<ClInclude Include="glslang\glslang\Include\ShHandle.h" />
|
||||
<ClInclude Include="glslang\glslang\Include\Types.h" />
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\glslang_tab.cpp.h" />
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\gl_types.h" />
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\Initialize.h" />
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\localintermediate.h" />
|
||||
@ -202,7 +205,6 @@
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\Scan.h" />
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\ScanContext.h" />
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\SymbolTable.h" />
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\unistd.h" />
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\Versions.h" />
|
||||
<ClInclude Include="glslang\glslang\Public\ShaderLang.h" />
|
||||
<ClInclude Include="glslang\OGLCompilersDLL\InitializeDll.h" />
|
||||
@ -217,7 +219,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="glslang\glslang\MachineIndependent\glslang.y" />
|
||||
<None Include="glslang\glslang\MachineIndependent\Makefile" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Text Include="glslang\glslang\ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="SPIRV">
|
||||
<UniqueIdentifier>{300f8b24-cec5-41dc-bf7f-e60745f3e383}</UniqueIdentifier>
|
||||
@ -110,6 +107,9 @@
|
||||
<ClCompile Include="glslang\SPIRV\InReadableOrder.cpp">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\glslang_tab.cpp">
|
||||
<Filter>glslang</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="glslang\SPIRV\disassemble.h">
|
||||
@ -202,9 +202,6 @@
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\SymbolTable.h">
|
||||
<Filter>glslang</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\unistd.h">
|
||||
<Filter>glslang</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\Versions.h">
|
||||
<Filter>glslang</Filter>
|
||||
</ClInclude>
|
||||
@ -212,13 +209,13 @@
|
||||
<Filter>glslang</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\OGLCompilersDLL\InitializeDll.h" />
|
||||
<ClInclude Include="glslang\glslang\MachineIndependent\glslang_tab.cpp.h">
|
||||
<Filter>glslang</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="glslang\glslang\MachineIndependent\glslang.y">
|
||||
<Filter>glslang</Filter>
|
||||
</None>
|
||||
<None Include="glslang\glslang\MachineIndependent\Makefile">
|
||||
<Filter>glslang</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -85,4 +85,4 @@ inline void CopyMatrix4x4(float dest[16], const float src[16]) {
|
||||
inline void ExpandFloat24x3ToFloat4(float dest[4], uint32_t src[3]) {
|
||||
uint32_t temp[4] = { src[0] << 8, src[1] << 8, src[2] << 8, 0 };
|
||||
memcpy(dest, temp, sizeof(float) * 4);
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\dx9sdk\Include;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\native\ext\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\ext;..\..;..\..\dx9sdk\Include;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\native\ext\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
@ -102,7 +102,7 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\dx9sdk\Include;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\native\ext\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\ext;..\..;..\..\dx9sdk\Include;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\native\ext\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
@ -128,7 +128,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\dx9sdk\Include;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\native\ext\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\ext;..\..;..\..\dx9sdk\Include;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\native\ext\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
@ -154,7 +154,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\dx9sdk\Include;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\native\ext\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\ext;..\..;..\..\dx9sdk\Include;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\native\ext\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
@ -265,6 +265,8 @@
|
||||
<ClInclude Include="profiler\profiler.h" />
|
||||
<ClInclude Include="thin3d\d3dx9_loader.h" />
|
||||
<ClInclude Include="thin3d\thin3d.h" />
|
||||
<ClInclude Include="thin3d\VulkanContext.h" />
|
||||
<ClInclude Include="thin3d\vulkan_utils.h" />
|
||||
<ClInclude Include="thread\executor.h" />
|
||||
<ClInclude Include="thread\prioritizedworkqueue.h" />
|
||||
<ClInclude Include="thread\thread.h" />
|
||||
@ -344,7 +346,6 @@
|
||||
<ClCompile Include="ext\libpng17\pngrtran.c" />
|
||||
<ClCompile Include="ext\libpng17\pngrutil.c" />
|
||||
<ClCompile Include="ext\libpng17\pngset.c" />
|
||||
<ClCompile Include="ext\libpng17\pngtest.c" />
|
||||
<ClCompile Include="ext\libpng17\pngtrans.c" />
|
||||
<ClCompile Include="ext\libpng17\pngwio.c" />
|
||||
<ClCompile Include="ext\libpng17\pngwrite.c" />
|
||||
@ -727,6 +728,9 @@
|
||||
<ClCompile Include="thin3d\thin3d.cpp" />
|
||||
<ClCompile Include="thin3d\thin3d_d3d9.cpp" />
|
||||
<ClCompile Include="thin3d\thin3d_gl.cpp" />
|
||||
<ClCompile Include="thin3d\thin3d_vulkan.cpp" />
|
||||
<ClCompile Include="thin3d\VulkanContext.cpp" />
|
||||
<ClCompile Include="thin3d\vulkan_utils.cpp" />
|
||||
<ClCompile Include="thread\executor.cpp" />
|
||||
<ClCompile Include="thread\prioritizedworkqueue.cpp" />
|
||||
<ClCompile Include="thread\threadpool.cpp" />
|
||||
|
@ -305,9 +305,15 @@
|
||||
<ClInclude Include="file\free.h">
|
||||
<Filter>file</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="thin3d\vulkan_utils.h">
|
||||
<Filter>thin3d</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="math\dataconv.h">
|
||||
<Filter>math</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="thin3d\VulkanContext.h">
|
||||
<Filter>thin3d</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="gfx\gl_debug_log.cpp">
|
||||
@ -502,9 +508,6 @@
|
||||
<ClCompile Include="ext\libpng17\pngset.c">
|
||||
<Filter>ext\libpng17</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext\libpng17\pngtest.c">
|
||||
<Filter>ext\libpng17</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext\libpng17\pngtrans.c">
|
||||
<Filter>ext\libpng17</Filter>
|
||||
</ClCompile>
|
||||
@ -745,6 +748,15 @@
|
||||
<ClCompile Include="file\free.cpp">
|
||||
<Filter>file</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="thin3d\vulkan_utils.cpp">
|
||||
<Filter>thin3d</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="thin3d\thin3d_vulkan.cpp">
|
||||
<Filter>thin3d</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="thin3d\VulkanContext.cpp">
|
||||
<Filter>thin3d</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="gfx">
|
||||
|
1619
ext/native/thin3d/VulkanContext.cpp
Normal file
1619
ext/native/thin3d/VulkanContext.cpp
Normal file
File diff suppressed because it is too large
Load Diff
277
ext/native/thin3d/VulkanContext.h
Normal file
277
ext/native/thin3d/VulkanContext.h
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Vulkan Samples Kit
|
||||
*
|
||||
* Copyright (C) 2015 Valve Corporation
|
||||
* Copyright (C) 2015 Google, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_INIT
|
||||
#define UTIL_INIT
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define VK_USE_PLATFORM_WIN32_KHR
|
||||
#define NOMINMAX /* Don't let Windows define min() or max() */
|
||||
#define APP_NAME_STR_LEN 80
|
||||
#include <Windows.h>
|
||||
#else // _WIN32
|
||||
#define VK_USE_PLATFORM_XCB_KHR
|
||||
#include <unistd.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#include "ext/vulkan/vulkan.h"
|
||||
#include "ext/vulkan/vk_sdk_platform.h"
|
||||
|
||||
/* Amount of time, in nanoseconds, to wait for a command buffer to complete */
|
||||
#define FENCE_TIMEOUT 10000000000
|
||||
|
||||
#if defined(NDEBUG) && defined(__GNUC__)
|
||||
#define U_ASSERT_ONLY __attribute__((unused))
|
||||
#else
|
||||
#define U_ASSERT_ONLY
|
||||
#endif
|
||||
|
||||
enum {
|
||||
VULKAN_FLAG_VALIDATE = 1,
|
||||
};
|
||||
|
||||
// A layer can expose extensions, keep track of those extensions here.
|
||||
struct layer_properties {
|
||||
VkLayerProperties properties;
|
||||
std::vector<VkExtensionProperties> extensions;
|
||||
};
|
||||
|
||||
// VulkanContext sets up the basics necessary for rendering to a window, including framebuffers etc.
|
||||
// Optionally, it can create a depth buffer for you as well.
|
||||
class VulkanContext {
|
||||
public:
|
||||
VulkanContext(const char *app_name, uint32_t flags);
|
||||
~VulkanContext();
|
||||
|
||||
VkResult CreateDevice(int physical_device);
|
||||
|
||||
VkDevice Device() {
|
||||
return device_;
|
||||
}
|
||||
|
||||
void InitSurfaceAndQueue(HINSTANCE conn, HWND wnd);
|
||||
void InitSwapchain();
|
||||
void InitSurfaceRenderPass(bool include_depth, bool clear);
|
||||
void InitFramebuffers(bool include_depth);
|
||||
void InitDepthStencilBuffer();
|
||||
void InitCommandPool();
|
||||
void InitCommandBuffer();
|
||||
|
||||
void InitObjects(HINSTANCE hInstance, HWND hWnd, bool depthPresent);
|
||||
void DestroyObjects();
|
||||
|
||||
void BeginInitCommandBuffer();
|
||||
void SubmitInitCommandBufferSync();
|
||||
VkCommandBuffer GetInitCommandBuffer() {
|
||||
return cmd_;
|
||||
}
|
||||
|
||||
void DestroySurfaceRenderPass();
|
||||
void DestroyFramebuffers();
|
||||
void DestroySwapChain();
|
||||
void DestroyDepthStencilBuffer();
|
||||
void DestroyCommandPool();
|
||||
void DestroyCommandBuffer();
|
||||
void DestroyDevice();
|
||||
|
||||
void WaitUntilQueueIdle();
|
||||
|
||||
// Utility functions for shorter code
|
||||
VkFence CreateFence();
|
||||
void WaitForFence(VkFence fence);
|
||||
|
||||
int GetWidth() { return width; }
|
||||
int GetHeight() { return height; }
|
||||
|
||||
// The surface render pass is special because it has to acquire the backbuffer, and may thus "block".
|
||||
// Use the returned command buffer to enqueue commands. Might be a good idea to use secondary cmd buffers.
|
||||
VkCommandBuffer BeginSurfaceRenderPass(VkClearValue clear_values[2]);
|
||||
|
||||
void EndSurfaceRenderPass();
|
||||
|
||||
bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
|
||||
|
||||
VkResult InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc);
|
||||
void DestroyDebugMsgCallback();
|
||||
|
||||
VkSemaphore acquireSemaphore;
|
||||
|
||||
VkRenderPass GetSurfaceRenderPass() {
|
||||
return surface_render_pass_;
|
||||
}
|
||||
|
||||
VkPhysicalDevice GetPhysicalDevice() {
|
||||
return physical_devices_[0];
|
||||
}
|
||||
|
||||
VkQueue GetGraphicsQueue() {
|
||||
return gfx_queue_;
|
||||
}
|
||||
|
||||
int GetGraphicsQueueFamilyIndex() {
|
||||
return gfx_queue_family_index_;
|
||||
}
|
||||
|
||||
VkResult init_global_extension_properties();
|
||||
VkResult init_layer_extension_properties(layer_properties &layer_props);
|
||||
|
||||
VkResult init_global_layer_properties();
|
||||
|
||||
VkResult init_device_extension_properties(layer_properties &layer_props);
|
||||
VkResult init_device_layer_properties();
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define APP_NAME_STR_LEN 80
|
||||
HINSTANCE connection; // hInstance - Windows Instance
|
||||
char name[APP_NAME_STR_LEN]; // Name to put on the window/icon
|
||||
HWND window; // hWnd - window handle
|
||||
#else // _WIN32
|
||||
xcb_connection_t *connection;
|
||||
xcb_screen_t *screen;
|
||||
xcb_window_t window;
|
||||
xcb_intern_atom_reply_t *atom_wm_delete_window;
|
||||
#endif // _WIN32
|
||||
|
||||
VkCommandPool cmd_pool_;
|
||||
VkCommandBuffer cmd_; // Buffer for initialization commands
|
||||
|
||||
VkInstance instance_;
|
||||
VkDevice device_;
|
||||
VkQueue gfx_queue_;
|
||||
|
||||
VkSurfaceKHR surface;
|
||||
bool prepared;
|
||||
bool use_staging_buffer_;
|
||||
|
||||
std::vector<const char *> instance_layer_names;
|
||||
std::vector<const char *> instance_extension_names;
|
||||
std::vector<layer_properties> instance_layer_properties;
|
||||
std::vector<VkExtensionProperties> instance_extension_properties;
|
||||
|
||||
std::vector<const char *> device_layer_names;
|
||||
std::vector<const char *> device_extension_names;
|
||||
std::vector<layer_properties> device_layer_properties;
|
||||
std::vector<VkExtensionProperties> device_extension_properties;
|
||||
std::vector<VkPhysicalDevice> physical_devices_;
|
||||
|
||||
uint32_t gfx_queue_family_index_;
|
||||
VkPhysicalDeviceProperties gpu_props;
|
||||
std::vector<VkQueueFamilyProperties> queue_props;
|
||||
VkPhysicalDeviceMemoryProperties memory_properties;
|
||||
|
||||
private:
|
||||
struct swap_chain_buffer {
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
};
|
||||
|
||||
// Swap chain
|
||||
int width, height;
|
||||
VkFormat swapchain_format;
|
||||
std::vector<VkFramebuffer> framebuffers_;
|
||||
uint32_t swapchainImageCount;
|
||||
VkSwapchainKHR swap_chain_;
|
||||
std::vector<swap_chain_buffer> swapChainBuffers;
|
||||
|
||||
|
||||
// Simple loader for the WSI extension.
|
||||
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR;
|
||||
PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
|
||||
PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
|
||||
PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
|
||||
PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
|
||||
PFN_vkQueuePresentKHR fpQueuePresentKHR;
|
||||
// And the DEBUG_REPORT extension.
|
||||
PFN_vkCreateDebugReportCallbackEXT dbgCreateMsgCallback;
|
||||
PFN_vkDestroyDebugReportCallbackEXT dbgDestroyMsgCallback;
|
||||
std::vector<VkDebugReportCallbackEXT> msg_callbacks;
|
||||
|
||||
struct {
|
||||
VkFormat format;
|
||||
VkImage image;
|
||||
VkDeviceMemory mem;
|
||||
VkImageView view;
|
||||
} depth;
|
||||
|
||||
VkRenderPass surface_render_pass_;
|
||||
uint32_t current_buffer;
|
||||
uint32_t queue_count;
|
||||
};
|
||||
|
||||
// Wrapper around what you need to use a texture.
|
||||
// Not very optimal - if you have many small textures you should use other strategies.
|
||||
class VulkanTexture {
|
||||
public:
|
||||
VkImage image;
|
||||
VkImageLayout imageLayout;
|
||||
|
||||
VkDeviceMemory mem;
|
||||
VkImageView view;
|
||||
|
||||
int32_t tex_width, tex_height;
|
||||
|
||||
// Always call Create, Lock, Unlock. Unlock performs the upload if necessary.
|
||||
|
||||
void Create(VulkanContext *vulkan, int w, int h);
|
||||
uint8_t *Lock(VulkanContext *vulkan, int *rowPitch);
|
||||
void Unlock(VulkanContext *vulkan);
|
||||
|
||||
void Destroy(VulkanContext *vulkan);
|
||||
|
||||
private:
|
||||
VkImage mappableImage;
|
||||
VkDeviceMemory mappableMemory;
|
||||
VkMemoryRequirements mem_reqs;
|
||||
bool needStaging;
|
||||
};
|
||||
|
||||
VkBool32 CheckLayers(const std::vector<layer_properties> &layer_props, const std::vector<const char *> &layer_names);
|
||||
|
||||
void VulkanBeginCommandBuffer(VkCommandBuffer cmd);
|
||||
|
||||
void vk_submit_sync(VkDevice device, VkSemaphore waitForSemaphore, VkQueue queue, VkCommandBuffer cmd);
|
||||
|
||||
void init_glslang();
|
||||
void finalize_glslang();
|
||||
|
||||
bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spirv);
|
||||
|
||||
void TransitionImageLayout(
|
||||
VkCommandBuffer cmd,
|
||||
VkImage image,
|
||||
VkImageAspectFlags aspectMask,
|
||||
VkImageLayout old_image_layout,
|
||||
VkImageLayout new_image_layout);
|
||||
|
||||
#endif // UTIL_INIT
|
||||
|
@ -7,6 +7,10 @@
|
||||
#include "file/vfs.h"
|
||||
#include "ext/jpge/jpgd.h"
|
||||
|
||||
// ================================== PIXEL/FRAGMENT SHADERS
|
||||
|
||||
// The Vulkan ones can be re-used with modern GL later if desired, as they're just GLSL.
|
||||
|
||||
static const char * const glsl_fsTexCol =
|
||||
"#ifdef GL_ES\n"
|
||||
"precision lowp float;\n"
|
||||
@ -23,6 +27,16 @@ static const char * const hlslFsTexCol =
|
||||
" return input.color * tex2D(Sampler0, input.uv);\n"
|
||||
"}\n";
|
||||
|
||||
static const char * const vulkan_fsTexCol =
|
||||
"#version 140\n"
|
||||
"#extension GL_ARB_separate_shader_objects : enable\n"
|
||||
"#extension GL_ARB_shading_language_420pack : enable\n"
|
||||
"layout(location = 0) in vec4 oColor0;\n"
|
||||
"layout(location = 1) in vec2 oTexCoord0;\n"
|
||||
"layout(location = 0) out vec4 fragColor0\n;"
|
||||
"layout(binding = 2) uniform sampler2D Sampler0;\n"
|
||||
"void main() { fragColor0 = texture2D(Sampler0, oTexCoord0) * oColor0; }\n";
|
||||
|
||||
static const char * const glsl_fsCol =
|
||||
"#ifdef GL_ES\n"
|
||||
"precision lowp float;\n"
|
||||
@ -36,6 +50,18 @@ static const char * const hlslFsCol =
|
||||
" return input.color;\n"
|
||||
"}\n";
|
||||
|
||||
static const char * const vulkan_fsCol =
|
||||
"#version 140\n"
|
||||
"#extension GL_ARB_separate_shader_objects : enable\n"
|
||||
"#extension GL_ARB_shading_language_420pack : enable\n"
|
||||
"layout(location = 0) in vec4 oColor0;\n"
|
||||
"layout(location = 0) out vec4 fragColor0\n;"
|
||||
"void main() { fragColor0 = oColor0; }\n";
|
||||
|
||||
|
||||
|
||||
// ================================== VERTEX SHADERS
|
||||
|
||||
static const char * const glsl_vsCol =
|
||||
"attribute vec3 Position;\n"
|
||||
"attribute vec4 Color0;\n"
|
||||
@ -57,6 +83,22 @@ static const char * const hlslVsCol =
|
||||
" return output;\n"
|
||||
"}\n";
|
||||
|
||||
static const char * const vulkan_vsCol =
|
||||
"#version 140\n"
|
||||
"#extension GL_ARB_separate_shader_objects : enable\n"
|
||||
"#extension GL_ARB_shading_language_420pack : enable\n"
|
||||
"layout (std140, binding = 1) uniform bufferVals {\n"
|
||||
" mat4 WorldViewProj;\n"
|
||||
"} myBufferVals;\n"
|
||||
"layout (location = 0) in vec4 pos;\n"
|
||||
"layout (location = 1) in vec4 inColor;\n"
|
||||
"layout (location = 0) out vec4 outColor;\n"
|
||||
"void main() {\n"
|
||||
" outColor = inColor;\n"
|
||||
" gl_Position = myBufferVals.WorldViewProj * pos;\n"
|
||||
"}\n";
|
||||
|
||||
|
||||
static const char * const glsl_vsTexCol =
|
||||
"attribute vec3 Position;\n"
|
||||
"attribute vec4 Color0;\n"
|
||||
@ -82,6 +124,25 @@ static const char * const hlslVsTexCol =
|
||||
" return output;\n"
|
||||
"}\n";
|
||||
|
||||
static const char * const vulkan_vsTexCol =
|
||||
"#version 140\n"
|
||||
"#extension GL_ARB_separate_shader_objects : enable\n"
|
||||
"#extension GL_ARB_shading_language_420pack : enable\n"
|
||||
"layout (std140, binding = 1) uniform bufferVals {\n"
|
||||
" mat4 WorldViewProj;\n"
|
||||
"} myBufferVals;\n"
|
||||
"layout (location = 0) in vec4 pos;\n"
|
||||
"layout (location = 1) in vec4 inColor;\n"
|
||||
"layout (location = 2) in vec2 inTexCoord;\n"
|
||||
"layout (location = 0) out vec4 outColor;\n"
|
||||
"layout (location = 1) out vec2 outTexCoord;\n"
|
||||
"void main() {\n"
|
||||
" outColor = inColor;\n"
|
||||
" outTexCoord = inTexCoord;\n"
|
||||
" gl_Position = myBufferVals.WorldViewProj * pos;\n"
|
||||
"}\n";
|
||||
|
||||
|
||||
void Thin3DContext::CreatePresets() {
|
||||
// Build prebuilt objects
|
||||
T3DBlendStateDesc off = { false };
|
||||
@ -100,11 +161,11 @@ void Thin3DContext::CreatePresets() {
|
||||
sampsPresets_[SAMPS_NEAREST] = CreateSamplerState(nearest);
|
||||
sampsPresets_[SAMPS_LINEAR] = CreateSamplerState(linear);
|
||||
|
||||
vsPresets_[VS_TEXTURE_COLOR_2D] = CreateVertexShader(glsl_vsTexCol, hlslVsTexCol);
|
||||
vsPresets_[VS_COLOR_2D] = CreateVertexShader(glsl_vsCol, hlslVsCol);
|
||||
vsPresets_[VS_TEXTURE_COLOR_2D] = CreateVertexShader(glsl_vsTexCol, hlslVsTexCol, vulkan_vsTexCol);
|
||||
vsPresets_[VS_COLOR_2D] = CreateVertexShader(glsl_vsCol, hlslVsCol, vulkan_vsCol);
|
||||
|
||||
fsPresets_[FS_TEXTURE_COLOR_2D] = CreateFragmentShader(glsl_fsTexCol, hlslFsTexCol);
|
||||
fsPresets_[FS_COLOR_2D] = CreateFragmentShader(glsl_fsCol, hlslFsCol);
|
||||
fsPresets_[FS_TEXTURE_COLOR_2D] = CreateFragmentShader(glsl_fsTexCol, hlslFsTexCol, vulkan_fsTexCol);
|
||||
fsPresets_[FS_COLOR_2D] = CreateFragmentShader(glsl_fsCol, hlslFsCol, vulkan_fsCol);
|
||||
|
||||
ssPresets_[SS_TEXTURE_COLOR_2D] = CreateShaderSet(vsPresets_[VS_TEXTURE_COLOR_2D], fsPresets_[FS_TEXTURE_COLOR_2D]);
|
||||
ssPresets_[SS_COLOR_2D] = CreateShaderSet(vsPresets_[VS_COLOR_2D], fsPresets_[FS_COLOR_2D]);
|
||||
|
@ -334,8 +334,8 @@ public:
|
||||
Thin3DShaderSet *GetShaderSetPreset(T3DShaderSetPreset preset) { return ssPresets_[preset]; }
|
||||
|
||||
// The implementation makes the choice of which shader code to use.
|
||||
virtual Thin3DShader *CreateVertexShader(const char *glsl_source, const char *hlsl_source) = 0;
|
||||
virtual Thin3DShader *CreateFragmentShader(const char *glsl_source, const char *hlsl_source) = 0;
|
||||
virtual Thin3DShader *CreateVertexShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) = 0;
|
||||
virtual Thin3DShader *CreateFragmentShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) = 0;
|
||||
|
||||
// Bound state objects. Too cumbersome to add them all as parameters to Draw.
|
||||
virtual void SetBlendState(Thin3DBlendState *state) = 0;
|
||||
@ -359,8 +359,15 @@ public:
|
||||
virtual void Draw(T3DPrimitive prim, Thin3DShaderSet *pipeline, Thin3DVertexFormat *format, Thin3DBuffer *vdata, int vertexCount, int offset) = 0;
|
||||
virtual void DrawIndexed(T3DPrimitive prim, Thin3DShaderSet *pipeline, Thin3DVertexFormat *format, Thin3DBuffer *vdata, Thin3DBuffer *idata, int vertexCount, int offset) = 0;
|
||||
virtual void DrawUP(T3DPrimitive prim, Thin3DShaderSet *pipeline, Thin3DVertexFormat *format, const void *vdata, int vertexCount) = 0;
|
||||
|
||||
// Render pass management. Default implementations here.
|
||||
virtual void Begin(bool clear, uint32_t colorval, float depthVal, int stencilVal) {
|
||||
Clear(0xF, colorval, depthVal, stencilVal);
|
||||
}
|
||||
virtual void End() {}
|
||||
|
||||
virtual void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) = 0;
|
||||
|
||||
|
||||
// Necessary to correctly flip scissor rectangles etc for OpenGL.
|
||||
void SetTargetSize(int w, int h) {
|
||||
targetWidth_ = w;
|
||||
@ -393,3 +400,7 @@ struct IDirect3DDevice9Ex;
|
||||
struct IDirect3D9Ex;
|
||||
Thin3DContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx);
|
||||
#endif
|
||||
|
||||
class VulkanContext;
|
||||
|
||||
Thin3DContext *T3DCreateVulkanContext(VulkanContext *context);
|
||||
|
@ -434,8 +434,8 @@ public:
|
||||
Thin3DTexture *CreateTexture() override;
|
||||
Thin3DTexture *CreateTexture(T3DTextureType type, T3DImageFormat format, int width, int height, int depth, int mipLevels) override;
|
||||
|
||||
Thin3DShader *CreateVertexShader(const char *glsl_source, const char *hlsl_source) override;
|
||||
Thin3DShader *CreateFragmentShader(const char *glsl_source, const char *hlsl_source) override;
|
||||
Thin3DShader *CreateVertexShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) override;
|
||||
Thin3DShader *CreateFragmentShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) override;
|
||||
|
||||
// Bound state objects. Too cumbersome to add them all as parameters to Draw.
|
||||
void SetBlendState(Thin3DBlendState *state) {
|
||||
@ -502,7 +502,7 @@ Thin3DDX9Context::Thin3DDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int ada
|
||||
Thin3DDX9Context::~Thin3DDX9Context() {
|
||||
}
|
||||
|
||||
Thin3DShader *Thin3DDX9Context::CreateVertexShader(const char *glsl_source, const char *hlsl_source) {
|
||||
Thin3DShader *Thin3DDX9Context::CreateVertexShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) {
|
||||
Thin3DDX9Shader *shader = new Thin3DDX9Shader(false);
|
||||
if (shader->Compile(device_, hlsl_source, "vs_2_0")) {
|
||||
return shader;
|
||||
@ -512,7 +512,7 @@ Thin3DShader *Thin3DDX9Context::CreateVertexShader(const char *glsl_source, cons
|
||||
}
|
||||
}
|
||||
|
||||
Thin3DShader *Thin3DDX9Context::CreateFragmentShader(const char *glsl_source, const char *hlsl_source) {
|
||||
Thin3DShader *Thin3DDX9Context::CreateFragmentShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) {
|
||||
Thin3DDX9Shader *shader = new Thin3DDX9Shader(true);
|
||||
if (shader->Compile(device_, hlsl_source, "ps_2_0")) {
|
||||
return shader;
|
||||
|
@ -386,8 +386,8 @@ public:
|
||||
}
|
||||
|
||||
// The implementation makes the choice of which shader code to use.
|
||||
Thin3DShader *CreateVertexShader(const char *glsl_source, const char *hlsl_source) override;
|
||||
Thin3DShader *CreateFragmentShader(const char *glsl_source, const char *hlsl_source) override;
|
||||
Thin3DShader *CreateVertexShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) override;
|
||||
Thin3DShader *CreateFragmentShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) override;
|
||||
|
||||
void SetScissorEnabled(bool enable) override {
|
||||
if (enable) {
|
||||
@ -737,7 +737,7 @@ void Thin3DGLContext::SetTextures(int start, int count, Thin3DTexture **textures
|
||||
}
|
||||
|
||||
|
||||
Thin3DShader *Thin3DGLContext::CreateVertexShader(const char *glsl_source, const char *hlsl_source) {
|
||||
Thin3DShader *Thin3DGLContext::CreateVertexShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) {
|
||||
Thin3DGLShader *shader = new Thin3DGLShader(false);
|
||||
if (shader->Compile(glsl_source)) {
|
||||
return shader;
|
||||
@ -747,7 +747,7 @@ Thin3DShader *Thin3DGLContext::CreateVertexShader(const char *glsl_source, const
|
||||
}
|
||||
}
|
||||
|
||||
Thin3DShader *Thin3DGLContext::CreateFragmentShader(const char *glsl_source, const char *hlsl_source) {
|
||||
Thin3DShader *Thin3DGLContext::CreateFragmentShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) {
|
||||
Thin3DGLShader *shader = new Thin3DGLShader(true);
|
||||
if (shader->Compile(glsl_source)) {
|
||||
return shader;
|
||||
|
1384
ext/native/thin3d/thin3d_vulkan.cpp
Normal file
1384
ext/native/thin3d/thin3d_vulkan.cpp
Normal file
File diff suppressed because it is too large
Load Diff
173
ext/native/thin3d/vulkan_utils.cpp
Normal file
173
ext/native/thin3d/vulkan_utils.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef USE_CRT_DBG
|
||||
#undef new
|
||||
#endif
|
||||
|
||||
#include "ext/glslang/SPIRV/GlslangToSpv.h"
|
||||
#include "ext/glslang/SPIRV/disassemble.h"
|
||||
|
||||
#ifdef USE_CRT_DBG
|
||||
#define new DBG_NEW
|
||||
#endif
|
||||
|
||||
#include "thin3d/vulkan_utils.h"
|
||||
|
||||
void VulkanDeviceMemoryManager::Init(VkPhysicalDevice gpu) {
|
||||
// Get Memory information and properties
|
||||
vkGetPhysicalDeviceMemoryProperties(gpu, &memory_properties_);
|
||||
}
|
||||
|
||||
VkResult VulkanDeviceMemoryManager::memory_type_from_properties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex) {
|
||||
// Search memtypes to find first index with those properties
|
||||
for (uint32_t i = 0; i < 32; i++) {
|
||||
if ((typeBits & 1) == 1) {
|
||||
// Type is available, does it match user properties?
|
||||
if ((memory_properties_.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) {
|
||||
*typeIndex = i;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
}
|
||||
typeBits >>= 1;
|
||||
}
|
||||
// No memory types matched, return failure
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
void VulkanImage::Create2D(VkDevice device, VulkanDeviceMemoryManager *memMan, VkFormat format, VkFlags required_props, VkImageUsageFlags usage, int width, int height) {
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
||||
VkImageCreateInfo i;
|
||||
i.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
i.pNext = NULL;
|
||||
i.imageType = VK_IMAGE_TYPE_2D;
|
||||
i.format = format;
|
||||
i.extent = { (uint32_t)width, (uint32_t)height, 1 };
|
||||
i.mipLevels = 1;
|
||||
i.arrayLayers = 1;
|
||||
i.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
i.tiling = VK_IMAGE_TILING_LINEAR;
|
||||
i.usage = usage;
|
||||
i.flags = 0;
|
||||
i.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
i.queueFamilyIndexCount = 0;
|
||||
i.pQueueFamilyIndices = nullptr;
|
||||
i.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
VkMemoryRequirements mem_reqs;
|
||||
|
||||
VkResult err = vkCreateImage(device, &i, nullptr, &image_);
|
||||
assert(!err);
|
||||
|
||||
vkGetImageMemoryRequirements(device, image_, &mem_reqs);
|
||||
|
||||
mem_alloc_.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
mem_alloc_.pNext = NULL;
|
||||
mem_alloc_.allocationSize = mem_reqs.size;
|
||||
mem_alloc_.memoryTypeIndex = 0;
|
||||
|
||||
err = memMan->memory_type_from_properties(mem_reqs.memoryTypeBits, required_props, &mem_alloc_.memoryTypeIndex);
|
||||
assert(!err);
|
||||
|
||||
err = vkAllocateMemory(device, &mem_alloc_, nullptr, &memory_);
|
||||
assert(!err);
|
||||
|
||||
err = vkBindImageMemory(device, image_, memory_, 0); // at offset 0.
|
||||
}
|
||||
|
||||
void VulkanImage::SetImageData2D(VkDevice device, const uint8_t *data, int width, int height, int pitch) {
|
||||
VkImageSubresource subres;
|
||||
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subres.mipLevel = 0;
|
||||
subres.arrayLayer = 0;
|
||||
|
||||
VkSubresourceLayout layout;
|
||||
void *destData;
|
||||
vkGetImageSubresourceLayout(device, image_, &subres, &layout);
|
||||
|
||||
VkResult err = vkMapMemory(device, memory_, 0, mem_alloc_.allocationSize, 0, &destData);
|
||||
assert(!err);
|
||||
|
||||
uint8_t *writePtr = (uint8_t *)destData + layout.offset;
|
||||
int bpp = 4; // TODO
|
||||
for (int y = 0; y < height; y++) {
|
||||
memcpy(writePtr + y * layout.rowPitch, data + y * pitch, bpp * width);
|
||||
}
|
||||
|
||||
vkUnmapMemory(device, memory_);
|
||||
}
|
||||
|
||||
|
||||
void VulkanImage::ChangeLayout(VkCommandBuffer cmd, VkImageAspectFlags aspectMask, VkImageLayout old_image_layout, VkImageLayout new_image_layout) {
|
||||
VkImageMemoryBarrier image_memory_barrier;
|
||||
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
image_memory_barrier.pNext = NULL;
|
||||
image_memory_barrier.dstAccessMask = 0;
|
||||
image_memory_barrier.srcAccessMask = 0;
|
||||
image_memory_barrier.oldLayout = old_image_layout;
|
||||
image_memory_barrier.newLayout = new_image_layout;
|
||||
image_memory_barrier.image = image_;
|
||||
image_memory_barrier.subresourceRange.aspectMask = aspectMask;
|
||||
image_memory_barrier.subresourceRange.layerCount = 1;
|
||||
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
|
||||
image_memory_barrier.subresourceRange.baseMipLevel = 0;
|
||||
image_memory_barrier.subresourceRange.levelCount = 1;
|
||||
|
||||
if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||
/* Make sure anything that was copying from this image has completed */
|
||||
image_memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
}
|
||||
|
||||
if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||
/* Make sure any Copy or CPU writes to image are flushed */
|
||||
image_memory_barrier.dstAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
}
|
||||
|
||||
VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
vkCmdPipelineBarrier(cmd, src_stages, dest_stages, false, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
|
||||
}
|
||||
|
||||
|
||||
bool CreateShaderModule(VkDevice device, const std::vector<uint32_t> &spirv, VkShaderModule *shaderModule) {
|
||||
VkShaderModuleCreateInfo sm;
|
||||
sm.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
sm.pNext = nullptr;
|
||||
sm.pCode = spirv.data();
|
||||
sm.codeSize = spirv.size() * sizeof(uint32_t);
|
||||
sm.flags = 0;
|
||||
VkResult result = vkCreateShaderModule(device, &sm, NULL, shaderModule);
|
||||
if (result != VK_SUCCESS) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
70
ext/native/thin3d/vulkan_utils.h
Normal file
70
ext/native/thin3d/vulkan_utils.h
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2015- PPSSPP Project.
|
||||
|
||||
// This program 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, version 2.0 or later versions.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define VK_PROTOTYPES
|
||||
#include "ext/vulkan/vulkan.h"
|
||||
|
||||
//
|
||||
class VulkanDeviceMemoryManager {
|
||||
public:
|
||||
VulkanDeviceMemoryManager() {}
|
||||
void Init(VkPhysicalDevice gpu);
|
||||
|
||||
VkResult memory_type_from_properties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
|
||||
|
||||
private:
|
||||
VkPhysicalDeviceMemoryProperties memory_properties_;
|
||||
};
|
||||
|
||||
|
||||
// Utility class to handle images without going insane.
|
||||
// Allocates its own memory.
|
||||
class VulkanImage {
|
||||
public:
|
||||
VulkanImage() : image_(nullptr), memory_(nullptr) {}
|
||||
|
||||
bool IsValid() const { return image_ != nullptr; }
|
||||
// This can be done completely unsynchronized.
|
||||
void Create2D(VkDevice device, VulkanDeviceMemoryManager *memMan, VkFormat format, VkFlags required_props, VkImageUsageFlags usage, int width, int height);
|
||||
|
||||
// This can only be used if you pass in VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in required_props in Create2D.
|
||||
void SetImageData2D(VkDevice device, const uint8_t *data, int width, int height, int pitch);
|
||||
void ChangeLayout(VkCommandBuffer cmd, VkImageAspectFlags aspectMask, VkImageLayout old_image_layout, VkImageLayout new_image_layout);
|
||||
VkImage GetImage() const {
|
||||
return image_;
|
||||
}
|
||||
|
||||
private:
|
||||
VkMemoryAllocateInfo mem_alloc_;
|
||||
VkImage image_;
|
||||
VkDeviceMemory memory_;
|
||||
int width_;
|
||||
int height_;
|
||||
};
|
||||
|
||||
|
||||
class Thin3DPipelineCache {
|
||||
|
||||
};
|
||||
|
||||
bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<uint32_t> &spirv);
|
||||
|
||||
bool CreateShaderModule(VkDevice device, const std::vector<uint32_t> &spirv, VkShaderModule *shaderModule);
|
@ -58,7 +58,7 @@ void UIScreen::update(InputState &input) {
|
||||
|
||||
void UIScreen::preRender() {
|
||||
Thin3DContext *thin3d = screenManager()->getThin3DContext();
|
||||
thin3d->Clear(T3DClear::COLOR | T3DClear::DEPTH | T3DClear::STENCIL, 0xFF000000, 0.0f, 0);
|
||||
thin3d->Begin(true, 0xFF000000, 0.0f, 0);
|
||||
|
||||
T3DViewport viewport;
|
||||
viewport.TopLeftX = 0;
|
||||
@ -72,6 +72,8 @@ void UIScreen::preRender() {
|
||||
}
|
||||
|
||||
void UIScreen::postRender() {
|
||||
Thin3DContext *thin3d = screenManager()->getThin3DContext();
|
||||
thin3d->End();
|
||||
}
|
||||
|
||||
void UIScreen::render() {
|
||||
|
@ -71,6 +71,7 @@ struct InputState;
|
||||
void D3D9_SwapBuffers() { }
|
||||
void GL_SwapBuffers() { }
|
||||
void GL_SwapInterval(int) { }
|
||||
void Vulkan_SwapBuffers() {}
|
||||
void NativeUpdate(InputState &input_state) { }
|
||||
void NativeRender(GraphicsContext *graphicsContext) { }
|
||||
void NativeResized() { }
|
||||
|
@ -106,7 +106,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;xinput.lib;d3d9.lib;d3dx9d.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>..\ext\vulkan\vulkan-1.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;xinput.lib;d3d9.lib;d3dx9d.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<BaseAddress>0x00400000</BaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<FixedBaseAddress>true</FixedBaseAddress>
|
||||
@ -138,7 +138,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9d.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>..\Windows\x64\Debug\glslang.lib;..\ext\vulkan\vulkan-1.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9d.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<BaseAddress>0x00400000</BaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<FixedBaseAddress>true</FixedBaseAddress>
|
||||
@ -173,7 +173,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>..\ext\vulkan\vulkan-1.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<BaseAddress>0x00400000</BaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<FixedBaseAddress>true</FixedBaseAddress>
|
||||
@ -209,7 +209,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>..\ext\vulkan\vulkan-1.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<BaseAddress>0x00400000</BaseAddress>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<FixedBaseAddress>true</FixedBaseAddress>
|
||||
@ -269,4 +269,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -54,6 +54,7 @@ std::string System_GetProperty(SystemProperty prop) { return ""; }
|
||||
int System_GetPropertyInt(SystemProperty prop) { return -1; }
|
||||
void NativeMessageReceived(const char *message, const char *value) {}
|
||||
void GL_SwapInterval(int) {}
|
||||
void Vulkan_SwapBuffers() {}
|
||||
|
||||
#ifndef M_PI_2
|
||||
#define M_PI_2 1.57079632679489661923
|
||||
|
@ -100,7 +100,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>..\ext\vulkan\vulkan-1.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalOptions>/ignore:4049 /ignore:4217 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalLibraryDirectories>..\ffmpeg\Windows\x86\lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
@ -123,7 +123,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>..\Windows\x64\Debug\glslang.lib;..\ext\vulkan\vulkan-1.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalOptions>/ignore:4049 /ignore:4217 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalLibraryDirectories>..\ffmpeg\Windows\x86_64\lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
@ -149,7 +149,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>..\ext\vulkan\vulkan-1.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalOptions>/ignore:4049 /ignore:4217 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalLibraryDirectories>..\ffmpeg\Windows\x86\lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
@ -174,7 +174,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>..\ext\vulkan\vulkan-1.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalOptions>/ignore:4049 /ignore:4217 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalLibraryDirectories>..\ffmpeg\Windows\x86_64\lib</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
@ -219,4 +219,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
Loading…
x
Reference in New Issue
Block a user