Initial vulkan code.

This was squashed from nine commits but using old versions of Vulkan.
This commit is contained in:
Henrik Rydgard 2015-10-10 16:41:19 +02:00
parent 538d801f17
commit c64064024d
55 changed files with 7851 additions and 60 deletions

View File

@ -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 {

View File

@ -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

View File

@ -31,6 +31,8 @@ enum GPUCore {
GPU_GLES,
GPU_SOFTWARE,
GPU_DIRECTX9,
GPU_DIRECTX11,
GPU_VULKAN,
};
class FileLoader;

View File

@ -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 {

View File

@ -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,

View File

@ -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;

View File

@ -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">

View File

@ -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>

View 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);
}

View 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_;
};

View 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;
}

View 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);

View File

View 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
View 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
View 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_;
};

View 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;
}

View 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:
};

View 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;
}

View 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

View 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";
}
}

View 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_;
};

View 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;
}
}
*/
//}

View 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 {
}
};

View 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;
}

View 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
View File

@ -0,0 +1,5 @@
#pragma once
#define VK_PROTOTYPES
#include "ext/vulkan/vulkan.h"

View File

@ -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() {

View File

@ -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

View File

@ -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();
}
}

View 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);
}

View 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();

View File

@ -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

View File

@ -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>

View File

@ -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">

View File

@ -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;
}

View File

@ -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">

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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" />

View File

@ -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">

File diff suppressed because it is too large Load Diff

View 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

View File

@ -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]);

View File

@ -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);

View File

@ -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;

View File

@ -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;

File diff suppressed because it is too large Load Diff

View 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;
}
}

View 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);

View File

@ -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() {

View File

@ -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() { }

View File

@ -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>

View File

@ -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

View File

@ -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>