- 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
This commit is contained in:
alexey.lysiuk 2019-05-08 11:39:21 +03:00
parent edcce76f3a
commit 56557a17f1
14 changed files with 41 additions and 27 deletions

View file

@ -24,7 +24,7 @@ struct FRenderer
virtual void Precache(uint8_t *texhitlist, TMap<PClassActor*, bool> &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;

View file

@ -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);

View file

@ -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;
};

View file

@ -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<DrawerCommandQueue>(Threads.MainThread()->FrameMemory.get());
copyqueue->Push<MemcpyCommand>(videobuffer, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1);
copyqueue->Push<MemcpyCommand>(videobuffer, bufferpitch, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1);
DrawerThreads::Execute(copyqueue);
PolyDrawerWaitCycles.Clock();

View file

@ -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();

View file

@ -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++)
{

View file

@ -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;

View file

@ -183,13 +183,13 @@ void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap<PClassActor*, bool> &
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;
}

View file

@ -12,7 +12,7 @@ struct FSoftwareRenderer : public FRenderer
void Precache(uint8_t *texhitlist, TMap<PClassActor*, bool> &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;

View file

@ -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);

View file

@ -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<DrawerCommandQueue>(MainThread()->FrameMemory.get());
copyqueue->Push<MemcpyCommand>(videobuffer, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1);
copyqueue->Push<MemcpyCommand>(videobuffer, bufferpitch, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1);
DrawerThreads::Execute(copyqueue);
DrawerWaitCycles.Clock();

View file

@ -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; }

View file

@ -47,7 +47,7 @@ public:
bool isFormatSupported(VulkanDevice *device);
std::unique_ptr<VulkanImage> create(VulkanDevice *device);
std::unique_ptr<VulkanImage> create(VulkanDevice *device, VkDeviceSize* allocatedBytes = nullptr);
std::unique_ptr<VulkanImage> tryCreate(VulkanDevice *device);
private:
@ -424,7 +424,7 @@ inline bool ImageBuilder::isFormatSupported(VulkanDevice *device)
return true;
}
inline std::unique_ptr<VulkanImage> ImageBuilder::create(VulkanDevice *device)
inline std::unique_ptr<VulkanImage> ImageBuilder::create(VulkanDevice *device, VkDeviceSize* allocatedBytes)
{
VkImage image;
VmaAllocation allocation;
@ -433,6 +433,14 @@ inline std::unique_ptr<VulkanImage> 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<VulkanImage>(device, image, allocation, imageInfo.extent.width, imageInfo.extent.height, imageInfo.mipLevels);
}

View file

@ -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);
}
}