From 0c70735bc489ef9ec60a8fc86d8f66db20200d8a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 21 May 2017 23:13:53 +0200 Subject: [PATCH] Buffered rendering is starting to work, though still kinda broken. --- Common/Vulkan/VulkanContext.cpp | 3 +++ Common/Vulkan/VulkanImage.cpp | 8 ++++++ Common/Vulkan/VulkanImage.h | 3 +++ GPU/Common/FramebufferCommon.cpp | 6 +++++ GPU/Vulkan/DrawEngineVulkan.cpp | 15 ++++++----- GPU/Vulkan/DrawEngineVulkan.h | 2 -- GPU/Vulkan/FramebufferVulkan.cpp | 25 ++++++++++-------- GPU/Vulkan/FramebufferVulkan.h | 4 +-- GPU/Vulkan/VulkanUtil.cpp | 1 + Windows/GPU/WindowsVulkanContext.cpp | 6 ++++- ext/native/thin3d/thin3d.h | 10 +++++++ ext/native/thin3d/thin3d_vulkan.cpp | 39 ++++++++++++++++++---------- 12 files changed, 86 insertions(+), 36 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index c621c24cc0..5004737c68 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -1307,6 +1307,9 @@ void TransitionImageLayout(VkCommandBuffer cmd, VkImage image, VkImageAspectFlag if (old_image_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { image_memory_barrier.srcAccessMask |= VK_ACCESS_MEMORY_READ_BIT; } + if (old_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + image_memory_barrier.srcAccessMask |= VK_ACCESS_SHADER_READ_BIT; + } if (old_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { image_memory_barrier.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index fe5f5e8f08..7fca19628d 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -362,6 +362,14 @@ void VulkanTexture::EndCreate() { VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } +void VulkanTexture::TransitionForUpload() { + VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer(); + TransitionImageLayout(cmd, image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); +} + void VulkanTexture::Destroy() { if (view != VK_NULL_HANDLE) { vulkan_->Delete().QueueDeleteImageView(view); diff --git a/Common/Vulkan/VulkanImage.h b/Common/Vulkan/VulkanImage.h index c7d6b61f68..3b67119946 100644 --- a/Common/Vulkan/VulkanImage.h +++ b/Common/Vulkan/VulkanImage.h @@ -34,6 +34,9 @@ public: bool CreateDirect(int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr); void UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels void EndCreate(); + + void TransitionForUpload(); + int GetNumMips() const { return numMips_; } void Destroy(); diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 9cb831339b..c2007df6bb 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -704,6 +704,7 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int if (useBufferedRendering_ && vfb && vfb->fbo) { draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP }); SetViewport2D(0, 0, vfb->renderWidth, vfb->renderHeight); + draw_->SetScissorRect(0, 0, vfb->renderWidth, vfb->renderHeight); } else { // We are drawing to the back buffer so need to flip. if (needBackBufferYSwap_) @@ -711,6 +712,7 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int float x, y, w, h; CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL); SetViewport2D(x, y, w, h); + draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); } DisableState(); @@ -894,6 +896,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { } // Just a pointer to plain memory to draw. We should create a framebuffer, then draw to it. SetViewport2D(0, 0, pixelWidth_, pixelHeight_); + draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); DrawFramebufferToOutput(Memory::GetPointer(displayFramebufPtr_), displayFormat_, displayStride_, true); return; } @@ -942,6 +945,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); draw_->BindFramebufferAsTexture(vfb->fbo, 0, Draw::FB_COLOR_BIT, 0); SetViewport2D(0, 0, pixelWidth_, pixelHeight_); + draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); bool linearFilter = g_Config.iBufFilter == SCALE_LINEAR; // We are doing the DrawActiveTexture call directly to the backbuffer here. Hence, we must // flip V. @@ -967,6 +971,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { int fbo_w, fbo_h; draw_->GetFramebufferDimensions(extraFBOs_[0], &fbo_w, &fbo_h); SetViewport2D(0, 0, fbo_w, fbo_h); + draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); shaderManager_->DirtyLastShader(); // dirty lastShader_ PostShaderUniforms uniforms{}; CalculatePostShaderUniforms(vfb->bufferWidth, vfb->bufferHeight, renderWidth_, renderHeight_, &uniforms); @@ -1013,6 +1018,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { }*/ } else { draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); + draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); // We are doing the DrawActiveTexture call directly to the backbuffer here. Hence, we must // flip V. if (needBackBufferYSwap_) diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index ff134f9f1b..3d1bdce91d 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -68,7 +68,6 @@ DrawEngineVulkan::DrawEngineVulkan(VulkanContext *vulkan, Draw::DrawContext *dra : vulkan_(vulkan), draw_(draw), prevPrim_(GE_PRIM_INVALID), - lastVTypeID_(-1), numDrawCalls(0), vertexCountInDrawCalls(0), curFrame_(0), @@ -329,10 +328,12 @@ inline void DrawEngineVulkan::SetupVertexDecoderInternal(u32 vertType) { const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24); // If vtype has changed, setup the vertex decoder. - if (vertTypeID != lastVTypeID_) { + if (vertTypeID != lastVType_) { dec_ = GetVertexDecoder(vertTypeID); - lastVTypeID_ = vertTypeID; + lastVType_ = vertTypeID; } + if (!dec_) + Crash(); } void DrawEngineVulkan::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) { @@ -710,7 +711,7 @@ void DrawEngineVulkan::DoFlush() { } prim = indexGen.Prim(); - bool hasColor = (lastVTypeID_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; + bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255); } else { @@ -743,7 +744,7 @@ void DrawEngineVulkan::DoFlush() { dirtyUniforms_ |= shaderManager_->UpdateUniforms(); - shaderManager_->GetShaders(prim, lastVTypeID_, &vshader, &fshader, useHWTransform); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform); VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, true); if (!pipeline) { // Already logged, let's bail out. @@ -778,7 +779,7 @@ void DrawEngineVulkan::DoFlush() { } else { // Decode to "decoded" DecodeVerts(nullptr, nullptr, nullptr); - bool hasColor = (lastVTypeID_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; + bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; if (gstate.isModeThrough()) { gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255); } else { @@ -849,7 +850,7 @@ void DrawEngineVulkan::DoFlush() { dirtyUniforms_ |= shaderManager_->UpdateUniforms(); - shaderManager_->GetShaders(prim, lastVTypeID_, &vshader, &fshader, useHWTransform); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform); VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey, dec_, vshader, fshader, false); if (!pipeline) { // Already logged, let's bail out. diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 6fbea4030d..fe109d3521 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -197,8 +197,6 @@ private: IndexGenerator indexGen; GEPrimitiveType prevPrim_; - u32 lastVTypeID_; - TransformedVertex *transformed = nullptr; TransformedVertex *transformedExpanded = nullptr; diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index e6ff816958..0a1e55cb04 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -129,9 +129,9 @@ void FramebufferManagerVulkan::InitDeviceObjects() { assert(fsBasicTex_ != VK_NULL_HANDLE); assert(vsBasicTex_ != VK_NULL_HANDLE); - // Get a representative render pass and use when creating the pipeline. - pipelineBasicTexBackBuffer_ = vulkan2D_.GetPipeline(pipelineCache2D_, vulkan_->GetSurfaceRenderPass(), vsBasicTex_, fsBasicTex_); - pipelineBasicTexFrameBuffer_ = vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS), vsBasicTex_, fsBasicTex_); + // Prime the 2D pipeline cache. + vulkan2D_.GetPipeline(pipelineCache2D_, vulkan_->GetSurfaceRenderPass(), vsBasicTex_, fsBasicTex_); + vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS), vsBasicTex_, fsBasicTex_); VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; @@ -240,6 +240,8 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor drawPixelsTex_->CreateDirect(width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); // Initialize backbuffer texture for DrawPixels drawPixelsTexFormat_ = srcPixelFormat; + } else { + drawPixelsTex_->TransitionForUpload(); } // TODO: We can just change the texture format and flip some bits around instead of this. @@ -314,11 +316,6 @@ void FramebufferManagerVulkan::SetViewport2D(int x, int y, int w, int h) { } void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, bool linearFilter) { - // TODO -} - -// x, y, w, h are relative coordinates against destW/destH, which is not very intuitive. -void FramebufferManagerVulkan::DrawTexture(VulkanTexture *texture, float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, VkPipeline pipeline, int uvRotation) { float texCoords[8] = { u0,v0, u1,v0, @@ -354,13 +351,18 @@ void FramebufferManagerVulkan::DrawTexture(VulkanTexture *texture, float x, floa vtx[i].y = vtx[i].y * invDestH - 1.0f; } + draw_->FlushState(); + + // TODO: Should probably use draw_ directly and not go low level + VulkanPushBuffer *push = frameData_[curFrame_].push_; VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::RENDERPASS_COMMANDBUFFER); // TODO: Choose linear or nearest appropriately, see GL impl. - vulkan2D_.BindDescriptorSet(cmd, texture->GetImageView(), linearSampler_); - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + VkImageView view = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW); + vulkan2D_.BindDescriptorSet(cmd, view, linearFilter ? linearSampler_ : nearestSampler_); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, cur2DPipeline_); VkBuffer vbuffer; VkDeviceSize offset = push->Push(vtx, sizeof(vtx), &vbuffer); vkCmdBindVertexBuffers(cmd, 0, 1, &vbuffer, &offset); @@ -368,7 +370,8 @@ void FramebufferManagerVulkan::DrawTexture(VulkanTexture *texture, float x, floa } void FramebufferManagerVulkan::Bind2DShader() { - + VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS); + cur2DPipeline_ = vulkan2D_.GetPipeline(pipelineCache2D_, rp, vsBasicTex_, fsBasicTex_); } void FramebufferManagerVulkan::BindPostShader(const PostShaderUniforms &uniforms) { diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h index d7ea385d49..489837a10f 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferVulkan.h @@ -69,9 +69,7 @@ public: drawEngine_ = td; } - // If texture != 0, will bind it. // x,y,w,h are relative to destW, destH which fill out the target completely. - void DrawTexture(VulkanTexture *texture, float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, VkPipeline pipeline, int uvRotation); void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, bool linearFilter) override; void DestroyAllFBOs(); @@ -188,6 +186,8 @@ private: VkPipeline pipelineBasicTexBackBuffer_; VkPipeline pipelineBasicTexFrameBuffer_; + VkPipeline cur2DPipeline_; + // Postprocessing VkPipeline pipelinePostShader_; diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index 6d1be59a30..676be492ab 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -217,6 +217,7 @@ VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShade PipelineKey key; key.vs = vs; key.fs = fs; + key.rp = rp; auto iter = pipelines_.find(key); if (iter != pipelines_.end()) { diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 6affd88f17..f64173a9b6 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -132,6 +132,10 @@ static VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugRep return false; if (msgCode == 11) return false; + // Silence "invalid reads of buffer data" - usually just uninitialized color buffers that will immediately get cleared due to our + // lacking clearing optimizations. + if (msgCode == 15 && objType == VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT) + return false; #ifdef _WIN32 std::string msg = message.str(); @@ -144,7 +148,7 @@ static VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugRep MessageBoxA(NULL, message.str().c_str(), "Alert", MB_OK); } } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { - if (options->breakOnWarning) { + if (options->breakOnWarning && IsDebuggerPresent()) { DebugBreak(); } } diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 92ae1f7d9f..a51de9af08 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -677,6 +677,16 @@ public: virtual void HandleEvent(Event ev, int width, int height, void *param1 = nullptr, void *param2 = nullptr) = 0; + // This flushes command buffers and waits for execution at the point of the end of the last + // renderpass that wrote to the requested framebuffer. This is needed before trying to read it back + // on modern APIs like Vulkan. Ifr the framebuffer is currently being rendered to, we'll just end the render pass. + // The next draw call will automatically start up a new one. + // APIs like OpenGL won't need to implement this one. + virtual void WaitRenderCompletion(Framebuffer *fbo) {} + + // Flush state like scissors etc so the caller can do its own custom drawing. + virtual void FlushState() {} + protected: void CreatePresets(); diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 624a6345a3..412fa4df60 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -422,6 +422,11 @@ public: void BeginFrame() override; void EndFrame() override; + void FlushState() override { + ApplyDynamicState(); + } + void WaitRenderCompletion(Framebuffer *fbo) override; + std::string GetInfoString(InfoField info) const override { // TODO: Make these actually query the right information switch (info) { @@ -447,15 +452,14 @@ public: switch (obj) { case NativeObject::COMPATIBLE_RENDERPASS: // Return a representative renderpass. - return (uintptr_t)(curRenderPass_ == vulkan_->GetSurfaceRenderPass() ? curRenderPass_ : renderPasses_[0]); + if (curRenderPass_ == vulkan_->GetSurfaceRenderPass()) + return (uintptr_t)curRenderPass_; + else + return (uintptr_t)renderPasses_[0]; case NativeObject::RENDERPASS_COMMANDBUFFER: return (uintptr_t)cmd_; case NativeObject::BOUND_TEXTURE_IMAGEVIEW: - if (boundTextures_[0]) { - return (uintptr_t)boundTextures_[0]->GetImageView(); - } else { - return 0; - } + return (uintptr_t)boundImageView_[0]; default: return 0; } @@ -508,11 +512,13 @@ private: }; VKTexture *boundTextures_[MAX_BOUND_TEXTURES]; VKSamplerState *boundSamplers_[MAX_BOUND_TEXTURES]; + VkImageView boundImageView_[MAX_BOUND_TEXTURES]; struct FrameData { VulkanPushBuffer *pushBuffer; VkCommandPool cmdPool_; VkCommandBuffer cmdBufs[MAX_FRAME_COMMAND_BUFFERS]; + int startCmdBufs_; int numCmdBufs_; // Per-frame descriptor set cache. As it's per frame and reset every frame, we don't need to @@ -863,17 +869,18 @@ VkCommandBuffer VKContext::AllocCmdBuf() { void VKContext::BeginFrame() { vulkan_->BeginFrame(); - FrameData *frame = &frame_[frameNum_ & 1]; - frame->numCmdBufs_ = 0; - vkResetCommandPool(vulkan_->GetDevice(), frame->cmdPool_, 0); - push_ = frame->pushBuffer; + FrameData &frame = frame_[frameNum_ & 1]; + frame.startCmdBufs_ = 0; + frame.numCmdBufs_ = 0; + vkResetCommandPool(vulkan_->GetDevice(), frame.cmdPool_, 0); + push_ = frame.pushBuffer; // OK, we now know that nothing is reading from this frame's data pushbuffer, push_->Reset(); push_->Begin(vulkan_); - frame->descSets_.clear(); - VkResult result = vkResetDescriptorPool(device_, frame->descriptorPool, 0); + frame.descSets_.clear(); + VkResult result = vkResetDescriptorPool(device_, frame.descriptorPool, 0); assert(result == VK_SUCCESS); scissor_.extent.width = pixel_xres; @@ -882,6 +889,10 @@ void VKContext::BeginFrame() { viewportDirty_ = true; } +void VKContext::WaitRenderCompletion(Framebuffer *fbo) { + // TODO +} + void VKContext::EndFrame() { if (curRenderPass_) { vulkan_->EndSurfaceRenderPass(); @@ -891,7 +902,7 @@ void VKContext::EndFrame() { // Cap off and submit all the command buffers we recorded during the frame. FrameData &frame = frame_[frameNum_ & 1]; - for (int i = 0; i < frame.numCmdBufs_; i++) { + for (int i = frame.startCmdBufs_; i < frame.numCmdBufs_; i++) { vkEndCommandBuffer(frame.cmdBufs[i]); vulkan_->QueueBeforeSurfaceRender(frame.cmdBufs[i]); } @@ -1204,6 +1215,7 @@ void VKContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, void VKContext::BindTextures(int start, int count, Texture **textures) { for (int i = start; i < start + count; i++) { boundTextures_[i] = static_cast(textures[i]); + boundImageView_[i] = boundTextures_[i]->GetImageView(); } } @@ -1719,6 +1731,7 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne // we're between passes so it's OK. vkCmdPipelineBarrier(transitionCmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &barrier); fb->color.layout = barrier.newLayout; + boundImageView_[0] = fb->color.view; } void VKContext::BindFramebufferForRead(Framebuffer *fbo) { /* noop */ }