Permalink
Browse files

Use RenderManager for thin3d stuff

  • Loading branch information...
hrydgard committed Aug 18, 2017
1 parent 84ed793 commit 417b96a1b07727887050563f9bf4d7348580248d
Showing with 123 additions and 68 deletions.
  1. +53 −4 Common/Vulkan/VulkanRenderManager.cpp
  2. +45 −8 Common/Vulkan/VulkanRenderManager.h
  3. +25 −56 ext/native/thin3d/thin3d_vulkan.cpp
@@ -1,5 +1,18 @@
#include "base/logging.h"
#include "VulkanRenderManager.h"
void VulkanRenderManager::BeginFrameWrites() {
vulkan_->BeginFrame();
renderPasses_.push_back(new VKRRenderPass);
curRp_ = renderPasses_.back();
}
void VulkanRenderManager::EndFrame() {
vulkan_->EndFrame();
}
void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask) {
// If this is the first drawing command, merge it into the pass.
if (curRp_->numDraws == 0) {
@@ -32,16 +45,18 @@ void VulkanRenderManager::Flush(VkCommandBuffer cmdbuf) {
break;
case VKR_DRAW_INDEXED:
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, c.drawIndexed.pipeline);
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, c.drawIndexed.pipelineLayout, 0, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets);
vkCmdBindIndexBuffer(cmdbuf, c.drawIndexed.ibuffer, c.drawIndexed.ioffset, VK_INDEX_TYPE_UINT16);
vkCmdBindVertexBuffers(cmdbuf, 0, 1, &c.drawIndexed.vbuffer, &c.drawIndexed.voffset);
vkCmdDrawIndexed(cmdbuf, c.drawIndexed.count, c.drawIndexed.instances, 0, 0, 0);
break;
case VKR_DRAW:
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, c.drawIndexed.pipelineLayout, 0, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets);
vkCmdBindVertexBuffers(cmdbuf, 0, 1, &c.drawIndexed.vbuffer, &c.drawIndexed.voffset);
vkCmdDraw(cmdbuf, c.drawIndexed.count, c.drawIndexed.instances, 0, 0);
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, c.draw.pipeline);
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, c.draw.pipelineLayout, 0, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets);
vkCmdBindVertexBuffers(cmdbuf, 0, 1, &c.draw.vbuffer, &c.draw.voffset);
vkCmdDraw(cmdbuf, c.draw.count, 1, 0, 0);
break;
case VKR_STENCIL:
@@ -55,11 +70,45 @@ void VulkanRenderManager::Flush(VkCommandBuffer cmdbuf) {
break;
case VKR_CLEAR:
// vkCmdClearAttachments
{
int numAttachments = 0;
VkClearRect rc{};
rc.baseArrayLayer = 0;
rc.layerCount = 1;
rc.rect.extent.width = curWidth_;
rc.rect.extent.height = curHeight_;
VkClearAttachment attachments[2];
if (c.clear.clearMask & VK_IMAGE_ASPECT_COLOR_BIT) {
VkClearAttachment &attachment = attachments[numAttachments++];
attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
attachment.colorAttachment = 0;
Uint8x4ToFloat4(attachment.clearValue.color.float32, c.clear.clearColor);
}
if (c.clear.clearMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
VkClearAttachment &attachment = attachments[numAttachments++];
attachment.aspectMask = 0;
if (c.clear.clearMask & VK_IMAGE_ASPECT_DEPTH_BIT) {
attachment.clearValue.depthStencil.depth = c.clear.clearZ;
attachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
}
if (c.clear.clearMask & VK_IMAGE_ASPECT_STENCIL_BIT) {
attachment.clearValue.depthStencil.stencil = c.clear.clearStencil;
attachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
}
if (numAttachments) {
vkCmdClearAttachments(cmdbuf, numAttachments, attachments, 1, &rc);
}
break;
}
default:
ELOG("Unimpl queue command");
;
}
}
delete renderPasses_[i];
}
renderPasses_.clear();
}
void VulkanRenderManager::Sync(VkCommandBuffer cmd) {
@@ -1,13 +1,17 @@
#pragma once
#include <cstdint>
#include <thread>
#include "Common/Vulkan/VulkanContext.h"
#include "math/dataconv.h"
#include "thin3d/thin3d.h"
// Takes the role that a GL driver does of sequencing and optimizing render passes.
// Only draws and binds are handled here, resource creation and allocations are handled as normal.
// Only draws and binds are handled here, resource creation and allocations are handled as normal -
// that's the nice thing with Vulkan.
// The cool thing is that you can Flush on a different thread than you record the commands on!
enum VkRenderCmd : uint8_t {
VKR_STENCIL,
@@ -29,7 +33,7 @@ struct VkRenderData {
int numUboOffsets;
uint32_t uboOffsets[3];
VkBuffer vbuffer;
int offset;
VkDeviceSize voffset;
int count;
} draw;
struct {
@@ -44,6 +48,7 @@ struct VkRenderData {
VkDeviceSize ioffset;
int16_t count;
int16_t instances;
VkIndexType indexType;
} drawIndexed;
struct {
uint32_t clearColor;
@@ -88,44 +93,76 @@ struct VKRRenderPass {
class VulkanRenderManager {
public:
void SetViewport(VkViewport vp) {
VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan) {}
// Makes sure that the GPU has caught up enough that we can start writing buffers of this frame again.
void BeginFrameWrites();
void EndFrame();
void SetViewport(const VkViewport &vp) {
VkRenderData data{ VKR_VIEWPORT };
data.viewport.vp = vp;
curRp_->commands.push_back(data);
}
void SetScissor(VkRect2D rc) {
void SetScissor(const VkRect2D &rc) {
VkRenderData data{ VKR_SCISSOR };
data.scissor.scissor = rc;
curRp_->commands.push_back(data);
}
void SetBlendFactor(float color[4]) {
VkRenderData data{ VKR_BLEND };
CopyFloat4(data.blendColor.color, color);
curRp_->commands.push_back(data);
}
void Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask);
void Draw(VkPipeline pipeline, VkBuffer vbuffer, int offset, int count) {
void Draw(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, int count) {
VkRenderData data{ VKR_DRAW };
data.draw.count = count;
data.draw.pipeline = pipeline;
data.draw.pipelineLayout = layout;
data.draw.ds = descSet;
data.draw.vbuffer = vbuffer;
data.draw.offset = offset;
data.draw.voffset = voffset;
data.draw.numUboOffsets = numUboOffsets;
for (int i = 0; i < numUboOffsets; i++)
data.draw.uboOffsets[i] = uboOffsets[i];
curRp_->commands.push_back(data);
curRp_->numDraws++;
}
void DrawIndexed(VkPipeline pipeline, VkPipelineLayout layout, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count) {
void DrawIndexed(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count, VkIndexType indexType) {
VkRenderData data{ VKR_DRAW };
data.drawIndexed.count = count;
data.drawIndexed.pipeline = pipeline;
data.drawIndexed.pipelineLayout = layout;
data.drawIndexed.ds = descSet;
data.drawIndexed.vbuffer = vbuffer;
data.drawIndexed.voffset = voffset;
data.drawIndexed.ibuffer = ibuffer;
data.drawIndexed.ioffset = ioffset;
data.drawIndexed.numUboOffsets = numUboOffsets;
for (int i = 0; i < numUboOffsets; i++)
data.drawIndexed.uboOffsets[i] = uboOffsets[i];
data.drawIndexed.indexType = indexType;
curRp_->commands.push_back(data);
curRp_->numDraws++;
}
// Can run on a different thread! Just make sure to use BeginFrameWrites.
void Flush(VkCommandBuffer cmd);
// Bad for performance but sometimes necessary for synchonous CPU readbacks (screenshots and whatnot).
// Bad for performance but sometimes necessary for synchronous CPU readbacks (screenshots and whatnot).
void Sync(VkCommandBuffer cmd);
std::vector<VKRRenderPass *> renderPasses_;
VKRRenderPass *curRp_;
private:
VulkanContext *vulkan_;
int curWidth_;
int curHeight_;
};
@@ -135,6 +135,7 @@ static const VkStencilOp stencilOpToVK[8] = {
VK_STENCIL_OP_DECREMENT_AND_WRAP,
};
// TODO: Replace with the one from dataconv
static inline void Uint8x4ToFloat4(uint32_t u, float f[4]) {
f[0] = ((u >> 0) & 0xFF) * (1.0f / 255.0f);
f[1] = ((u >> 8) & 0xFF) * (1.0f / 255.0f);
@@ -475,7 +476,7 @@ class VKContext : public DrawContext {
return (uintptr_t)boundImageView_[0];
case NativeObject::RENDER_MANAGER:
return renderManager_;
return (uintptr_t)&renderManager_;
default:
return 0;
}
@@ -701,7 +702,7 @@ bool VKTexture::Create(const TextureDesc &desc) {
}
VKContext::VKContext(VulkanContext *vulkan)
: viewportDirty_(false), scissorDirty_(false), vulkan_(vulkan), frameNum_(0), caps_{} {
: viewportDirty_(false), scissorDirty_(false), vulkan_(vulkan), frameNum_(0), caps_{}, renderManager_(vulkan) {
caps_.anisoSupported = vulkan->GetFeaturesAvailable().samplerAnisotropy != 0;
caps_.geometryShaderSupported = vulkan->GetFeaturesAvailable().geometryShader != 0;
caps_.tesselationShaderSupported = vulkan->GetFeaturesAvailable().tessellationShader != 0;
@@ -892,7 +893,7 @@ VkCommandBuffer VKContext::AllocCmdBuf() {
}
void VKContext::BeginFrame() {
vulkan_->BeginFrame();
renderManager_.BeginFrameWrites();
FrameData &frame = frame_[frameNum_];
frame.startCmdBufs_ = 0;
@@ -920,6 +921,7 @@ void VKContext::WaitRenderCompletion(Framebuffer *fbo) {
void VKContext::EndFrame() {
EndCurrentRenderpass();
renderManager_.Flush(cmd_);
if (cmd_)
Crash();
@@ -934,7 +936,8 @@ void VKContext::EndFrame() {
// Stop collecting data in the frame's data pushbuffer.
push_->End();
vulkan_->EndFrame();
renderManager_.EndFrame();
frameNum_++;
if (frameNum_ >= vulkan_->GetInflightFrames())
@@ -1109,16 +1112,16 @@ void VKContext::SetViewports(int count, Viewport *viewports) {
}
void VKContext::SetBlendFactor(float color[4]) {
vkCmdSetBlendConstants(cmd_, color);
renderManager_.SetBlendFactor(color);
}
void VKContext::ApplyDynamicState() {
if (scissorDirty_) {
vkCmdSetScissor(cmd_, 0, 1, &scissor_);
renderManager_.SetScissor(scissor_);
scissorDirty_ = false;
}
if (viewportDirty_) {
vkCmdSetViewport(cmd_, 0, 1, &viewport_);
renderManager_.SetViewport(viewport_);
viewportDirty_ = false;
}
}
@@ -1303,13 +1306,9 @@ void VKContext::Draw(int vertexCount, int offset) {
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
size_t vbBindOffset = push_->Push(vbuf->GetData(), vbuf->GetSize(), &vulkanVbuf);
vkCmdBindPipeline(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, curPipeline_->vkpipeline);
VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
vkCmdBindDescriptorSets(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descSet, 1, &ubo_offset);
VkBuffer buffers[1] = { vulkanVbuf };
VkDeviceSize offsets[1] = { vbBindOffset };
vkCmdBindVertexBuffers(cmd_, 0, 1, buffers, offsets);
vkCmdDraw(cmd_, vertexCount, 1, offset, 0);
renderManager_.Draw(curPipeline_->vkpipeline, pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vertexCount);
}
void VKContext::DrawIndexed(int vertexCount, int offset) {
@@ -1323,17 +1322,9 @@ void VKContext::DrawIndexed(int vertexCount, int offset) {
size_t vbBindOffset = push_->Push(vbuf->GetData(), vbuf->GetSize(), &vulkanVbuf);
size_t ibBindOffset = push_->Push(ibuf->GetData(), ibuf->GetSize(), &vulkanIbuf);
vkCmdBindPipeline(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, curPipeline_->vkpipeline);
VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
vkCmdBindDescriptorSets(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descSet, 1, &ubo_offset);
VkBuffer buffers[1] = { vulkanVbuf };
VkDeviceSize offsets[1] = { vbBindOffset };
vkCmdBindVertexBuffers(cmd_, 0, 1, buffers, offsets);
vkCmdBindIndexBuffer(cmd_, vulkanIbuf, ibBindOffset, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmd_, vertexCount, 1, 0, offset, 0);
renderManager_.DrawIndexed(curPipeline_->vkpipeline, pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf, (int)ibBindOffset, vertexCount, VK_INDEX_TYPE_UINT32);
}
void VKContext::DrawUP(const void *vdata, int vertexCount) {
@@ -1343,52 +1334,30 @@ void VKContext::DrawUP(const void *vdata, int vertexCount) {
size_t vbBindOffset = push_->Push(vdata, vertexCount * curPipeline_->stride[0], &vulkanVbuf);
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
vkCmdBindPipeline(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, curPipeline_->vkpipeline);
VkBuffer buffers[1] = { vulkanVbuf };
VkDeviceSize offsets[1] = { vbBindOffset };
vkCmdBindVertexBuffers(cmd_, 0, 1, buffers, offsets);
VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
vkCmdBindDescriptorSets(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descSet, 1, &ubo_offset);
vkCmdDraw(cmd_, vertexCount, 1, 0, 0);
renderManager_.Draw(curPipeline_->vkpipeline, pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, vbBindOffset, vertexCount);
}
// TODO: We should avoid this function as much as possible, instead use renderpass on-load clearing.
void VKContext::Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) {
void VKContext::Clear(int clearMask, uint32_t colorval, float depthVal, int stencilVal) {
if (!curRenderPass_) {
ELOG("Clear: Need an active render pass");
return;
}
int numAttachments = 0;
VkClearRect rc{};
rc.baseArrayLayer = 0;
rc.layerCount = 1;
rc.rect.extent.width = curWidth_;
rc.rect.extent.height = curHeight_;
VkClearAttachment attachments[2];
if (mask & FBChannel::FB_COLOR_BIT) {
VkClearAttachment &attachment = attachments[numAttachments++];
attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
attachment.colorAttachment = 0;
Uint8x4ToFloat4(colorval, attachment.clearValue.color.float32);
}
if (mask & (FBChannel::FB_DEPTH_BIT | FBChannel::FB_STENCIL_BIT)) {
VkClearAttachment &attachment = attachments[numAttachments++];
attachment.aspectMask = 0;
if (mask & FBChannel::FB_DEPTH_BIT) {
attachment.clearValue.depthStencil.depth = depthVal;
attachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
}
if (mask & FBChannel::FB_STENCIL_BIT) {
attachment.clearValue.depthStencil.stencil = stencilVal;
attachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
}
if (numAttachments) {
vkCmdClearAttachments(cmd_, numAttachments, attachments, 1, &rc);
}
int mask = 0;
if (clearMask & FBChannel::FB_COLOR_BIT)
mask |= VK_IMAGE_ASPECT_COLOR_BIT;
if (clearMask & FBChannel::FB_DEPTH_BIT)
mask |= VK_IMAGE_ASPECT_DEPTH_BIT;
if (clearMask & FBChannel::FB_STENCIL_BIT)
mask |= VK_IMAGE_ASPECT_STENCIL_BIT;
renderManager_.Clear(colorval, depthVal, stencilVal, mask);
}
DrawContext *T3DCreateVulkanContext(VulkanContext *vulkan) {

0 comments on commit 417b96a

Please sign in to comment.