From 9cd4db5f180851beae33ee592cd0c3b5a64adfaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 11 Nov 2017 20:36:44 +0100 Subject: [PATCH] Vulkan hw tess: Use pushbuffers instead of temp images to upload data. --- GPU/Common/DrawEngineCommon.h | 1 + GPU/Vulkan/DrawEngineVulkan.cpp | 86 ++++++++++++++++++++++----------- GPU/Vulkan/DrawEngineVulkan.h | 49 +++++++------------ 3 files changed, 78 insertions(+), 58 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 99023d63f1..cdaa579a19 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -155,6 +155,7 @@ protected: int numPatches; class TessellationDataTransfer { protected: + // TODO: These aren't used by all backends. int prevSize; int prevSizeTex; int prevSizeCol; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 54d8001807..28a2a32bbe 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -294,6 +294,9 @@ void DrawEngineVulkan::BeginFrame() { frame->pushVertex->Begin(vulkan_); frame->pushIndex->Begin(vulkan_); + // TODO: How can we make this nicer... + ((TessellationDataTransferVulkan *)tessDataTransfer)->SetPushBuffer(frame->pushUBO); + // TODO : Find a better place to do this. if (!nullTexture_) { ILOG("INIT : Creating null texture"); @@ -1096,53 +1099,82 @@ DrawEngineVulkan::TessellationDataTransferVulkan::~TessellationDataTransferVulka } void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&pos, float *&tex, float *&col, int size, bool hasColor, bool hasTexCoords) { - int rowPitch; ILOG("INIT : Prep tess"); VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER); // Position - if (prevSize < size) { - prevSize = size; + delete data_tex[0]; + data_tex[0] = new VulkanTexture(vulkan_, nullptr); // TODO: Should really use an allocator. + data_tex[0]->CreateDirect(cmd, size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - delete data_tex[0]; - data_tex[0] = new VulkanTexture(vulkan_, nullptr); // TODO: Should really use an allocator. - data_tex[0]->CreateDirect(cmd, size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - } - pos = (float *)data_tex[0]->Lock(0, &rowPitch); + posSize_ = size; + pos = (float *)push_->Push(size * sizeof(float) * 4, &posOffset_, &posBuf_); // Texcoords + delete data_tex[1]; + data_tex[1] = nullptr; if (hasTexCoords) { - if (prevSizeTex < size) { - prevSizeTex = size; + data_tex[1] = new VulkanTexture(vulkan_, nullptr); // TODO: Should really use an allocator. + data_tex[1]->CreateDirect(cmd, size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - delete data_tex[1]; - data_tex[1] = new VulkanTexture(vulkan_, nullptr); // TODO: Should really use an allocator. - data_tex[1]->CreateDirect(cmd, size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - } - tex = (float *)data_tex[1]->Lock(0, &rowPitch); + tex = (float *)push_->Push(size * sizeof(float) * 4, &texOffset_, &texBuf_); + texSize_ = size; + } else { + texSize_ = 0; + tex = nullptr; } // Color - int sizeColor = hasColor ? size : 1; - if (prevSizeCol < sizeColor) { - prevSizeCol = sizeColor; + colSize_ = hasColor ? size : 1; + delete data_tex[2]; + data_tex[2] = new VulkanTexture(vulkan_, nullptr); // TODO: Should really use an allocator. + data_tex[2]->CreateDirect(cmd, colSize_, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - delete data_tex[2]; - data_tex[2] = new VulkanTexture(vulkan_, nullptr); // TODO: Should really use an allocator. - data_tex[2]->CreateDirect(cmd, sizeColor, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - } - col = (float *)data_tex[2]->Lock(0, &rowPitch); + col = (float *)push_->Push(size * sizeof(float) * 4, &colOffset_, &colBuf_); } 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]->Unlock(cmd); + data_tex[0]->UploadMip(cmd, 0, posSize_, 1, posBuf_, posOffset_, posSize_); + data_tex[0]->EndCreate(cmd); // Texcoords - if (hasTexCoords) - data_tex[1]->Unlock(cmd); + if (hasTexCoords) { + data_tex[1]->UploadMip(cmd, 0, texSize_, 1, texBuf_, texOffset_, texSize_); + data_tex[1]->EndCreate(cmd); + } // Color - data_tex[2]->Unlock(cmd); + data_tex[2]->UploadMip(cmd, 0, colSize_, 1, colBuf_, colOffset_, colSize_); + data_tex[2]->EndCreate(cmd); } + +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); +} \ No newline at end of file diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 8a8a972d41..48641131dc 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -261,47 +261,34 @@ private: // Hardware tessellation class TessellationDataTransferVulkan : public TessellationDataTransfer { - private: - VulkanContext *vulkan_; - Draw::DrawContext *draw_; - VulkanTexture *data_tex[3]{}; - VkSampler sampler = VK_NULL_HANDLE; public: TessellationDataTransferVulkan(VulkanContext *vulkan, Draw::DrawContext *draw); ~TessellationDataTransferVulkan(); + + 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; VulkanTexture *GetTexture(int i) const { return data_tex[i]; } VkSampler GetSampler() const { return sampler; } - void 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; + void CreateSampler(); + private: + VulkanContext *vulkan_; + Draw::DrawContext *draw_; + VulkanTexture *data_tex[3]{}; + VkSampler sampler = VK_NULL_HANDLE; + VulkanPushBuffer *push_; // Updated each frame. - 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; - } + 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; - samp.maxLod = 1.0f; - samp.minLod = 0.0f; - samp.mipLodBias = 0.0f; - - VkResult res = vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &sampler); - assert(res == VK_SUCCESS); - } }; };