From 56557a17f16078faaf55387914e6d44a2d704023 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 8 May 2019 11:39:21 +0300 Subject: [PATCH] - fixed output of software renderers with Vulkan backend Vulkan hardware buffer for software canvas may have some padding Software renderers should be aware of buffer's pitch in order to copy pixels properly https://forum.zdoom.org/viewtopic.php?t=64562 --- src/r_renderer.h | 2 +- src/rendering/gl/textures/gl_hwtexture.cpp | 1 + src/rendering/hwrenderer/textures/hw_ihwtexture.h | 10 +++++----- src/rendering/polyrenderer/poly_renderer.cpp | 4 ++-- src/rendering/polyrenderer/poly_renderer.h | 2 +- src/rendering/swrenderer/drawers/r_thread.cpp | 8 ++++---- src/rendering/swrenderer/drawers/r_thread.h | 3 ++- src/rendering/swrenderer/r_swrenderer.cpp | 6 +++--- src/rendering/swrenderer/r_swrenderer.h | 2 +- src/rendering/swrenderer/r_swscene.cpp | 7 ++++--- src/rendering/swrenderer/scene/r_scene.cpp | 4 ++-- src/rendering/swrenderer/scene/r_scene.h | 2 +- src/rendering/vulkan/system/vk_builders.h | 12 ++++++++++-- src/rendering/vulkan/textures/vk_hwtexture.cpp | 5 ++++- 14 files changed, 41 insertions(+), 27 deletions(-) diff --git a/src/r_renderer.h b/src/r_renderer.h index 126d7a2ee..1f3dec145 100644 --- a/src/r_renderer.h +++ b/src/r_renderer.h @@ -24,7 +24,7 @@ struct FRenderer virtual void Precache(uint8_t *texhitlist, TMap &actorhitlist) = 0; // render 3D view - virtual void RenderView(player_t *player, DCanvas *target, void *videobuffer) = 0; + virtual void RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch) = 0; // renders view to a savegame picture virtual void WriteSavePic(player_t *player, FileWriter *file, int width, int height) = 0; diff --git a/src/rendering/gl/textures/gl_hwtexture.cpp b/src/rendering/gl/textures/gl_hwtexture.cpp index e4736f4d6..01d818f5b 100644 --- a/src/rendering/gl/textures/gl_hwtexture.cpp +++ b/src/rendering/gl/textures/gl_hwtexture.cpp @@ -191,6 +191,7 @@ void FHardwareTexture::AllocateBuffer(int w, int h, int texelsize) int rh = GetTexDimension(h); if (texelsize < 1 || texelsize > 4) texelsize = 4; glTextureBytes = texelsize; + bufferpitch = w; if (rw == w || rh == h) { glGenBuffers(1, &glBufferID); diff --git a/src/rendering/hwrenderer/textures/hw_ihwtexture.h b/src/rendering/hwrenderer/textures/hw_ihwtexture.h index f05baf47d..7000edccb 100644 --- a/src/rendering/hwrenderer/textures/hw_ihwtexture.h +++ b/src/rendering/hwrenderer/textures/hw_ihwtexture.h @@ -14,10 +14,6 @@ public: MAX_TEXTURES = 16 }; -public: - - -public: IHardwareTexture() {} virtual ~IHardwareTexture() {} @@ -26,5 +22,9 @@ public: virtual unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) = 0; void Resize(int swidth, int sheight, int width, int height, unsigned char *src_data, unsigned char *dst_data); -}; + int GetBufferPitch() const { return bufferpitch; } + +protected: + int bufferpitch = -1; +}; diff --git a/src/rendering/polyrenderer/poly_renderer.cpp b/src/rendering/polyrenderer/poly_renderer.cpp index 491f1b8ee..9c3642488 100644 --- a/src/rendering/polyrenderer/poly_renderer.cpp +++ b/src/rendering/polyrenderer/poly_renderer.cpp @@ -59,7 +59,7 @@ PolyRenderer::PolyRenderer() { } -void PolyRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer) +void PolyRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch) { using namespace swrenderer; @@ -73,7 +73,7 @@ void PolyRenderer::RenderView(player_t *player, DCanvas *target, void *videobuff Threads.MainThread()->FlushDrawQueue(); auto copyqueue = std::make_shared(Threads.MainThread()->FrameMemory.get()); - copyqueue->Push(videobuffer, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1); + copyqueue->Push(videobuffer, bufferpitch, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1); DrawerThreads::Execute(copyqueue); PolyDrawerWaitCycles.Clock(); diff --git a/src/rendering/polyrenderer/poly_renderer.h b/src/rendering/polyrenderer/poly_renderer.h index 4750d2b04..b40f5d44d 100644 --- a/src/rendering/polyrenderer/poly_renderer.h +++ b/src/rendering/polyrenderer/poly_renderer.h @@ -49,7 +49,7 @@ class PolyRenderer public: PolyRenderer(); - void RenderView(player_t *player, DCanvas *target, void *videobuffer); + void RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch); void RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines); void RenderRemainingPlayerSprites(); diff --git a/src/rendering/swrenderer/drawers/r_thread.cpp b/src/rendering/swrenderer/drawers/r_thread.cpp index e8b6eeada..b04bde383 100644 --- a/src/rendering/swrenderer/drawers/r_thread.cpp +++ b/src/rendering/swrenderer/drawers/r_thread.cpp @@ -271,8 +271,8 @@ void GroupMemoryBarrierCommand::Execute(DrawerThread *thread) ///////////////////////////////////////////////////////////////////////////// -MemcpyCommand::MemcpyCommand(void *dest, const void *src, int width, int height, int srcpitch, int pixelsize) - : dest(dest), src(src), width(width), height(height), srcpitch(srcpitch), pixelsize(pixelsize) +MemcpyCommand::MemcpyCommand(void *dest, int destpitch, const void *src, int width, int height, int srcpitch, int pixelsize) + : dest(dest), src(src), destpitch(destpitch), width(width), height(height), srcpitch(srcpitch), pixelsize(pixelsize) { } @@ -281,9 +281,9 @@ void MemcpyCommand::Execute(DrawerThread *thread) int start = thread->skipped_by_thread(0); int count = thread->count_for_thread(0, height); int sstep = thread->num_cores * srcpitch * pixelsize; - int dstep = thread->num_cores * width * pixelsize; + int dstep = thread->num_cores * destpitch * pixelsize; int size = width * pixelsize; - uint8_t *d = (uint8_t*)dest + start * width * pixelsize; + uint8_t *d = (uint8_t*)dest + start * destpitch * pixelsize; const uint8_t *s = (const uint8_t*)src + start * srcpitch * pixelsize; for (int i = 0; i < count; i++) { diff --git a/src/rendering/swrenderer/drawers/r_thread.h b/src/rendering/swrenderer/drawers/r_thread.h index f12193a49..eb804ac76 100644 --- a/src/rendering/swrenderer/drawers/r_thread.h +++ b/src/rendering/swrenderer/drawers/r_thread.h @@ -125,12 +125,13 @@ private: class MemcpyCommand : public DrawerCommand { public: - MemcpyCommand(void *dest, const void *src, int width, int height, int srcpitch, int pixelsize); + MemcpyCommand(void *dest, int destpitch, const void *src, int width, int height, int srcpitch, int pixelsize); void Execute(DrawerThread *thread); private: void *dest; const void *src; + int destpitch; int width; int height; int srcpitch; diff --git a/src/rendering/swrenderer/r_swrenderer.cpp b/src/rendering/swrenderer/r_swrenderer.cpp index cf153551f..c2536e3d2 100644 --- a/src/rendering/swrenderer/r_swrenderer.cpp +++ b/src/rendering/swrenderer/r_swrenderer.cpp @@ -183,13 +183,13 @@ void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap & FImageSource::EndPrecaching(); } -void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer) +void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch) { if (V_IsPolyRenderer()) { PolyRenderer::Instance()->Viewpoint = r_viewpoint; PolyRenderer::Instance()->Viewwindow = r_viewwindow; - PolyRenderer::Instance()->RenderView(player, target, videobuffer); + PolyRenderer::Instance()->RenderView(player, target, videobuffer, bufferpitch); r_viewpoint = PolyRenderer::Instance()->Viewpoint; r_viewwindow = PolyRenderer::Instance()->Viewwindow; } @@ -197,7 +197,7 @@ void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target, void *vide { mScene.MainThread()->Viewport->viewpoint = r_viewpoint; mScene.MainThread()->Viewport->viewwindow = r_viewwindow; - mScene.RenderView(player, target, videobuffer); + mScene.RenderView(player, target, videobuffer, bufferpitch); r_viewpoint = mScene.MainThread()->Viewport->viewpoint; r_viewwindow = mScene.MainThread()->Viewport->viewwindow; } diff --git a/src/rendering/swrenderer/r_swrenderer.h b/src/rendering/swrenderer/r_swrenderer.h index 84627f2cd..f2cdb116d 100644 --- a/src/rendering/swrenderer/r_swrenderer.h +++ b/src/rendering/swrenderer/r_swrenderer.h @@ -12,7 +12,7 @@ struct FSoftwareRenderer : public FRenderer void Precache(uint8_t *texhitlist, TMap &actorhitlist) override; // render 3D view - void RenderView(player_t *player, DCanvas *target, void *videobuffer) override; + void RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch) override; // renders view to a savegame picture void WriteSavePic (player_t *player, FileWriter *file, int width, int height) override; diff --git a/src/rendering/swrenderer/r_swscene.cpp b/src/rendering/swrenderer/r_swscene.cpp index 164ffd536..8c24a3db1 100644 --- a/src/rendering/swrenderer/r_swscene.cpp +++ b/src/rendering/swrenderer/r_swscene.cpp @@ -106,10 +106,11 @@ sector_t *SWSceneDrawer::RenderView(player_t *player) Canvas.reset(new DCanvas(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor())); } - auto buf = fbtex->GetSystemTexture()->MapBuffer(); + IHardwareTexture *systemTexture = fbtex->GetSystemTexture(); + auto buf = systemTexture->MapBuffer(); if (!buf) I_FatalError("Unable to map buffer for software rendering"); - SWRenderer->RenderView(player, Canvas.get(), buf); - fbtex->GetSystemTexture()->CreateTexture(nullptr, screen->GetWidth(), screen->GetHeight(), 0, false, 0, "swbuffer"); + SWRenderer->RenderView(player, Canvas.get(), buf, systemTexture->GetBufferPitch()); + systemTexture->CreateTexture(nullptr, screen->GetWidth(), screen->GetHeight(), 0, false, 0, "swbuffer"); auto map = swrenderer::CameraLight::Instance()->ShaderColormap(); screen->DrawTexture(fbtex.get(), 0, 0, DTA_SpecialColormap, map, TAG_DONE); diff --git a/src/rendering/swrenderer/scene/r_scene.cpp b/src/rendering/swrenderer/scene/r_scene.cpp index b598f49b0..32a1a47c9 100644 --- a/src/rendering/swrenderer/scene/r_scene.cpp +++ b/src/rendering/swrenderer/scene/r_scene.cpp @@ -90,7 +90,7 @@ namespace swrenderer clearcolor = color; } - void RenderScene::RenderView(player_t *player, DCanvas *target, void *videobuffer) + void RenderScene::RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch) { auto viewport = MainThread()->Viewport.get(); viewport->RenderTarget = target; @@ -132,7 +132,7 @@ namespace swrenderer RenderActorView(player->mo, true, false); auto copyqueue = std::make_shared(MainThread()->FrameMemory.get()); - copyqueue->Push(videobuffer, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1); + copyqueue->Push(videobuffer, bufferpitch, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1); DrawerThreads::Execute(copyqueue); DrawerWaitCycles.Clock(); diff --git a/src/rendering/swrenderer/scene/r_scene.h b/src/rendering/swrenderer/scene/r_scene.h index cba258056..035d12133 100644 --- a/src/rendering/swrenderer/scene/r_scene.h +++ b/src/rendering/swrenderer/scene/r_scene.h @@ -48,7 +48,7 @@ namespace swrenderer void SetClearColor(int color); - void RenderView(player_t *player, DCanvas *target, void *videobuffer); + void RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch); void RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines = false); bool DontMapLines() const { return dontmaplines; } diff --git a/src/rendering/vulkan/system/vk_builders.h b/src/rendering/vulkan/system/vk_builders.h index af5b54c82..2b959aa61 100644 --- a/src/rendering/vulkan/system/vk_builders.h +++ b/src/rendering/vulkan/system/vk_builders.h @@ -47,7 +47,7 @@ public: bool isFormatSupported(VulkanDevice *device); - std::unique_ptr create(VulkanDevice *device); + std::unique_ptr create(VulkanDevice *device, VkDeviceSize* allocatedBytes = nullptr); std::unique_ptr tryCreate(VulkanDevice *device); private: @@ -424,7 +424,7 @@ inline bool ImageBuilder::isFormatSupported(VulkanDevice *device) return true; } -inline std::unique_ptr ImageBuilder::create(VulkanDevice *device) +inline std::unique_ptr ImageBuilder::create(VulkanDevice *device, VkDeviceSize* allocatedBytes) { VkImage image; VmaAllocation allocation; @@ -433,6 +433,14 @@ inline std::unique_ptr ImageBuilder::create(VulkanDevice *device) if (result != VK_SUCCESS) I_FatalError("Could not create vulkan image"); + if (allocatedBytes != nullptr) + { + VmaAllocationInfo allocatedInfo; + vmaGetAllocationInfo(device->allocator, allocation, &allocatedInfo); + + *allocatedBytes = allocatedInfo.size; + } + return std::make_unique(device, image, allocation, imageInfo.extent.width, imageInfo.extent.height, imageInfo.mipLevels); } diff --git a/src/rendering/vulkan/textures/vk_hwtexture.cpp b/src/rendering/vulkan/textures/vk_hwtexture.cpp index be94b747a..755e3a8dc 100644 --- a/src/rendering/vulkan/textures/vk_hwtexture.cpp +++ b/src/rendering/vulkan/textures/vk_hwtexture.cpp @@ -368,6 +368,7 @@ void VkHardwareTexture::AllocateBuffer(int w, int h, int texelsize) VkFormat format = texelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM; ImageBuilder imgbuilder; + VkDeviceSize allocatedBytes = 0; imgbuilder.setFormat(format); imgbuilder.setSize(w, h); imgbuilder.setLinearTiling(); @@ -375,7 +376,7 @@ void VkHardwareTexture::AllocateBuffer(int w, int h, int texelsize) imgbuilder.setMemoryType( VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - mImage = imgbuilder.create(fb->device); + mImage = imgbuilder.create(fb->device, &allocatedBytes); mImage->SetDebugName("VkHardwareTexture.mImage"); mImageLayout = VK_IMAGE_LAYOUT_GENERAL; mTexelsize = texelsize; @@ -390,6 +391,8 @@ void VkHardwareTexture::AllocateBuffer(int w, int h, int texelsize) PipelineBarrier imageTransition; imageTransition.addImage(mImage.get(), VK_IMAGE_LAYOUT_UNDEFINED, mImageLayout, 0, VK_ACCESS_SHADER_READ_BIT); imageTransition.execute(cmdbuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + bufferpitch = int(allocatedBytes / h / texelsize); } }