Merge branch 'master' into TemporaryHackishBranch

This commit is contained in:
LunaMoo committed 2017-11-13 01:08:44 +01:00
commit 2ebdbc4ed9
31 files changed
+625 -284

No files matched your search

+2
View File
@@ -1265,6 +1265,8 @@ set(GPU_SOURCES
GPU/Common/ShaderUniforms.h
GPU/Common/ShaderCommon.cpp
GPU/Common/ShaderCommon.h
GPU/Common/ShaderTranslation.cpp
GPU/Common/ShaderTranslation.h
GPU/Common/SplineCommon.cpp
GPU/Common/SplineCommon.h
GPU/Common/StencilCommon.cpp
+3 -3
View File
@@ -272,7 +272,7 @@ private:
VkPhysicalDeviceMemoryProperties memory_properties{};
// Custom collection of things that are good to know
VulkanPhysicalDeviceInfo deviceInfo_;
VulkanPhysicalDeviceInfo deviceInfo_{};
// Swap chain
int width_ = 0;
@@ -299,8 +299,8 @@ private:
uint32_t queue_count = 0;
VkPhysicalDeviceFeatures featuresAvailable_;
VkPhysicalDeviceFeatures featuresEnabled_;
VkPhysicalDeviceFeatures featuresAvailable_{};
VkPhysicalDeviceFeatures featuresEnabled_{};
std::vector<VkCommandBuffer> cmdQueue_;
};
+1 -1
View File
@@ -37,7 +37,7 @@ bool VulkanPushBuffer::AddBuffer() {
VkBufferCreateInfo b = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
b.size = size_;
b.flags = 0;
b.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
b.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
b.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
b.queueFamilyIndexCount = 0;
b.pQueueFamilyIndices = nullptr;
+8
View File
@@ -103,12 +103,20 @@ public:
}
// "Zero-copy" variant - you can write the data directly as you compute it.
// Recommended.
void *Push(size_t size, uint32_t *bindOffset, VkBuffer *vkbuf) {
assert(writePtr_);
size_t off = Allocate(size, vkbuf);
*bindOffset = (uint32_t)off;
return writePtr_ + off;
}
void *PushAligned(size_t size, uint32_t *bindOffset, VkBuffer *vkbuf, int align) {
assert(writePtr_);
offset_ = (offset_ + align - 1) & ~(align - 1);
size_t off = Allocate(size, vkbuf);
*bindOffset = (uint32_t)off;
return writePtr_ + off;
}
size_t GetTotalSize() const;
+5 -1
View File
@@ -162,8 +162,12 @@ protected:
public:
virtual ~TessellationDataTransfer() {}
// Send spline/bezier's control points to vertex shader through floating point texture.
virtual void PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) {
posStride = 4;
texStride = 4;
colStride = 4;
}
virtual void SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) = 0;
virtual void PrepareBuffers(float *&pos, float *&tex, float *&col, int size, bool hasColor, bool hasTexCoords) {};
};
TessellationDataTransfer *tessDataTransfer;
};
+1 -1
View File
@@ -69,7 +69,7 @@ class VulkanFBO;
struct PostShaderUniforms {
float texelDelta[2]; float pixelDelta[2];
float time[4];
bool video;
float video;
};
struct VirtualFramebuffer {
+92 -11
View File
@@ -17,8 +17,6 @@
#include "ppsspp_config.h"
#if !defined(ANDROID)
#include <memory>
#include <vector>
#include <sstream>
@@ -34,6 +32,8 @@
#include "ShaderTranslation.h"
#include "ext/glslang/SPIRV/GlslangToSpv.h"
#include "thin3d/thin3d.h"
#if !defined(ANDROID)
#include "ext/SPIRV-Cross/spirv.hpp"
#include "ext/SPIRV-Cross/spirv_common.hpp"
#include "ext/SPIRV-Cross/spirv_cross.hpp"
@@ -41,6 +41,7 @@
#ifdef _WIN32
#include "ext/SPIRV-Cross/spirv_hlsl.hpp"
#endif
#endif
extern void init_resources(TBuiltInResource &Resources);
@@ -58,12 +59,12 @@ static EShLanguage GetLanguage(const Draw::ShaderStage stage) {
void ShaderTranslationInit() {
// TODO: We have TLS issues on UWP
#if !PPSSPP_PLATFORM(UWP)
#if !PPSSPP_PLATFORM(UWP) && !defined(ANDROID)
glslang::InitializeProcess();
#endif
}
void ShaderTranslationShutdown() {
#if !PPSSPP_PLATFORM(UWP)
#if !PPSSPP_PLATFORM(UWP) && !defined(ANDROID)
glslang::FinalizeProcess();
#endif
}
@@ -83,7 +84,22 @@ cbuffer data : register(b0) {
float2 u_texelDelta;
float2 u_pixelDelta;
float4 u_time;
bool u_video;
float u_video;
};
)";
static const char *vulkanPrologue =
R"(#version 430
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
)";
static const char *pushconstantBufferDecl = R"(
layout(push_constant) uniform data {
vec2 u_texelDelta;
vec2 u_pixelDelta;
vec4 u_time;
float u_video;
};
)";
@@ -112,10 +128,78 @@ std::string Postprocess(std::string code, ShaderLanguage lang, Draw::ShaderStage
return output;
}
bool ConvertToVulkanGLSL(std::string *dest, TranslatedShaderMetadata *destMetadata, std::string src, Draw::ShaderStage stage, std::string *errorMessage) {
std::stringstream out;
static struct {
Draw::ShaderStage stage;
const char *needle;
const char *replacement;
} replacements[] = {
{ Draw::ShaderStage::VERTEX, "attribute vec4 a_position;", "layout(location = 0) in vec4 a_position;" },
{ Draw::ShaderStage::VERTEX, "attribute vec2 a_texcoord0;", "layout(location = 1) in vec2 a_texcoord0;"},
{ Draw::ShaderStage::VERTEX, "varying vec2 v_position;", "layout(location = 0) out vec2 v_position;" },
{ Draw::ShaderStage::FRAGMENT, "varying vec2 v_position;", "layout(location = 0) in vec2 v_position;" },
{ Draw::ShaderStage::FRAGMENT, "texture2D(", "texture(" },
{ Draw::ShaderStage::FRAGMENT, "gl_FragColor", "fragColor0" },
};
out << vulkanPrologue;
if (stage == Draw::ShaderStage::FRAGMENT) {
out << "layout (location = 0) out vec4 fragColor0;\n";
}
// Output the uniform buffer.
out << pushconstantBufferDecl;
// Alright, now let's go through it line by line and zap the single uniforms
// and perform replacements.
std::string line;
std::stringstream instream(src);
while (std::getline(instream, line)) {
char buffer[256];
int vecSize, num;
if (line.find("uniform bool") != std::string::npos) {
continue;
} else if (line.find("uniform sampler2D") == 0) {
line = "layout(set = 0, binding = 0) " + line;
} else if (line.find("uniform ") != std::string::npos) {
continue;
} else if (2 == sscanf(line.c_str(), "varying vec%d v_texcoord%d;", &vecSize, &num)) {
if (stage == Draw::ShaderStage::FRAGMENT) {
line = StringFromFormat("layout(location = %d) in vec%d v_texcoord%d;", num, vecSize, num);
} else {
line = StringFromFormat("layout(location = %d) out vec%d v_texcoord%d;", num, vecSize, num);
}
}
for (int i = 0; i < ARRAY_SIZE(replacements); i++) {
if (replacements[i].stage == stage)
line = ReplaceAll(line, replacements[i].needle, replacements[i].replacement);
}
out << line << "\n";
}
// DUMPLOG(src.c_str());
// ILOG("---->");
// DUMPLOG(LineNumberString(out.str()).c_str());
*dest = out.str();
return true;
}
bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShaderMetadata *destMetadata, std::string src, ShaderLanguage srcLang, Draw::ShaderStage stage, std::string *errorMessage) {
if (srcLang != GLSL_300 && srcLang != GLSL_140)
return false;
if ((srcLang == GLSL_140 || srcLang == GLSL_300) && destLang == GLSL_VULKAN) {
// Let's just mess about at the string level, no need to recompile.
bool result = ConvertToVulkanGLSL(dest, destMetadata, src, stage, errorMessage);
return result;
}
#if defined(ANDROID)
return false;
#else
#if PPSSPP_PLATFORM(UWP)
return false;
#endif
@@ -126,8 +210,8 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade
TBuiltInResource Resources;
init_resources(Resources);
// Enable SPIR-V and Vulkan rules when parsing GLSL
EShMessages messages = EShMessages::EShMsgDefault; // (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
// Don't enable SPIR-V and Vulkan rules when parsing GLSL. Our postshaders are written in oldschool GLES 2.0.
EShMessages messages = EShMessages::EShMsgDefault;
EShLanguage shaderStage = GetLanguage(stage);
glslang::TShader shader(shaderStage);
@@ -166,8 +250,6 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade
// Alright, step 1 done. Now let's take this SPIR-V shader and output in our desired format.
switch (destLang) {
case GLSL_VULKAN:
return false; // TODO
#ifdef _WIN32
case HLSL_DX9:
{
@@ -227,6 +309,5 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade
default:
return false;
}
}
#endif
}
-4
View File
@@ -21,8 +21,6 @@
#include "GPU/Common/ShaderCommon.h"
#include "thin3d/thin3d.h"
#ifndef ANDROID
struct TranslatedShaderMetadata {
};
@@ -31,5 +29,3 @@ void ShaderTranslationInit();
void ShaderTranslationShutdown();
bool TranslateShader(std::string *dst, ShaderLanguage destLang, TranslatedShaderMetadata *destMetadata, std::string src, ShaderLanguage srcLang, Draw::ShaderStage stage, std::string *errorMessage);
#endif
+30 -13
View File
@@ -908,13 +908,22 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi
const bool hasColor = (origVertType & GE_VTYPE_COL_MASK) != 0;
const bool hasTexCoords = (origVertType & GE_VTYPE_TC_MASK) != 0;
tessDataTransfer->PrepareBuffers(pos, tex, col, count_u * count_v, hasColor, hasTexCoords);
int posStride, texStride, colStride;
tessDataTransfer->PrepareBuffers(pos, tex, col, posStride, texStride, colStride, count_u * count_v, hasColor, hasTexCoords);
float *p = pos;
float *t = tex;
float *c = col;
for (int idx = 0; idx < count_u * count_v; idx++) {
memcpy(pos + idx * 4, points[idx]->pos.AsArray(), 3 * sizeof(float));
if (hasTexCoords)
memcpy(tex + idx * 4, points[idx]->uv, 2 * sizeof(float));
if (hasColor)
memcpy(col + idx * 4, Vec4f::FromRGBA(points[idx]->color_32).AsArray(), 4 * sizeof(float));
memcpy(p, points[idx]->pos.AsArray(), 3 * sizeof(float));
p += posStride;
if (hasTexCoords) {
memcpy(t, points[idx]->uv, 2 * sizeof(float));
t += texStride;
}
if (hasColor) {
memcpy(c, Vec4f::FromRGBA(points[idx]->color_32).AsArray(), 4 * sizeof(float));
c += colStride;
}
}
if (!hasColor)
memcpy(col, Vec4f::FromRGBA(points[0]->color_32).AsArray(), 4 * sizeof(float));
@@ -985,7 +994,6 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi
ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex));
}
float *pos = (float*)(decoded + 65536 * 18); // Size 4 float
float *tex = pos + count_u * count_v * 4; // Size 4 float
float *col = tex + count_u * count_v * 4; // Size 4 float
@@ -997,14 +1005,23 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi
int num_patches_v = (count_v - 1) / 3;
BezierPatch *patches = nullptr;
if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) {
tessDataTransfer->PrepareBuffers(pos, tex, col, count_u * count_v, hasColor, hasTexCoords);
int posStride, texStride, colStride;
tessDataTransfer->PrepareBuffers(pos, tex, col, posStride, texStride, colStride, count_u * count_v, hasColor, hasTexCoords);
float *p = pos;
float *t = tex;
float *c = col;
for (int idx = 0; idx < count_u * count_v; idx++) {
SimpleVertex *point = simplified_control_points + (indices ? idxConv.convert(idx) : idx);
memcpy(pos + idx * 4, point->pos.AsArray(), 3 * sizeof(float));
if (hasTexCoords)
memcpy(tex + idx * 4, point->uv, 2 * sizeof(float));
if (hasColor)
memcpy(col + idx * 4, Vec4f::FromRGBA(point->color_32).AsArray(), 4 * sizeof(float));
memcpy(p, point->pos.AsArray(), 3 * sizeof(float));
p += posStride;
if (hasTexCoords) {
memcpy(t, point->uv, 2 * sizeof(float));
t += texStride;
}
if (hasColor) {
memcpy(c, Vec4f::FromRGBA(point->color_32).AsArray(), 4 * sizeof(float));
c += colStride;
}
}
if (!hasColor) {
SimpleVertex *point = simplified_control_points + (indices ? idxConv.convert(0) : 0);
+10 -14
View File
@@ -226,7 +226,6 @@ void FramebufferManagerGLES::Init() {
// Workaround for upscaling shaders where we force x1 resolution without saving it
Resized();
CompileDraw2DProgram();
SetLineWidth();
}
void FramebufferManagerGLES::SetTextureCache(TextureCacheGLES *tc) {
@@ -449,18 +448,6 @@ void FramebufferManagerGLES::RebindFramebuffer() {
glstate.viewport.restore();
}
void FramebufferManagerGLES::SetLineWidth() {
#ifndef USING_GLES2
if (g_Config.iInternalResolution == 0) {
glLineWidth(std::max(1, (int)(renderWidth_ / 480)));
glPointSize(std::max(1.0f, (float)(renderWidth_ / 480.f)));
} else {
glLineWidth(g_Config.iInternalResolution);
glPointSize((float)g_Config.iInternalResolution);
}
#endif
}
void FramebufferManagerGLES::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) {
if (!useBufferedRendering_ || !vfb->fbo) {
return;
@@ -1091,7 +1078,16 @@ void FramebufferManagerGLES::Resized() {
}
DestroyDraw2DProgram();
SetLineWidth();
#ifndef USING_GLES2
if (g_Config.iInternalResolution == 0) {
glLineWidth(std::max(1, (int)(renderWidth_ / 480)));
glPointSize(std::max(1.0f, (float)(renderWidth_ / 480.f)));
} else {
glLineWidth(g_Config.iInternalResolution);
glPointSize((float)g_Config.iInternalResolution);
}
#endif
if (!draw2dprogram_) {
CompileDraw2DProgram();
+9 -5
View File
@@ -218,11 +218,15 @@ void ProcessRect(const VertexData& v0, const VertexData& v1)
RotateUVThrough(v0, v1, *topright, *bottomleft);
// Four triangles to do backfaces as well. Two of them will get backface culled.
Rasterizer::DrawTriangle(*topleft, *topright, *bottomright);
Rasterizer::DrawTriangle(*bottomright, *topright, *topleft);
Rasterizer::DrawTriangle(*bottomright, *bottomleft, *topleft);
Rasterizer::DrawTriangle(*topleft, *bottomleft, *bottomright);
if (gstate.isModeClear()) {
Rasterizer::ClearRectangle(v0, v1);
} else {
// Four triangles to do backfaces as well. Two of them will get backface culled.
Rasterizer::DrawTriangle(*topleft, *topright, *bottomright);
Rasterizer::DrawTriangle(*bottomright, *topright, *topleft);
Rasterizer::DrawTriangle(*bottomright, *bottomleft, *topleft);
Rasterizer::DrawTriangle(*topleft, *bottomleft, *bottomright);
}
}
}
+169 -21
View File
@@ -1183,7 +1183,7 @@ template <bool clearMode>
void DrawTriangleSlice(
const VertexData& v0, const VertexData& v1, const VertexData& v2,
int minX, int minY, int maxX, int maxY,
int hy1, int hy2)
bool byY, int h1, int h2)
{
Vec4<int> bias0 = Vec4<int>::AssignToAll(IsRightSideOrFlatBottomLine(v0.screenpos.xy(), v1.screenpos.xy(), v2.screenpos.xy()) ? -1 : 0);
Vec4<int> bias1 = Vec4<int>::AssignToAll(IsRightSideOrFlatBottomLine(v1.screenpos.xy(), v2.screenpos.xy(), v0.screenpos.xy()) ? -1 : 0);
@@ -1215,23 +1215,26 @@ void DrawTriangleSlice(
TriangleEdge e1;
TriangleEdge e2;
if (byY) {
maxY = std::min(maxY, minY + h2 * 16 * 2);
minY += h1 * 16 * 2;
} else {
maxX = std::min(maxX, minX + h2 * 16 * 2);
minX += h1 * 16 * 2;
}
ScreenCoords pprime(minX, minY, 0);
Vec4<int> w0_base = e0.Start(v1.screenpos, v2.screenpos, pprime);
Vec4<int> w1_base = e1.Start(v2.screenpos, v0.screenpos, pprime);
Vec4<int> w2_base = e2.Start(v0.screenpos, v1.screenpos, pprime);
// Step forward to y1 (slice..)
w0_base += e0.stepY * hy1;
w1_base += e1.stepY * hy1;
w2_base += e2.stepY * hy1;
// All the z values are the same, no interpolation required.
// This is common, and when we interpolate, we lose accuracy.
const bool flatZ = v0.screenpos.z == v1.screenpos.z && v0.screenpos.z == v2.screenpos.z;
Sampler::Funcs sampler = Sampler::GetFuncs();
for (pprime.y = minY + hy1 * 32; pprime.y < minY + hy2 * 32; pprime.y += 32,
for (pprime.y = minY; pprime.y < maxY; pprime.y += 32,
w0_base = e0.StepY(w0_base),
w1_base = e1.StepY(w1_base),
w2_base = e2.StepY(w2_base)) {
@@ -1351,8 +1354,8 @@ void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData&
int minX = std::min(std::min(v0.screenpos.x, v1.screenpos.x), v2.screenpos.x) & ~0xF;
int minY = std::min(std::min(v0.screenpos.y, v1.screenpos.y), v2.screenpos.y) & ~0xF;
int maxX = std::max(std::max(v0.screenpos.x, v1.screenpos.x), v2.screenpos.x) & ~0xF;
int maxY = std::max(std::max(v0.screenpos.y, v1.screenpos.y), v2.screenpos.y) & ~0xF;
int maxX = (std::max(std::max(v0.screenpos.x, v1.screenpos.x), v2.screenpos.x) + 0xF) & ~0xF;
int maxY = (std::max(std::max(v0.screenpos.y, v1.screenpos.y), v2.screenpos.y) + 0xF) & ~0xF;
DrawingCoords scissorTL(gstate.getScissorX1(), gstate.getScissorY1(), 0);
DrawingCoords scissorBR(gstate.getScissorX2(), gstate.getScissorY2(), 0);
@@ -1362,24 +1365,37 @@ void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData&
maxY = std::min(maxY, (int)TransformUnit::DrawingToScreen(scissorBR).y);
// 32 because we do two pixels at once, and we don't want overlap.
int range = (maxY - minY) / 32 + 1;
if (gstate.isModeClear()) {
if (range >= 12 && (maxX - minX) >= 24 * 16) {
int rangeY = (maxY - minY) / 32 + 1;
int rangeX = (maxX - minX) / 32 + 1;
if (rangeY >= 12 && rangeX >= rangeY * 4) {
if (gstate.isModeClear()) {
auto bound = [&](int a, int b) -> void {
DrawTriangleSlice<true>(v0, v1, v2, minX, minY, maxX, maxY, a, b);
DrawTriangleSlice<true>(v0, v1, v2, minX, minY, maxX, maxY, false, a, b);
};
GlobalThreadPool::Loop(bound, 0, range);
GlobalThreadPool::Loop(bound, 0, rangeX);
} else {
DrawTriangleSlice<true>(v0, v1, v2, minX, minY, maxX, maxY, 0, range);
auto bound = [&](int a, int b) -> void {
DrawTriangleSlice<false>(v0, v1, v2, minX, minY, maxX, maxY, false, a, b);
};
GlobalThreadPool::Loop(bound, 0, rangeX);
}
} else if (rangeY >= 12 && rangeX >= 12) {
if (gstate.isModeClear()) {
auto bound = [&](int a, int b) -> void {
DrawTriangleSlice<true>(v0, v1, v2, minX, minY, maxX, maxY, true, a, b);
};
GlobalThreadPool::Loop(bound, 0, rangeY);
} else {
auto bound = [&](int a, int b) -> void {
DrawTriangleSlice<false>(v0, v1, v2, minX, minY, maxX, maxY, true, a, b);
};
GlobalThreadPool::Loop(bound, 0, rangeY);
}
} else {
if (range >= 12 && (maxX - minX) >= 24 * 16) {
auto bound = [&](int a, int b) -> void {
DrawTriangleSlice<false>(v0, v1, v2, minX, minY, maxX, maxY, a, b);
};
GlobalThreadPool::Loop(bound, 0, range);
if (gstate.isModeClear()) {
DrawTriangleSlice<true>(v0, v1, v2, minX, minY, maxX, maxY, true, 0, rangeY);
} else {
DrawTriangleSlice<false>(v0, v1, v2, minX, minY, maxX, maxY, 0, range);
DrawTriangleSlice<false>(v0, v1, v2, minX, minY, maxX, maxY, true, 0, rangeY);
}
}
}
@@ -1460,6 +1476,138 @@ void DrawPoint(const VertexData &v0)
}
}
void ClearRectangle(const VertexData &v0, const VertexData &v1)
{
int minX = std::min(v0.screenpos.x, v1.screenpos.x) & ~0xF;
int minY = std::min(v0.screenpos.y, v1.screenpos.y) & ~0xF;
int maxX = (std::max(v0.screenpos.x, v1.screenpos.x) + 0xF) & ~0xF;
int maxY = (std::max(v0.screenpos.y, v1.screenpos.y) + 0xF) & ~0xF;
DrawingCoords scissorTL(gstate.getScissorX1(), gstate.getScissorY1(), 0);
DrawingCoords scissorBR(gstate.getScissorX2(), gstate.getScissorY2(), 0);
minX = std::max(minX, (int)TransformUnit::DrawingToScreen(scissorTL).x);
maxX = std::max(0, std::min(maxX, (int)TransformUnit::DrawingToScreen(scissorBR).x));
minY = std::max(minY, (int)TransformUnit::DrawingToScreen(scissorTL).y);
maxY = std::max(0, std::min(maxY, (int)TransformUnit::DrawingToScreen(scissorBR).y));
const int w = (maxX - minX) / 16;
if (w <= 0)
return;
if (gstate.isClearModeDepthMask()) {
ScreenCoords pprime(minX, minY, 0);
const u16 z = v1.screenpos.z;
const int stride = gstate.DepthBufStride();
for (pprime.y = minY; pprime.y < maxY; pprime.y += 16) {
DrawingCoords p = TransformUnit::ScreenToDrawing(pprime);
if ((z & 0xFF) == (z >> 8)) {
u16 *row = &depthbuf.as16[p.x + p.y * stride];
memset(row, z, w * 2);
} else {
for (int x = 0; x < w; ++x) {
SetPixelDepth(p.x + x, p.y, z);
}
}
}
}
const u32 new_color = v1.color0.ToRGBA();
u16 new_color16;
// Note: this stays 0xFFFFFFFF if keeping color and alpha, even for 16-bit.
u32 keepOldMask = 0xFFFFFFFF;
switch (gstate.FrameBufFormat()) {
case GE_FORMAT_565:
new_color16 = RGBA8888ToRGB565(new_color);
if (gstate.isClearModeColorMask())
keepOldMask = 0;
break;
case GE_FORMAT_5551:
new_color16 = RGBA8888ToRGBA5551(new_color);
if (gstate.isClearModeColorMask())
keepOldMask &= 0x00008000;
if (gstate.isClearModeAlphaMask())
keepOldMask &= 0x00007FFF;
break;
case GE_FORMAT_4444:
new_color16 = RGBA8888ToRGBA4444(new_color);
if (gstate.isClearModeColorMask())
keepOldMask &= 0x0000F000;
if (gstate.isClearModeAlphaMask())
keepOldMask &= 0x00000FFF;
break;
case GE_FORMAT_8888:
if (gstate.isClearModeColorMask())
keepOldMask &= 0xFF000000;
if (gstate.isClearModeAlphaMask())
keepOldMask &= 0x00FFFFFF;
break;
case GE_FORMAT_INVALID:
_dbg_assert_msg_(G3D, false, "Software: invalid framebuf format.");
break;
}
if (keepOldMask == 0) {
ScreenCoords pprime(minX, minY, 0);
const int stride = gstate.FrameBufStride();
if (gstate.FrameBufFormat() == GE_FORMAT_8888) {
for (pprime.y = minY; pprime.y < maxY; pprime.y += 16) {
DrawingCoords p = TransformUnit::ScreenToDrawing(pprime);
if ((new_color & 0xFF) == (new_color >> 8) && (new_color && 0xFFFF) == (new_color >> 16)) {
u32 *row = &fb.as32[p.x + p.y * stride];
memset(row, new_color, w * 4);
} else {
for (int x = 0; x < w; ++x) {
fb.Set32(p.x + x, p.y, stride, new_color);
}
}
}
} else {
for (pprime.y = minY; pprime.y < maxY; pprime.y += 16) {
DrawingCoords p = TransformUnit::ScreenToDrawing(pprime);
if ((new_color16 & 0xFF) == (new_color16 >> 8)) {
u16 *row = &fb.as16[p.x + p.y * stride];
memset(row, new_color16, w * 2);
} else {
for (int x = 0; x < w; ++x) {
fb.Set16(p.x + x, p.y, stride, new_color16);
}
}
}
}
} else if (keepOldMask != 0xFFFFFFFF) {
ScreenCoords pprime(minX, minY, 0);
const int stride = gstate.FrameBufStride();
if (gstate.FrameBufFormat() == GE_FORMAT_8888) {
for (pprime.y = minY; pprime.y < maxY; pprime.y += 16) {
DrawingCoords p = TransformUnit::ScreenToDrawing(pprime);
for (int x = 0; x < w; ++x) {
const u32 old_color = fb.Get32(p.x + x, p.y, stride);
const u32 c = (old_color & keepOldMask) | (new_color & ~keepOldMask);
fb.Set32(p.x + x, p.y, stride, c);
}
}
} else {
for (pprime.y = minY; pprime.y < maxY; pprime.y += 16) {
DrawingCoords p = TransformUnit::ScreenToDrawing(pprime);
for (int x = 0; x < w; ++x) {
const u16 old_color = fb.Get16(p.x + x, p.y, stride);
const u16 c = (old_color & keepOldMask) | (new_color16 & ~keepOldMask);
fb.Set16(p.x + x, p.y, stride, c);
}
}
}
}
}
void DrawLine(const VertexData &v0, const VertexData &v1)
{
// TODO: Use a proper line drawing algorithm that handles fractional endpoints correctly.
+1
View File
@@ -27,6 +27,7 @@ namespace Rasterizer {
void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& v2);
void DrawPoint(const VertexData &v0);
void DrawLine(const VertexData &v0, const VertexData &v1);
void ClearRectangle(const VertexData &v0, const VertexData &v1);
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer);
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level);
+12 -3
View File
@@ -155,22 +155,31 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
fbTex = nullptr;
}
// For accuracy, try to handle 0 stride - sometimes used.
if (displayStride_ == 0) {
srcheight = 1;
}
Draw::TextureDesc desc{};
desc.type = Draw::TextureType::LINEAR2D;
desc.format = Draw::DataFormat::R8G8B8A8_UNORM;
desc.depth = 1;
desc.mipLevels = 1;
bool hasImage = true;
if (!Memory::IsValidAddress(displayFramebuf_)) {
if (!Memory::IsValidAddress(displayFramebuf_) || srcwidth == 0 || srcheight == 0) {
hasImage = false;
u1 = 1.0f;
} else if (displayFormat_ == GE_FORMAT_8888) {
u8 *data = Memory::GetPointer(displayFramebuf_);
desc.width = displayStride_;
desc.width = displayStride_ == 0 ? srcwidth : displayStride_;
desc.height = srcheight;
desc.initData.push_back(data);
desc.format = Draw::DataFormat::R8G8B8A8_UNORM;
u1 = (float)srcwidth / displayStride_;
if (displayStride_ != 0) {
u1 = (float)srcwidth / displayStride_;
} else {
u1 = 1.0f;
}
} else {
// TODO: This should probably be converted in a shader instead..
fbTexBuffer.resize(srcwidth * srcheight);
+64 -127
View File
@@ -67,9 +67,7 @@ enum {
DRAW_BINDING_DYNUBO_BASE = 2,
DRAW_BINDING_DYNUBO_LIGHT = 3,
DRAW_BINDING_DYNUBO_BONE = 4,
DRAW_BINDING_TESS_POS_TEXTURE = 5,
DRAW_BINDING_TESS_TEX_TEXTURE = 6,
DRAW_BINDING_TESS_COL_TEXTURE = 7,
DRAW_BINDING_TESS_STORAGE_BUF = 5,
};
enum {
@@ -97,7 +95,7 @@ DrawEngineVulkan::DrawEngineVulkan(VulkanContext *vulkan, Draw::DrawContext *dra
void DrawEngineVulkan::InitDeviceObjects() {
// All resources we need for PSP drawing. Usually only bindings 0 and 2-4 are populated.
VkDescriptorSetLayoutBinding bindings[8];
VkDescriptorSetLayoutBinding bindings[6];
bindings[0].descriptorCount = 1;
bindings[0].pImmutableSamplers = nullptr;
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
@@ -123,37 +121,28 @@ void DrawEngineVulkan::InitDeviceObjects() {
bindings[4].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
bindings[4].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings[4].binding = DRAW_BINDING_DYNUBO_BONE;
// Hardware tessellation. TODO: Don't allocate these unless actually drawing splines.
// Will require additional
// Used only for hardware tessellation.
bindings[5].descriptorCount = 1;
bindings[5].pImmutableSamplers = nullptr;
bindings[5].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[5].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
bindings[5].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings[5].binding = DRAW_BINDING_TESS_POS_TEXTURE;
bindings[6].descriptorCount = 1;
bindings[6].pImmutableSamplers = nullptr;
bindings[6].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[6].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings[6].binding = DRAW_BINDING_TESS_TEX_TEXTURE;
bindings[7].descriptorCount = 1;
bindings[7].pImmutableSamplers = nullptr;
bindings[7].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[7].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings[7].binding = DRAW_BINDING_TESS_COL_TEXTURE;
bindings[5].binding = DRAW_BINDING_TESS_STORAGE_BUF;
VkDevice device = vulkan_->GetDevice();
VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
dsl.bindingCount = 8;
dsl.bindingCount = ARRAY_SIZE(bindings);
dsl.pBindings = bindings;
VkResult res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_);
assert(VK_SUCCESS == res);
VkDescriptorPoolSize dpTypes[2];
VkDescriptorPoolSize dpTypes[3];
dpTypes[0].descriptorCount = 8192;
dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
dpTypes[1].descriptorCount = 8192 + 4096; // Due to the tess stuff, we need a LOT of these. Most will be empty...
dpTypes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
dpTypes[2].descriptorCount = 2048;
dpTypes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
VkDescriptorPoolCreateInfo dp = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
dp.pNext = nullptr;
@@ -509,6 +498,10 @@ void DrawEngineVulkan::DecodeVerts(VulkanPushBuffer *push, uint32_t *bindOffset,
}
}
void DrawEngineVulkan::SetLineWidth(float lineWidth) {
pipelineManager_->SetLineWidth(lineWidth);
}
VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone) {
DescriptorSetKey key;
key.imageView_ = imageView;
@@ -517,12 +510,15 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
key.base_ = base;
key.light_ = light;
key.bone_ = bone;
assert(base != VK_NULL_HANDLE);
assert(light != VK_NULL_HANDLE);
assert(bone != VK_NULL_HANDLE);
_dbg_assert_(G3D, base != VK_NULL_HANDLE);
_dbg_assert_(G3D, light != VK_NULL_HANDLE);
_dbg_assert_(G3D, bone != VK_NULL_HANDLE);
bool tess = gstate_c.bezier || gstate_c.spline;
FrameData *frame = &frame_[vulkan_->GetCurFrame()];
if (!gstate_c.bezier && !gstate_c.spline) { // Has no cache when HW tessellation.
// See if we already have this descriptor set cached.
if (!tess) { // Don't cache descriptors for HW tessellation.
VkDescriptorSet d = frame->descSets.Get(key);
if (d != VK_NULL_HANDLE)
return d;
@@ -579,29 +575,27 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
// Skipping 2nd texture for now.
// Tessellation data textures
if (gstate_c.bezier || gstate_c.spline) {
VkDescriptorImageInfo tess_tex[3]{};
VkSampler sampler = ((TessellationDataTransferVulkan *)tessDataTransfer)->GetSampler();
for (int i = 0; i < 3; i++) {
VulkanTexture *texture = ((TessellationDataTransferVulkan *)tessDataTransfer)->GetTexture(i);
if (texture) {
assert(texture->GetImageView());
VkImageView imageView = texture->GetImageView();
tess_tex[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
tess_tex[i].imageView = imageView;
tess_tex[i].sampler = sampler;
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writes[n].pNext = nullptr;
writes[n].dstBinding = DRAW_BINDING_TESS_POS_TEXTURE + i;
writes[n].pImageInfo = &tess_tex[i];
writes[n].descriptorCount = 1;
writes[n].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writes[n].dstSet = desc;
n++;
}
}
// Tessellation data buffer. Make sure this is declared outside the if to avoid optimizer
// shenanigans.
VkDescriptorBufferInfo tess_buf{};
if (tess) {
VkBuffer buf;
VkDeviceSize offset;
VkDeviceSize range;
((TessellationDataTransferVulkan *)tessDataTransfer)->GetBufferAndOffset(&buf, &offset, &range);
assert(buf);
tess_buf.buffer = buf;
tess_buf.offset = offset;
tess_buf.range = range;
tessOffset_ = offset;
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writes[n].pNext = nullptr;
writes[n].dstBinding = DRAW_BINDING_TESS_STORAGE_BUF;
writes[n].pBufferInfo = &tess_buf;
writes[n].descriptorCount = 1;
writes[n].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
writes[n].dstSet = desc;
n++;
}
// Uniform buffer objects
@@ -1003,7 +997,7 @@ void DrawEngineVulkan::DoFlush() {
}
lastPipeline_ = pipeline;
}
ApplyDrawStateLate(renderManager, false, 0, pipeline->useBlendConstant);
ApplyDrawStateLate(renderManager, result.setStencil, result.stencilValue, pipeline->useBlendConstant);
gstate_c.Clean(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
lastPipeline_ = pipeline;
}
@@ -1091,97 +1085,40 @@ void DrawEngineVulkan::UpdateUBOs(FrameData *frame) {
DrawEngineVulkan::TessellationDataTransferVulkan::TessellationDataTransferVulkan(VulkanContext *vulkan, Draw::DrawContext *draw)
: TessellationDataTransfer(), vulkan_(vulkan), draw_(draw) {
CreateSampler();
}
DrawEngineVulkan::TessellationDataTransferVulkan::~TessellationDataTransferVulkan() {
for (int i = 0; i < 3; i++)
delete data_tex[i];
vulkan_->Delete().QueueDeleteSampler(sampler);
}
// TODO: Consolidate the three textures into one, with height 3.
// This can be done for all the backends.
void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&pos, float *&tex, float *&col, int size, bool hasColor, bool hasTexCoords) {
// TODO: Actually, even better, avoid the usage of textures altogether and just use shader storage buffers from the current pushbuffer.
void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) {
colStride = 4;
assert(size > 0);
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
// Position
delete data_tex[0];
data_tex[0] = new VulkanTexture(vulkan_, nullptr); // TODO: Should really use an allocator.
bool success = data_tex[0]->CreateDirect(cmd, size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
assert(success);
// TODO: This SHOULD work without padding but I can't get it to work on nvidia, so had
// to expand to vec4. Driver bug?
struct TessData {
float pos[3]; float pad1;
float uv[2]; float pad2[2];
float color[4];
};
pos = (float *)push_->Push(size * sizeof(float) * 4, &posOffset_, &posBuf_);
posSize_ = size;
int ssboAlignment = vulkan_->GetPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
uint8_t *data = (uint8_t *)push_->PushAligned(size * sizeof(TessData), &offset_, &buf_, ssboAlignment);
range_ = size * sizeof(TessData);
// Texcoords
delete data_tex[1];
if (hasTexCoords) {
data_tex[1] = new VulkanTexture(vulkan_, nullptr); // TODO: Should really use an allocator.
success = data_tex[1]->CreateDirect(cmd, size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
assert(success);
tex = (float *)push_->Push(size * sizeof(float) * 4, &texOffset_, &texBuf_);
texSize_ = size;
} else {
data_tex[1] = nullptr;
tex = nullptr;
texSize_ = 0;
}
// Color
colSize_ = hasColor ? size : 1;
delete data_tex[2];
data_tex[2] = new VulkanTexture(vulkan_, nullptr); // TODO: Should really use an allocator.
success = data_tex[2]->CreateDirect(cmd, colSize_, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
assert(success);
col = (float *)push_->Push(colSize_ * sizeof(float) * 4, &colOffset_, &colBuf_);
pos = (float *)(data);
tex = (float *)(data + offsetof(TessData, uv));
col = (float *)(data + offsetof(TessData, color));
posStride = sizeof(TessData) / sizeof(float);
colStride = hasColor ? (sizeof(TessData) / sizeof(float)) : 0;
texStride = sizeof(TessData) / sizeof(float);
}
void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) {
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
// Position
data_tex[0]->UploadMip(cmd, 0, posSize_, 1, posBuf_, posOffset_, posSize_);
data_tex[0]->EndCreate(cmd, true);
// Texcoords
if (hasTexCoords) {
data_tex[1]->UploadMip(cmd, 0, texSize_, 1, texBuf_, texOffset_, texSize_);
data_tex[1]->EndCreate(cmd, true);
}
// Color
data_tex[2]->UploadMip(cmd, 0, colSize_, 1, colBuf_, colOffset_, colSize_);
data_tex[2]->EndCreate(cmd, true);
}
void DrawEngineVulkan::TessellationDataTransferVulkan::CreateSampler() {
VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samp.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samp.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samp.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
samp.compareOp = VK_COMPARE_OP_NEVER;
samp.flags = 0;
samp.magFilter = VK_FILTER_NEAREST;
samp.minFilter = VK_FILTER_NEAREST;
samp.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) {
// Docs say the min of this value and the supported max are used.
samp.maxAnisotropy = 1 << g_Config.iAnisotropyLevel;
samp.anisotropyEnable = true;
} else {
samp.maxAnisotropy = 1.0f;
samp.anisotropyEnable = false;
}
samp.maxLod = 1.0f;
samp.minLod = 0.0f;
samp.mipLodBias = 0.0f;
VkResult res = vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &sampler);
assert(res == VK_SUCCESS);
assert(pos);
// Nothing to do here!
}
+19 -16
View File
@@ -33,6 +33,7 @@
#include <unordered_map>
#include "Common/Hashmaps.h"
#include "Common/Vulkan/VulkanMemory.h"
#include "GPU/Vulkan/VulkanUtil.h"
@@ -175,6 +176,8 @@ public:
return stats_;
}
void SetLineWidth(float lineWidth);
private:
struct FrameData;
void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant);
@@ -259,6 +262,8 @@ private:
VulkanPipelineRasterStateKey pipelineKey_{};
VulkanDynamicState dynState_{};
int tessOffset_ = 0;
// Hardware tessellation
class TessellationDataTransferVulkan : public TessellationDataTransfer {
public:
@@ -267,28 +272,26 @@ private:
void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; }
void SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) override;
void PrepareBuffers(float *&pos, float *&tex, float *&col, int size, bool hasColor, bool hasTexCoords) override;
void PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) override;
VulkanTexture *GetTexture(int i) const { return data_tex[i]; }
void GetBufferAndOffset(VkBuffer *buf, VkDeviceSize *offset, VkDeviceSize *range) {
*buf = buf_;
*offset = (VkDeviceSize)offset_;
*range = (VkDeviceSize)range_;
buf_ = 0;
offset_ = 0;
range_ = 0;
}
VkSampler GetSampler() const { return sampler; }
void CreateSampler();
private:
VulkanContext *vulkan_;
Draw::DrawContext *draw_;
VulkanTexture *data_tex[3]{};
VkSampler sampler = VK_NULL_HANDLE;
VulkanPushBuffer *push_; // Updated each frame.
int posSize_ = 0;
uint32_t posOffset_ = 0;
VkBuffer posBuf_ = 0;
int texSize_ = 0;
uint32_t texOffset_ = 0;
VkBuffer texBuf_ = 0;
int colSize_ = 0;
uint32_t colOffset_ = 0;
VkBuffer colBuf_ = 0;
int size_ = 0;
uint32_t offset_ = 0;
uint32_t range_ = 0;
VkBuffer buf_ = VK_NULL_HANDLE;
};
};
+97 -24
View File
@@ -23,6 +23,8 @@
#include "base/timeutil.h"
#include "math/lin/matrix4x4.h"
#include "math/dataconv.h"
#include "i18n/i18n.h"
#include "ext/native/file/vfs.h"
#include "ext/native/thin3d/thin3d.h"
#include "Common/Vulkan/VulkanContext.h"
@@ -39,6 +41,7 @@
#include "GPU/ge_constants.h"
#include "GPU/GPUState.h"
#include "GPU/Common/ShaderTranslation.h"
#include "GPU/Common/PostShader.h"
#include "GPU/Common/TextureDecoder.h"
#include "GPU/Common/FramebufferCommon.h"
@@ -155,6 +158,12 @@ void FramebufferManagerVulkan::DestroyDeviceObjects() {
vulkan_->Delete().QueueDeleteSampler(linearSampler_);
if (nearestSampler_ != VK_NULL_HANDLE)
vulkan_->Delete().QueueDeleteSampler(nearestSampler_);
if (postVs_)
vulkan_->Delete().QueueDeleteShaderModule(postVs_);
if (postFs_)
vulkan_->Delete().QueueDeleteShaderModule(postFs_);
pipelinePostShader_ = VK_NULL_HANDLE; // actual pipeline should get destroyed by vulkan2d.
}
void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth) {
@@ -180,28 +189,6 @@ void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, boo
}
}
void FramebufferManagerVulkan::UpdatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight) {
float u_delta = 1.0f / renderWidth;
float v_delta = 1.0f / renderHeight;
float u_pixel_delta = u_delta;
float v_pixel_delta = v_delta;
if (postShaderAtOutputResolution_) {
float x, y, w, h;
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL);
u_pixel_delta = (1.0f / w) * (480.0f / bufferWidth);
v_pixel_delta = (1.0f / h) * (272.0f / bufferHeight);
}
postUniforms_.texelDelta[0] = u_delta;
postUniforms_.texelDelta[1] = v_delta;
postUniforms_.pixelDelta[0] = u_pixel_delta;
postUniforms_.pixelDelta[1] = v_pixel_delta;
int flipCount = __DisplayGetFlipCount();
int vCount = __DisplayGetVCount();
float time[4] = { time_now(), (vCount % 60) * 1.0f / 60.0f, (float)vCount, (float)(flipCount % 60) };
memcpy(postUniforms_.time, time, 4 * sizeof(float));
}
void FramebufferManagerVulkan::Init() {
FramebufferManagerCommon::Init();
// Workaround for upscaling shaders where we force x1 resolution without saving it
@@ -349,6 +336,9 @@ void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, floa
VkBuffer vbuffer;
VkDeviceSize offset = push_->Push(vtx, sizeof(vtx), &vbuffer);
renderManager->BindPipeline(cur2DPipeline_);
if (cur2DPipeline_ == pipelinePostShader_) {
renderManager->PushConstants(vulkan2D_->GetPipelineLayout(), VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT, 0, (int)sizeof(postShaderUniforms_), &postShaderUniforms_);
}
renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, vbuffer, offset, 4);
}
@@ -358,7 +348,22 @@ void FramebufferManagerVulkan::Bind2DShader() {
}
void FramebufferManagerVulkan::BindPostShader(const PostShaderUniforms &uniforms) {
Bind2DShader();
if (!pipelinePostShader_) {
if (usePostShader_) {
CompilePostShader();
}
if (!usePostShader_) {
SetNumExtraFBOs(0);
Bind2DShader();
return;
} else {
SetNumExtraFBOs(1);
}
}
postShaderUniforms_ = uniforms;
cur2DPipeline_ = pipelinePostShader_;
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
}
@@ -462,7 +467,7 @@ VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, V
bool FramebufferManagerVulkan::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
nvfb->colorDepth = Draw::FBO_8888;
nvfb->fbo = draw_->CreateFramebuffer({ nvfb->width, nvfb->height, 1, 1, true, (Draw::FBColorDepth)nvfb->colorDepth });
nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->height, 1, 1, true, (Draw::FBColorDepth)nvfb->colorDepth });
if (!(nvfb->fbo)) {
ERROR_LOG(FRAMEBUF, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight);
return false;
@@ -626,4 +631,72 @@ void FramebufferManagerVulkan::Resized() {
if (UpdateSize()) {
DestroyAllFBOs();
}
// Might have a new post shader - let's compile it.
CompilePostShader();
}
void FramebufferManagerVulkan::CompilePostShader() {
if (postVs_) {
vulkan_->Delete().QueueDeleteShaderModule(postVs_);
}
if (postFs_) {
vulkan_->Delete().QueueDeleteShaderModule(postFs_);
}
const ShaderInfo *shaderInfo = nullptr;
if (g_Config.sPostShaderName == "Off") {
usePostShader_ = false;
return;
}
usePostShader_ = false;
ReloadAllPostShaderInfo();
shaderInfo = GetPostShaderInfo(g_Config.sPostShaderName);
std::string errorVSX, errorFSX;
std::string vsSource;
std::string fsSource;
if (shaderInfo) {
postShaderAtOutputResolution_ = shaderInfo->outputResolution;
size_t sz;
char *vs = (char *)VFSReadFile(shaderInfo->vertexShaderFile.c_str(), &sz);
if (!vs)
return;
char *fs = (char *)VFSReadFile(shaderInfo->fragmentShaderFile.c_str(), &sz);
if (!fs) {
free(vs);
return;
}
std::string vsSourceGLSL = vs;
std::string fsSourceGLSL = fs;
free(vs);
free(fs);
TranslatedShaderMetadata metaVS, metaFS;
if (!TranslateShader(&vsSource, GLSL_VULKAN, &metaVS, vsSourceGLSL, GLSL_140, Draw::ShaderStage::VERTEX, &errorVSX))
return;
if (!TranslateShader(&fsSource, GLSL_VULKAN, &metaFS, fsSourceGLSL, GLSL_140, Draw::ShaderStage::FRAGMENT, &errorFSX))
return;
} else {
return;
}
I18NCategory *gr = GetI18NCategory("Graphics");
// TODO: Delete the old pipeline?
std::string errorVS;
std::string errorFS;
postVs_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, vsSource.c_str(), &errorVS);
postFs_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, fsSource.c_str(), &errorFS);
VkRenderPass backbufferRP = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_RENDERPASS);
if (postVs_ && postFs_) {
pipelinePostShader_ = vulkan2D_->GetPipeline(backbufferRP, postVs_, postFs_, true, Vulkan2D::VK2DDepthStencilMode::NONE);
} else {
ELOG("Failed to compile.");
}
usePostShader_ = true;
}
+8 -5
View File
@@ -86,6 +86,7 @@ public:
void NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth);
protected:
void CompilePostShader();
void Bind2DShader() override;
void BindPostShader(const PostShaderUniforms &uniforms) override;
void SetViewport2D(int x, int y, int w, int h) override;
@@ -100,8 +101,6 @@ private:
// The returned texture does not need to be free'd, might be returned from a pool (currently single entry)
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
void UpdatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight);
void InitDeviceObjects();
void DestroyDeviceObjects();
@@ -130,16 +129,20 @@ private:
VkPipelineCache pipelineCache2D_;
// Basic shaders
VkShaderModule fsBasicTex_;
VkShaderModule vsBasicTex_;
VkShaderModule fsBasicTex_ = VK_NULL_HANDLE;
VkShaderModule vsBasicTex_ = VK_NULL_HANDLE;
VkShaderModule stencilVs_ = VK_NULL_HANDLE;
VkShaderModule stencilFs_ = VK_NULL_HANDLE;
VkPipeline cur2DPipeline_ = VK_NULL_HANDLE;
// Postprocessing
VkPipeline pipelinePostShader_;
VkShaderModule postVs_ = VK_NULL_HANDLE;
VkShaderModule postFs_ = VK_NULL_HANDLE;
VkPipeline pipelinePostShader_ = VK_NULL_HANDLE;
PostShaderUniforms postShaderUniforms_;
VkSampler linearSampler_;
VkSampler nearestSampler_;
+7 -1
View File
@@ -95,11 +95,11 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
drawEngine_.SetFramebufferManager(framebufferManagerVulkan_);
drawEngine_.SetShaderManager(shaderManagerVulkan_);
drawEngine_.SetPipelineManager(pipelineManager_);
framebufferManagerVulkan_->SetVulkan2D(&vulkan2D_);
framebufferManagerVulkan_->Init();
framebufferManagerVulkan_->SetTextureCache(textureCacheVulkan_);
framebufferManagerVulkan_->SetDrawEngine(&drawEngine_);
framebufferManagerVulkan_->SetShaderManager(shaderManagerVulkan_);
framebufferManagerVulkan_->SetVulkan2D(&vulkan2D_);
textureCacheVulkan_->SetDepalShaderCache(&depalShaderCache_);
textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_);
textureCacheVulkan_->SetShaderManager(shaderManagerVulkan_);
@@ -158,6 +158,9 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
UpdateVsyncInterval(true);
textureCacheVulkan_->NotifyConfigChanged();
if (vulkan_->GetFeaturesEnabled().wideLines) {
drawEngine_.SetLineWidth(PSP_CoreParameter().renderWidth / 480.0f);
}
}
GPU_Vulkan::~GPU_Vulkan() {
@@ -221,6 +224,9 @@ void GPU_Vulkan::BeginHostFrame() {
framebufferManager_->Resized();
drawEngine_.Resized();
textureCacheVulkan_->NotifyConfigChanged();
if (vulkan_->GetFeaturesEnabled ().wideLines) {
drawEngine_.SetLineWidth(PSP_CoreParameter().renderWidth / 480.0f);
}
}
resized_ = false;
+19 -3
View File
@@ -121,7 +121,7 @@ static bool UsesBlendConstant(int factor) {
static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pipelineCache,
VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &key,
const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) {
const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, float lineWidth) {
bool useBlendConstant = false;
VkPipelineColorBlendAttachmentState blend0 = {};
@@ -188,7 +188,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
rs.depthBiasEnable = false;
rs.cullMode = key.cullMode;
rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rs.lineWidth = 1.0f;
rs.lineWidth = lineWidth;
rs.rasterizerDiscardEnable = false;
rs.polygonMode = VK_POLYGON_MODE_FILL;
rs.depthClampEnable = false;
@@ -289,6 +289,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
vulkanPipeline->pipeline = pipeline;
vulkanPipeline->uniformBlocks = UB_VS_FS_BASE;
vulkanPipeline->useBlendConstant = useBlendConstant;
vulkanPipeline->usesLines = key.topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST || key.topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
if (useHwTransform) {
if (vs->HasLights()) {
vulkanPipeline->uniformBlocks |= UB_VS_LIGHTS;
@@ -320,7 +321,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo
VulkanPipeline *pipeline = CreateVulkanPipeline(
vulkan_->GetDevice(), pipelineCache_, layout, renderPass,
rasterKey, vtxDec, vs, fs, useHwTransform);
rasterKey, vtxDec, vs, fs, useHwTransform, lineWidth_);
// Even if the result is nullptr, insert it so we don't try to create it repeatedly.
pipelines_.Insert(key, pipeline);
return pipeline;
@@ -370,3 +371,18 @@ std::string PipelineManagerVulkan::DebugGetObjectString(std::string id, DebugSha
return "N/A";
}
}
void PipelineManagerVulkan::SetLineWidth(float lineWidth) {
if (lineWidth_ == lineWidth)
return;
lineWidth_ = lineWidth;
// Wipe all line-drawing pipelines.
pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) {
if (value->usesLines) {
vulkan_->Delete().QueueDeletePipeline(value->pipeline);
delete value;
pipelines_.Remove(key);
}
});
}
+4
View File
@@ -65,6 +65,7 @@ struct VulkanPipeline {
VkPipeline pipeline;
int uniformBlocks; // UB_ enum above.
bool useBlendConstant;
bool usesLines;
};
class VulkanContext;
@@ -81,6 +82,8 @@ public:
void Clear();
void SetLineWidth(float lw);
void DeviceLost();
void DeviceRestore(VulkanContext *vulkan);
@@ -91,4 +94,5 @@ private:
DenseHashMap<VulkanPipelineKey, VulkanPipeline *, nullptr> pipelines_;
VkPipelineCache pipelineCache_;
VulkanContext *vulkan_;
float lineWidth_ = 1.0f;
};
+13 -9
View File
@@ -38,7 +38,7 @@
#include "GPU/Vulkan/ShaderManagerVulkan.h"
static const char *vulkan_glsl_preamble =
"#version 400\n"
"#version 430\n"
"#extension GL_ARB_separate_shader_objects : enable\n"
"#extension GL_ARB_shading_language_420pack : enable\n\n";
@@ -224,9 +224,14 @@ bool GenerateVulkanGLSLVertexShader(const ShaderID &id, char *buffer, bool *uses
WRITE(p, "out gl_PerVertex { vec4 gl_Position; };\n");
if (doBezier || doSpline) {
WRITE(p, "layout (binding = 5) uniform sampler2D u_tess_pos_tex;\n");
WRITE(p, "layout (binding = 6) uniform sampler2D u_tess_tex_tex;\n");
WRITE(p, "layout (binding = 7) uniform sampler2D u_tess_col_tex;\n");
WRITE(p, "layout (std430) struct TessData {\n");
WRITE(p, " vec4 pos;\n");
WRITE(p, " vec4 uv;\n");
WRITE(p, " vec4 color;\n");
WRITE(p, "};");
WRITE(p, "layout (std430, set = 0, binding = 5) buffer s_tess_data {\n");
WRITE(p, " TessData data[];");
WRITE(p, "} tess_data;");
for (int i = 2; i <= 4; i++) {
// Define 3 types vec2, vec3, vec4
@@ -347,12 +352,11 @@ bool GenerateVulkanGLSLVertexShader(const ShaderID &id, char *buffer, bool *uses
WRITE(p, " for (int i = 0; i < 4; i++) {\n");
WRITE(p, " for (int j = 0; j < 4; j++) {\n");
WRITE(p, " int idx = (i + v%s) * base.spline_count_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : "");
WRITE(p, " ivec2 index = ivec2(idx, 0);\n");
WRITE(p, " _pos[i * 4 + j] = texelFetch(u_tess_pos_tex, index, 0).xyz;\n");
WRITE(p, " _pos[i * 4 + j] = tess_data.data[idx].pos.xyz;\n");
if (doTexture && hasTexcoord && hasTexcoordTess)
WRITE(p, " _tex[i * 4 + j] = texelFetch(u_tess_tex_tex, index, 0).xy;\n");
WRITE(p, " _tex[i * 4 + j] = tess_data.data[idx].uv.xy;\n");
if (hasColor && hasColorTess)
WRITE(p, " _col[i * 4 + j] = texelFetch(u_tess_col_tex, index, 0).rgba;\n");
WRITE(p, " _col[i * 4 + j] = tess_data.data[idx].color;\n");
WRITE(p, " }\n");
WRITE(p, " }\n");
WRITE(p, " vec2 tess_pos = position.xy;\n");
@@ -381,7 +385,7 @@ bool GenerateVulkanGLSLVertexShader(const ShaderID &id, char *buffer, bool *uses
if (hasColorTess)
WRITE(p, " vec4 col = tess_sample(_col, weights);\n");
else
WRITE(p, " vec4 col = texelFetch(u_tess_col_tex, ivec2(0, 0), 0).rgba;\n");
WRITE(p, " vec4 col = tess_data.data[0].color;\n");
}
if (hasNormal) {
// Curved surface is probably always need to compute normal(not sampling from control points)
+4 -3
View File
@@ -63,12 +63,13 @@ void Vulkan2D::DestroyDeviceObjects() {
void Vulkan2D::InitDeviceObjects() {
pipelineCache_ = vulkan_->CreatePipelineCache();
// All resources we need for PSP drawing. Usually only bindings 0 and 2-4 are populated.
VkDescriptorSetLayoutBinding bindings[2] = {};
// Texture.
bindings[0].descriptorCount = 1;
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
bindings[0].binding = 0;
// In depal, this second texture is used for the palette.
bindings[1].descriptorCount = 1;
bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
@@ -98,8 +99,8 @@ void Vulkan2D::InitDeviceObjects() {
VkPushConstantRange push = {};
push.offset = 0;
push.size = 16;
push.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
push.size = 48;
push.stageFlags = VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT;
VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
pl.pPushConstantRanges = &push;
+1 -1
View File
@@ -104,7 +104,7 @@ private:
VK2DDepthStencilMode depthStencilMode;
bool readVertices;
bool operator < (const PipelineKey &other) const {
return std::tie(vs, fs, rp, depthStencilMode, readVertices) < std::tie(other.vs, other.fs, other.rp, depthStencilMode, readVertices);
return std::tie(vs, fs, rp, depthStencilMode, readVertices) < std::tie(other.vs, other.fs, other.rp, other.depthStencilMode, other.readVertices);
}
};
+12 -3
View File
@@ -988,7 +988,11 @@ void EmuScreen::preRender() {
bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
if ((!useBufferedRendering && !g_Config.bSoftwareRendering) || Core_IsStepping()) {
// We need to clear here already so that drawing during the frame is done on a clean slate.
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 });
if (Core_IsStepping()) {
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE });
} else {
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 });
}
Viewport viewport;
viewport.TopLeftX = 0;
@@ -1052,6 +1056,9 @@ void EmuScreen::render() {
if (coreState == CORE_NEXTFRAME) {
// set back to running for the next frame
coreState = CORE_RUNNING;
} else if (coreState == CORE_STEPPING) {
// If we're stepping, it's convenient not to clear the screen.
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE });
} else {
// Didn't actually reach the end of the frame, ran out of the blockTicks cycles.
// In this case we need to bind and wipe the backbuffer, at least.
@@ -1063,8 +1070,10 @@ void EmuScreen::render() {
PSP_EndHostFrame();
if (invalid_)
return;
if (!osm.IsEmpty() || g_Config.bShowDebugStats || g_Config.iShowFPSCounter || g_Config.bShowTouchControls || g_Config.bShowDeveloperMenu || g_Config.bShowAudioDebug || saveStatePreview_->GetVisibility() != UI::V_GONE || g_Config.bShowFrameProfiler) {
const bool hasVisibleUI = !osm.IsEmpty() || saveStatePreview_->GetVisibility() != UI::V_GONE || g_Config.bShowTouchControls;
const bool showDebugUI = g_Config.bShowDebugStats || g_Config.bShowDeveloperMenu || g_Config.bShowAudioDebug || g_Config.bShowFrameProfiler;
if (hasVisibleUI || showDebugUI || g_Config.iShowFPSCounter != 0) {
// This sets up some important states but not the viewport.
screenManager()->getUIContext()->Begin();
+1
View File
@@ -223,6 +223,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/GPU/Common/TextureCacheCommon.cpp.arm \
$(SRC)/GPU/Common/TextureScalerCommon.cpp.arm \
$(SRC)/GPU/Common/ShaderCommon.cpp \
$(SRC)/GPU/Common/ShaderTranslation.cpp \
$(SRC)/GPU/Common/StencilCommon.cpp \
$(SRC)/GPU/Common/SplineCommon.cpp.arm \
$(SRC)/GPU/Common/DrawEngineCommon.cpp.arm \
+2
View File
@@ -89,6 +89,8 @@ const char *GetFn(const char *fn);
} \
} while (false)
#define DUMPLOG(x) OutputDebugStringUTF8(x)
#ifdef _DEBUG
#define DLOG(...) XLOG_IMPL("D", __VA_ARGS__)
#else
+20 -8
View File
@@ -4,19 +4,29 @@
// Debug help: adb logcat -s DEBUG PPSSPPNativeActivity PPSSPP
// TODO: This is only enough for 4x render resolution / 4x texture upscale for debugger.
// Maybe we should use a dynamically allocated one for larger?
const uint32_t readbackBufferSize = 2048 * 2048 * 4;
void VulkanQueueRunner::CreateDeviceObjects() {
ILOG("VulkanQueueRunner::CreateDeviceObjects");
InitBackbufferRenderPass();
InitRenderpasses();
}
void VulkanQueueRunner::ResizeReadbackBuffer(VkDeviceSize requiredSize) {
if (readbackBuffer_ && requiredSize <= readbackBufferSize_) {
return;
}
if (readbackMemory_) {
vulkan_->Delete().QueueDeleteDeviceMemory(readbackMemory_);
}
if (readbackBuffer_) {
vulkan_->Delete().QueueDeleteBuffer(readbackBuffer_);
}
readbackBufferSize_ = requiredSize;
VkDevice device = vulkan_->GetDevice();
VkBufferCreateInfo buf{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
buf.size = readbackBufferSize;
buf.size = readbackBufferSize_;
buf.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
vkCreateBuffer(device, &buf, nullptr, &readbackBuffer_);
@@ -40,10 +50,8 @@ void VulkanQueueRunner::DestroyDeviceObjects() {
ILOG("VulkanQueueRunner::DestroyDeviceObjects");
VkDevice device = vulkan_->GetDevice();
vulkan_->Delete().QueueDeleteDeviceMemory(readbackMemory_);
vkFreeMemory(device, readbackMemory_, nullptr);
readbackMemory_ = VK_NULL_HANDLE;
vulkan_->Delete().QueueDeleteBuffer(readbackBuffer_);
readbackBuffer_ = VK_NULL_HANDLE;
readbackBufferSize_ = 0;
for (int i = 0; i < ARRAY_SIZE(renderPasses_); i++) {
assert(renderPasses_[i] != VK_NULL_HANDLE);
@@ -845,6 +853,8 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd
vkCmdPipelineBarrier(cmd, stage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
}
ResizeReadbackBuffer(sizeof(uint32_t) * step.readback.srcRect.extent.width * step.readback.srcRect.extent.height);
VkBufferImageCopy region{};
region.imageOffset = { step.readback.srcRect.offset.x, step.readback.srcRect.offset.y, 0 };
region.imageExtent = { step.readback.srcRect.extent.width, step.readback.srcRect.extent.height, 1 };
@@ -869,6 +879,8 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe
SetupTransitionToTransferSrc(srcImage, barrier, stage, VK_IMAGE_ASPECT_COLOR_BIT);
vkCmdPipelineBarrier(cmd, stage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
ResizeReadbackBuffer(sizeof(uint32_t) * step.readback_image.srcRect.extent.width * step.readback_image.srcRect.extent.height);
VkBufferImageCopy region{};
region.imageOffset = { step.readback_image.srcRect.offset.x, step.readback_image.srcRect.offset.y, 0 };
region.imageExtent = { step.readback_image.srcRect.extent.width, step.readback_image.srcRect.extent.height, 1 };
+6 -3
View File
@@ -74,7 +74,7 @@ struct VkRenderData {
VkShaderStageFlags stages;
uint8_t offset;
uint8_t size;
uint8_t data[32]; // Should be enough for now.
uint8_t data[40]; // Should be enough for now.
} push;
};
};
@@ -184,6 +184,8 @@ private:
void LogReadback(const VKRStep &pass);
void LogReadbackImage(const VKRStep &pass);
void ResizeReadbackBuffer(VkDeviceSize requiredSize);
static void SetupTransitionToTransferSrc(VKRImage &img, VkImageMemoryBarrier &barrier, VkPipelineStageFlags &stage, VkImageAspectFlags aspect);
static void SetupTransitionToTransferDst(VKRImage &img, VkImageMemoryBarrier &barrier, VkPipelineStageFlags &stage, VkImageAspectFlags aspect);
@@ -199,6 +201,7 @@ private:
// Readback buffer. Currently we only support synchronous readback, so we only really need one.
// We size it generously.
VkDeviceMemory readbackMemory_;
VkBuffer readbackBuffer_;
VkDeviceMemory readbackMemory_ = VK_NULL_HANDLE;
VkBuffer readbackBuffer_ = VK_NULL_HANDLE;
VkDeviceSize readbackBufferSize_ = 0;
};
+1 -1
View File
@@ -139,7 +139,7 @@ public:
void PushConstants(VkPipelineLayout pipelineLayout, VkShaderStageFlags stages, int offset, int size, void *constants) {
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
assert(size + offset < 32);
assert(size + offset < 40);
VkRenderData data{ VKRRenderCommand::PUSH_CONSTANTS };
data.push.pipelineLayout = pipelineLayout;
data.push.stages = stages;
+4 -3
View File
@@ -312,8 +312,9 @@ struct DescriptorSetKey {
class VKTexture : public Texture {
public:
VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, const TextureDesc &desc)
: vulkan_(vulkan), format_(desc.format), mipLevels_(desc.mipLevels) {
Create(cmd, desc);
: vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) {
bool result = Create(cmd, desc);
assert(result);
}
~VKTexture() {
@@ -336,7 +337,7 @@ private:
}
VulkanContext *vulkan_;
VulkanTexture *vkTex_;
VulkanTexture *vkTex_ = nullptr;
int mipLevels_;