Skip to content
Permalink
Browse files

- 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
  • Loading branch information...
alexey-lysiuk authored and madame-rachelle committed May 8, 2019
1 parent efd0bf4 commit 2d69f750927f12fe4d224f7529acee46d7c6ea02
@@ -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;
@@ -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);
@@ -14,10 +14,6 @@ class IHardwareTexture
MAX_TEXTURES = 16
};

public:


public:
IHardwareTexture() {}
virtual ~IHardwareTexture() {}

@@ -26,5 +22,9 @@ class IHardwareTexture
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;
};
@@ -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();
@@ -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();

@@ -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++)
{
@@ -125,12 +125,13 @@ class GroupMemoryBarrierCommand : public DrawerCommand
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;
@@ -183,21 +183,21 @@ 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;
}
else
{
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;
}
@@ -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;
@@ -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);
@@ -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();
@@ -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; }
@@ -47,7 +47,7 @@ class ImageBuilder

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

@@ -368,14 +368,15 @@ 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();
imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT, VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT);
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);
}
}

0 comments on commit 2d69f75

Please sign in to comment.
You can’t perform that action at this time.