mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-20 06:00:58 +00:00
Merge pull request #15589 from hrydgard/glsl-compilation-parallelization
Vulkan: Parallelize GLSL compilation
This commit is contained in:
commit
b92ea74fb3
@ -1182,18 +1182,11 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
|
||||
case VKRRenderCommand::BIND_GRAPHICS_PIPELINE:
|
||||
{
|
||||
VKRGraphicsPipeline *pipeline = c.graphics_pipeline.pipeline;
|
||||
if (pipeline->Pending()) {
|
||||
// Stall processing, waiting for the compile queue to catch up.
|
||||
std::unique_lock<std::mutex> lock(compileDoneMutex_);
|
||||
while (!pipeline->pipeline) {
|
||||
compileDone_.wait(lock);
|
||||
}
|
||||
}
|
||||
if (pipeline->pipeline != lastGraphicsPipeline && pipeline->pipeline != VK_NULL_HANDLE) {
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline);
|
||||
VkPipeline pipeline = c.graphics_pipeline.pipeline->BlockUntilReady();
|
||||
if (pipeline != lastGraphicsPipeline && pipeline != VK_NULL_HANDLE) {
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
pipelineLayout = c.pipeline.pipelineLayout;
|
||||
lastGraphicsPipeline = pipeline->pipeline;
|
||||
lastGraphicsPipeline = pipeline;
|
||||
// Reset dynamic state so it gets refreshed with the new pipeline.
|
||||
lastStencilWriteMask = -1;
|
||||
lastStencilCompareMask = -1;
|
||||
@ -1204,18 +1197,11 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
|
||||
case VKRRenderCommand::BIND_COMPUTE_PIPELINE:
|
||||
{
|
||||
VKRComputePipeline *pipeline = c.compute_pipeline.pipeline;
|
||||
if (pipeline->Pending()) {
|
||||
// Stall processing, waiting for the compile queue to catch up.
|
||||
std::unique_lock<std::mutex> lock(compileDoneMutex_);
|
||||
while (!pipeline->pipeline) {
|
||||
compileDone_.wait(lock);
|
||||
}
|
||||
}
|
||||
if (pipeline->pipeline != lastComputePipeline && pipeline->pipeline != VK_NULL_HANDLE) {
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline);
|
||||
VkPipeline pipeline = c.graphics_pipeline.pipeline->BlockUntilReady();
|
||||
if (pipeline != lastComputePipeline && pipeline != VK_NULL_HANDLE) {
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
|
||||
pipelineLayout = c.pipeline.pipelineLayout;
|
||||
lastComputePipeline = pipeline->pipeline;
|
||||
lastComputePipeline = pipeline;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1335,7 +1321,6 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
}
|
||||
default:
|
||||
ERROR_LOG(G3D, "Unimpl queue command");
|
||||
;
|
||||
}
|
||||
}
|
||||
vkCmdEndRenderPass(cmd);
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
|
||||
#include "Common/Thread/Promise.h"
|
||||
#include "Common/Data/Collections/Hashmaps.h"
|
||||
#include "Common/GPU/Vulkan/VulkanContext.h"
|
||||
#include "Common/GPU/Vulkan/VulkanBarrier.h"
|
||||
@ -55,11 +55,11 @@ struct VkRenderData {
|
||||
VkPipelineLayout pipelineLayout;
|
||||
} pipeline;
|
||||
struct {
|
||||
VKRGraphicsPipeline *pipeline;
|
||||
Promise<VkPipeline> *pipeline;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
} graphics_pipeline;
|
||||
struct {
|
||||
VKRComputePipeline *pipeline;
|
||||
Promise<VkPipeline> *pipeline;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
} compute_pipeline;
|
||||
struct {
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/TimeUtil.h"
|
||||
|
||||
#include "Common/GPU/Vulkan/VulkanAlloc.h"
|
||||
#include "Common/GPU/Vulkan/VulkanContext.h"
|
||||
@ -29,23 +30,54 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan) {
|
||||
// Already failed to create this one.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fill in the last part of the desc since now it's time to block.
|
||||
VkShaderModule vs = desc->vertexShader->BlockUntilReady();
|
||||
VkShaderModule fs = desc->fragmentShader->BlockUntilReady();
|
||||
|
||||
if (!vs || !fs) {
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline - missing shader modules");
|
||||
// We're kinda screwed here?
|
||||
return false;
|
||||
}
|
||||
|
||||
VkPipelineShaderStageCreateInfo ss[2]{};
|
||||
ss[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
ss[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
ss[0].pSpecializationInfo = nullptr;
|
||||
ss[0].module = vs;
|
||||
ss[0].pName = "main";
|
||||
ss[0].flags = 0;
|
||||
ss[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
ss[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
ss[1].pSpecializationInfo = nullptr;
|
||||
ss[1].module = fs;
|
||||
ss[1].pName = "main";
|
||||
ss[1].flags = 0;
|
||||
|
||||
desc->pipe.pStages = ss;
|
||||
desc->pipe.stageCount = 2;
|
||||
|
||||
double start = time_now_d();
|
||||
VkPipeline vkpipeline;
|
||||
VkResult result = vkCreateGraphicsPipelines(vulkan->GetDevice(), desc->pipelineCache, 1, &desc->pipe, nullptr, &vkpipeline);
|
||||
|
||||
INFO_LOG(G3D, "Pipeline creation time: %0.2f ms", (time_now_d() - start) * 1000.0);
|
||||
|
||||
bool success = true;
|
||||
if (result == VK_INCOMPLETE) {
|
||||
// Bad (disallowed by spec) return value seen on Adreno in Burnout :( Try to ignore?
|
||||
// Would really like to log more here, we could probably attach more info to desc.
|
||||
//
|
||||
// At least create a null placeholder to avoid creating over and over if something is broken.
|
||||
pipeline = VK_NULL_HANDLE;
|
||||
pipeline->Post(VK_NULL_HANDLE);
|
||||
success = false;
|
||||
} else if (result != VK_SUCCESS) {
|
||||
pipeline = VK_NULL_HANDLE;
|
||||
pipeline->Post(VK_NULL_HANDLE);
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result));
|
||||
success = false;
|
||||
} else {
|
||||
pipeline = vkpipeline;
|
||||
pipeline->Post(vkpipeline);
|
||||
}
|
||||
|
||||
delete desc;
|
||||
@ -63,11 +95,11 @@ bool VKRComputePipeline::Create(VulkanContext *vulkan) {
|
||||
|
||||
bool success = true;
|
||||
if (result != VK_SUCCESS) {
|
||||
pipeline = VK_NULL_HANDLE;
|
||||
pipeline->Post(VK_NULL_HANDLE);
|
||||
ERROR_LOG(G3D, "Failed creating compute pipeline! result='%s'", VulkanResultToString(result));
|
||||
success = false;
|
||||
} else {
|
||||
pipeline = vkpipeline;
|
||||
pipeline->Post(vkpipeline);
|
||||
}
|
||||
|
||||
delete desc;
|
||||
@ -449,6 +481,12 @@ void VulkanRenderManager::CompileThreadFunc() {
|
||||
if (!run_) {
|
||||
break;
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, "Compilation thread has %d pipelines to create", (int)toCompile.size());
|
||||
|
||||
// TODO: Here we can sort the pending pipelines by vertex and fragment shaders,
|
||||
// and split up further.
|
||||
// Those with the same pairs of shaders should be on the same thread.
|
||||
for (auto &entry : toCompile) {
|
||||
switch (entry.type) {
|
||||
case CompileQueueEntry::Type::GRAPHICS:
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <thread>
|
||||
#include <queue>
|
||||
|
||||
#include "Common/Thread/Promise.h"
|
||||
#include "Common/System/Display.h"
|
||||
#include "Common/GPU/Vulkan/VulkanContext.h"
|
||||
#include "Common/Data/Convert/SmallDataConvert.h"
|
||||
@ -121,7 +122,11 @@ struct VKRGraphicsPipelineDesc {
|
||||
VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
|
||||
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
|
||||
VkPipelineShaderStageCreateInfo shaderStageInfo[2]{};
|
||||
|
||||
// Replaced the ShaderStageInfo with promises here so we can wait for compiles to finish.
|
||||
Promise<VkShaderModule> *vertexShader;
|
||||
Promise<VkShaderModule> *fragmentShader;
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
|
||||
VkVertexInputAttributeDescription attrs[8]{};
|
||||
VkVertexInputBindingDescription ibd{};
|
||||
@ -139,10 +144,12 @@ struct VKRComputePipelineDesc {
|
||||
// Wrapped pipeline, which will later allow for background compilation while emulating the rest of the frame.
|
||||
struct VKRGraphicsPipeline {
|
||||
VKRGraphicsPipeline() {
|
||||
pipeline = VK_NULL_HANDLE;
|
||||
pipeline = Promise<VkPipeline>::CreateEmpty();
|
||||
}
|
||||
|
||||
VKRGraphicsPipelineDesc *desc = nullptr; // While non-zero, is pending and pipeline isn't valid.
|
||||
std::atomic<VkPipeline> pipeline;
|
||||
|
||||
Promise<VkPipeline> *pipeline;
|
||||
|
||||
bool Create(VulkanContext *vulkan);
|
||||
bool Pending() const {
|
||||
@ -155,7 +162,7 @@ struct VKRComputePipeline {
|
||||
pipeline = VK_NULL_HANDLE;
|
||||
}
|
||||
VKRComputePipelineDesc *desc = nullptr;
|
||||
std::atomic<VkPipeline> pipeline;
|
||||
Promise<VkPipeline> *pipeline;
|
||||
|
||||
bool Create(VulkanContext *vulkan);
|
||||
bool Pending() const {
|
||||
@ -256,7 +263,7 @@ public:
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
_dbg_assert_(pipeline != nullptr);
|
||||
VkRenderData data{ VKRRenderCommand::BIND_GRAPHICS_PIPELINE };
|
||||
data.graphics_pipeline.pipeline = pipeline;
|
||||
data.graphics_pipeline.pipeline = pipeline->pipeline;
|
||||
data.graphics_pipeline.pipelineLayout = pipelineLayout;
|
||||
curPipelineFlags_ |= flags;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
@ -266,7 +273,7 @@ public:
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
_dbg_assert_(pipeline != nullptr);
|
||||
VkRenderData data{ VKRRenderCommand::BIND_COMPUTE_PIPELINE };
|
||||
data.compute_pipeline.pipeline = pipeline;
|
||||
data.compute_pipeline.pipeline = pipeline->pipeline;
|
||||
data.compute_pipeline.pipelineLayout = pipelineLayout;
|
||||
curPipelineFlags_ |= flags;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
|
@ -19,7 +19,7 @@ struct Mailbox {
|
||||
|
||||
std::mutex mutex_;
|
||||
std::condition_variable condvar_;
|
||||
T data_ = nullptr;
|
||||
T data_{};
|
||||
|
||||
T Wait() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
@ -43,7 +43,7 @@ struct Mailbox {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (!data_) {
|
||||
data_ = data;
|
||||
condvar_.notify_one();
|
||||
condvar_.notify_all();
|
||||
return true;
|
||||
} else {
|
||||
// Already has value.
|
||||
|
@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "Common/Thread/Channel.h"
|
||||
#include "Common/Thread/ThreadManager.h"
|
||||
|
||||
@ -33,6 +35,7 @@ public:
|
||||
// Has ownership over the data. Single use.
|
||||
// TODO: Split Mailbox (rx_ and tx_) up into separate proxy objects.
|
||||
// NOTE: Poll/BlockUntilReady should only be used from one thread.
|
||||
// TODO: Make movable?
|
||||
template<class T>
|
||||
class Promise {
|
||||
public:
|
||||
@ -47,15 +50,36 @@ public:
|
||||
return promise;
|
||||
}
|
||||
|
||||
static Promise<T> *AlreadyDone(T data) {
|
||||
Promise<T> *promise = new Promise<T>();
|
||||
promise->data_ = data;
|
||||
promise->ready_ = true;
|
||||
return promise;
|
||||
}
|
||||
|
||||
static Promise<T> *CreateEmpty() {
|
||||
Mailbox<T> *mailbox = new Mailbox<T>();
|
||||
Promise<T> *promise = new Promise<T>();
|
||||
promise->rx_ = mailbox;
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Allow an empty promise to spawn, too, in case we want to delay it.
|
||||
void SpawnEmpty(ThreadManager *threadman, std::function<T()> fun, TaskType taskType) {
|
||||
PromiseTask<T> *task = new PromiseTask<T>(fun, rx_, taskType);
|
||||
threadman->EnqueueTask(task);
|
||||
}
|
||||
|
||||
~Promise() {
|
||||
std::lock_guard<std::mutex> guard(readyMutex_);
|
||||
// A promise should have been fulfilled before it's destroyed.
|
||||
_assert_(ready_);
|
||||
_assert_(!rx_);
|
||||
delete data_;
|
||||
}
|
||||
|
||||
// Returns T if the data is ready, nullptr if it's not.
|
||||
T Poll() {
|
||||
std::lock_guard<std::mutex> guard(readyMutex_);
|
||||
if (ready_) {
|
||||
return data_;
|
||||
} else {
|
||||
@ -71,6 +95,7 @@ public:
|
||||
}
|
||||
|
||||
T BlockUntilReady() {
|
||||
std::lock_guard<std::mutex> guard(readyMutex_);
|
||||
if (ready_) {
|
||||
return data_;
|
||||
} else {
|
||||
@ -82,10 +107,17 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// For outside injection of data, when not using Spawn
|
||||
void Post(T data) {
|
||||
rx_->Send(data);
|
||||
}
|
||||
|
||||
private:
|
||||
Promise() {}
|
||||
|
||||
T data_ = nullptr;
|
||||
// Promise can only be constructed in Spawn (or AlreadyDone).
|
||||
T data_{};
|
||||
bool ready_ = false;
|
||||
Mailbox<T> *rx_;
|
||||
std::mutex readyMutex_;
|
||||
Mailbox<T> *rx_ = nullptr;
|
||||
};
|
||||
|
@ -36,7 +36,7 @@ void PipelineManagerVulkan::Clear() {
|
||||
|
||||
pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) {
|
||||
if (value->pipeline) {
|
||||
VkPipeline pipeline = value->pipeline->pipeline;
|
||||
VkPipeline pipeline = value->pipeline->pipeline->BlockUntilReady();
|
||||
vulkan_->Delete().QueueDeletePipeline(pipeline);
|
||||
vulkan_->Delete().QueueCallback([](void *p) {
|
||||
VKRGraphicsPipeline *pipeline = (VKRGraphicsPipeline *)p;
|
||||
@ -256,28 +256,8 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
|
||||
ms.pSampleMask = nullptr;
|
||||
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkPipelineShaderStageCreateInfo *ss = &desc->shaderStageInfo[0];
|
||||
ss[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
ss[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
ss[0].pSpecializationInfo = nullptr;
|
||||
ss[0].module = vs->GetModule();
|
||||
ss[0].pName = "main";
|
||||
ss[0].flags = 0;
|
||||
ss[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
ss[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
ss[1].pSpecializationInfo = nullptr;
|
||||
ss[1].module = fs->GetModule();
|
||||
ss[1].pName = "main";
|
||||
ss[1].flags = 0;
|
||||
|
||||
if (!ss[0].module || !ss[1].module) {
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline - bad shaders");
|
||||
// Create a placeholder to avoid creating over and over if shader compiler broken.
|
||||
VulkanPipeline *nullPipeline = new VulkanPipeline();
|
||||
nullPipeline->pipeline = VK_NULL_HANDLE;
|
||||
nullPipeline->flags = 0;
|
||||
return nullPipeline;
|
||||
}
|
||||
desc->fragmentShader = fs->GetModule();
|
||||
desc->vertexShader = vs->GetModule();
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo &inputAssembly = desc->inputAssembly;
|
||||
inputAssembly.flags = 0;
|
||||
@ -321,7 +301,6 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
|
||||
VkGraphicsPipelineCreateInfo &pipe = desc->pipe;
|
||||
pipe.flags = 0;
|
||||
pipe.stageCount = 2;
|
||||
pipe.pStages = ss;
|
||||
pipe.basePipelineIndex = 0;
|
||||
|
||||
pipe.pColorBlendState = &desc->cbs;
|
||||
@ -633,8 +612,8 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha
|
||||
pipelines_.Iterate([&](const VulkanPipelineKey &pkey, VulkanPipeline *value) {
|
||||
if (failed)
|
||||
return;
|
||||
VulkanVertexShader *vshader = shaderManager->GetVertexShaderFromModule(pkey.vShader);
|
||||
VulkanFragmentShader *fshader = shaderManager->GetFragmentShaderFromModule(pkey.fShader);
|
||||
VulkanVertexShader *vshader = shaderManager->GetVertexShaderFromModule(pkey.vShader->BlockUntilReady());
|
||||
VulkanFragmentShader *fshader = shaderManager->GetFragmentShaderFromModule(pkey.fShader->BlockUntilReady());
|
||||
if (!vshader || !fshader) {
|
||||
failed = true;
|
||||
return;
|
||||
|
@ -18,7 +18,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "Common/Data/Collections/Hashmaps.h"
|
||||
#include "Common/Thread/Promise.h"
|
||||
|
||||
#include "GPU/Common/VertexDecoderCommon.h"
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
@ -33,8 +35,8 @@ class VulkanRenderManager;
|
||||
struct VulkanPipelineKey {
|
||||
VulkanPipelineRasterStateKey raster; // prim is included here
|
||||
VkRenderPass renderPass;
|
||||
VkShaderModule vShader;
|
||||
VkShaderModule fShader;
|
||||
Promise<VkShaderModule> *vShader;
|
||||
Promise<VkShaderModule> *fShader;
|
||||
uint32_t vtxFmtId;
|
||||
bool useHWTransform;
|
||||
|
||||
|
@ -42,62 +42,62 @@
|
||||
#include "GPU/Vulkan/DrawEngineVulkan.h"
|
||||
#include "GPU/Vulkan/FramebufferManagerVulkan.h"
|
||||
|
||||
VkShaderModule CompileShaderModule(VulkanContext *vulkan, VkShaderStageFlagBits stage, const char *code) {
|
||||
PROFILE_THIS_SCOPE("shadercomp");
|
||||
// Most drivers treat vkCreateShaderModule as pretty much a memcpy. What actually
|
||||
// takes time here, and makes this worthy of parallelization, is GLSLtoSPV.
|
||||
Promise<VkShaderModule> *CompileShaderModuleAsync(VulkanContext *vulkan, VkShaderStageFlagBits stage, const char *code) {
|
||||
return Promise<VkShaderModule>::Spawn(&g_threadManager, [=] {
|
||||
PROFILE_THIS_SCOPE("shadercomp");
|
||||
|
||||
std::string errorMessage;
|
||||
std::vector<uint32_t> spirv;
|
||||
std::string errorMessage;
|
||||
std::vector<uint32_t> spirv;
|
||||
|
||||
bool success = GLSLtoSPV(stage, code, GLSLVariant::VULKAN, spirv, &errorMessage);
|
||||
bool success = GLSLtoSPV(stage, code, GLSLVariant::VULKAN, spirv, &errorMessage);
|
||||
|
||||
VkShaderModule shaderModule = VK_NULL_HANDLE;
|
||||
|
||||
if (!errorMessage.empty()) {
|
||||
if (success) {
|
||||
ERROR_LOG(G3D, "Warnings in shader compilation!");
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Error in shader compilation!");
|
||||
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);
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugStringA(LineNumberString(code).c_str());
|
||||
OutputDebugStringA("Error messages:\n");
|
||||
OutputDebugStringA(errorMessage.c_str());
|
||||
#endif
|
||||
Reporting::ReportMessage("Vulkan error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);
|
||||
}
|
||||
ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str());
|
||||
ERROR_LOG(G3D, "Shader source:\n%s", code);
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugStringA(LineNumberString(code).c_str());
|
||||
OutputDebugStringA("Error messages:\n");
|
||||
OutputDebugStringA(errorMessage.c_str());
|
||||
#endif
|
||||
Reporting::ReportMessage("Vulkan error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);
|
||||
} else {
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugStringA(LineNumberString(code).c_str());
|
||||
#endif
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugStringA("OK\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (success) {
|
||||
vulkan->CreateShaderModule(spirv, &shaderModule);
|
||||
}
|
||||
VkShaderModule shaderModule = VK_NULL_HANDLE;
|
||||
if (success) {
|
||||
success = vulkan->CreateShaderModule(spirv, &shaderModule);
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugStringA("OK");
|
||||
#endif
|
||||
}
|
||||
|
||||
return shaderModule;
|
||||
return shaderModule;
|
||||
}, TaskType::CPU_COMPUTE);
|
||||
}
|
||||
|
||||
|
||||
VulkanFragmentShader::VulkanFragmentShader(VulkanContext *vulkan, FShaderID id, const char *code)
|
||||
: vulkan_(vulkan), id_(id) {
|
||||
source_ = code;
|
||||
module_ = CompileShaderModule(vulkan, VK_SHADER_STAGE_FRAGMENT_BIT, source_.c_str());
|
||||
module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_FRAGMENT_BIT, source_.c_str());
|
||||
if (!module_) {
|
||||
failed_ = true;
|
||||
return;
|
||||
} else {
|
||||
VERBOSE_LOG(G3D, "Compiled fragment shader:\n%s\n", (const char *)code);
|
||||
}
|
||||
}
|
||||
|
||||
VulkanFragmentShader::~VulkanFragmentShader() {
|
||||
if (module_ != VK_NULL_HANDLE) {
|
||||
vulkan_->Delete().QueueDeleteShaderModule(module_);
|
||||
if (module_) {
|
||||
VkShaderModule shaderModule = module_->BlockUntilReady();
|
||||
vulkan_->Delete().QueueDeleteShaderModule(shaderModule);
|
||||
delete module_;
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,18 +115,19 @@ std::string VulkanFragmentShader::GetShaderString(DebugShaderStringType type) co
|
||||
VulkanVertexShader::VulkanVertexShader(VulkanContext *vulkan, VShaderID id, const char *code, bool useHWTransform)
|
||||
: vulkan_(vulkan), useHWTransform_(useHWTransform), id_(id) {
|
||||
source_ = code;
|
||||
module_ = CompileShaderModule(vulkan, VK_SHADER_STAGE_VERTEX_BIT, source_.c_str());
|
||||
module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_VERTEX_BIT, source_.c_str());
|
||||
if (!module_) {
|
||||
failed_ = true;
|
||||
return;
|
||||
} else {
|
||||
VERBOSE_LOG(G3D, "Compiled vertex shader:\n%s\n", (const char *)code);
|
||||
}
|
||||
}
|
||||
|
||||
VulkanVertexShader::~VulkanVertexShader() {
|
||||
if (module_ != VK_NULL_HANDLE) {
|
||||
vulkan_->Delete().QueueDeleteShaderModule(module_);
|
||||
if (module_) {
|
||||
VkShaderModule shaderModule = module_->BlockUntilReady();
|
||||
vulkan_->Delete().QueueDeleteShaderModule(shaderModule);
|
||||
delete module_;
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,7 +335,9 @@ std::string ShaderManagerVulkan::DebugGetShaderString(std::string id, DebugShade
|
||||
VulkanVertexShader *ShaderManagerVulkan::GetVertexShaderFromModule(VkShaderModule module) {
|
||||
VulkanVertexShader *vs = nullptr;
|
||||
vsCache_.Iterate([&](const VShaderID &id, VulkanVertexShader *shader) {
|
||||
if (shader->GetModule() == module)
|
||||
Promise<VkShaderModule> *p = shader->GetModule();
|
||||
VkShaderModule m = p->BlockUntilReady();
|
||||
if (m == module)
|
||||
vs = shader;
|
||||
});
|
||||
return vs;
|
||||
@ -343,7 +346,9 @@ VulkanVertexShader *ShaderManagerVulkan::GetVertexShaderFromModule(VkShaderModul
|
||||
VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderModule module) {
|
||||
VulkanFragmentShader *fs = nullptr;
|
||||
fsCache_.Iterate([&](const FShaderID &id, VulkanFragmentShader *shader) {
|
||||
if (shader->GetModule() == module)
|
||||
Promise<VkShaderModule> *p = shader->GetModule();
|
||||
VkShaderModule m = p->BlockUntilReady();
|
||||
if (m == module)
|
||||
fs = shader;
|
||||
});
|
||||
return fs;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
#include "Common/Thread/Promise.h"
|
||||
#include "Common/Data/Collections/Hashmaps.h"
|
||||
#include "Common/GPU/Vulkan/VulkanMemory.h"
|
||||
#include "GPU/Common/ShaderCommon.h"
|
||||
@ -43,11 +44,11 @@ public:
|
||||
bool Failed() const { return failed_; }
|
||||
|
||||
std::string GetShaderString(DebugShaderStringType type) const;
|
||||
VkShaderModule GetModule() const { return module_; }
|
||||
Promise<VkShaderModule> *GetModule() { return module_; }
|
||||
const FShaderID &GetID() { return id_; }
|
||||
|
||||
protected:
|
||||
VkShaderModule module_ = VK_NULL_HANDLE;
|
||||
Promise<VkShaderModule> *module_ = nullptr;
|
||||
|
||||
VulkanContext *vulkan_;
|
||||
std::string source_;
|
||||
@ -66,11 +67,11 @@ public:
|
||||
bool UseHWTransform() const { return useHWTransform_; }
|
||||
|
||||
std::string GetShaderString(DebugShaderStringType type) const;
|
||||
VkShaderModule GetModule() const { return module_; }
|
||||
Promise<VkShaderModule> *GetModule() { return module_; }
|
||||
const VShaderID &GetID() { return id_; }
|
||||
|
||||
protected:
|
||||
VkShaderModule module_ = VK_NULL_HANDLE;
|
||||
Promise<VkShaderModule> *module_ = nullptr;
|
||||
|
||||
VulkanContext *vulkan_;
|
||||
std::string source_;
|
||||
|
@ -1094,8 +1094,8 @@ AVI Dump started. = AVI dump started
|
||||
AVI Dump stopped. = AVI dump stopped
|
||||
Cache ISO in RAM = Cachea hela ISO:n i RAM
|
||||
Change CPU Clock = Ändra CPU-frekvens (kan orsaka instabilitet)
|
||||
Color Saturation = Color Saturation
|
||||
Color Tint = Color Tint
|
||||
Color Saturation = Färgmättnad
|
||||
Color Tint = Färgförskjutning
|
||||
Error: load undo state is from a different game = Error: load undo state is from a different game
|
||||
Failed to load state for load undo. Error in the file system. = Failed to load state for load undo. Error in the file system.
|
||||
Floating symbols = Floating symbols
|
||||
|
@ -114,10 +114,10 @@ public:
|
||||
JsonAllocator() : head(nullptr) {};
|
||||
JsonAllocator(const JsonAllocator &) = delete;
|
||||
JsonAllocator &operator=(const JsonAllocator &) = delete;
|
||||
JsonAllocator(JsonAllocator &&x) : head(x.head) {
|
||||
JsonAllocator(JsonAllocator &&x) noexcept : head(x.head) {
|
||||
x.head = nullptr;
|
||||
}
|
||||
JsonAllocator &operator=(JsonAllocator &&x) {
|
||||
JsonAllocator &operator=(JsonAllocator &&x) noexcept {
|
||||
head = x.head;
|
||||
x.head = nullptr;
|
||||
return *this;
|
||||
|
Loading…
x
Reference in New Issue
Block a user