mirror of
https://github.com/yquake2/ref_vk.git
synced 2025-02-17 01:22:13 +00:00
Merge pull request #5 from Spirrwell/master
[WIP] Fixes for Vulkan backend
This commit is contained in:
commit
a7e53dd827
6 changed files with 131 additions and 99 deletions
|
@ -253,8 +253,8 @@ extern qvktexture_t vk_colorbuffer;
|
|||
extern qvktexture_t vk_colorbufferWarp;
|
||||
// indicator if the frame is currently being rendered
|
||||
extern qboolean vk_frameStarted;
|
||||
// Indicates if the renderer needs to be restarted.
|
||||
extern qboolean vk_restartNeeded;
|
||||
// Indicates if the swap chain needs to be rebuilt.
|
||||
extern qboolean vk_recreateSwapchainNeeded;
|
||||
// is QVk initialized?
|
||||
extern qboolean vk_initialized;
|
||||
|
||||
|
@ -295,6 +295,7 @@ const char* QVk_GetError(VkResult errorCode);
|
|||
VkResult QVk_BeginFrame(const VkViewport* viewport, const VkRect2D* scissor);
|
||||
VkResult QVk_EndFrame(qboolean force);
|
||||
void QVk_BeginRenderpass(qvkrenderpasstype_t rpType);
|
||||
qboolean QVk_RecreateSwapchain();
|
||||
void QVk_FreeStagingBuffer(qvkstagingbuffer_t *buffer);
|
||||
VkResult QVk_CreateBuffer(VkDeviceSize size, qvkbuffer_t *dstBuffer, const qvkbufferopts_t options);
|
||||
void QVk_FreeBuffer(qvkbuffer_t *buffer);
|
||||
|
|
|
@ -123,8 +123,8 @@ static uint32_t vk_imageIndex = 0;
|
|||
static int vk_activeStagingBuffer = 0;
|
||||
// started rendering frame?
|
||||
qboolean vk_frameStarted = false;
|
||||
// the renderer needs to be restarted.
|
||||
qboolean vk_restartNeeded = false;
|
||||
// the swap chain needs to be rebuilt.
|
||||
qboolean vk_recreateSwapchainNeeded = false;
|
||||
// is QVk initialized?
|
||||
qboolean vk_initialized = false;
|
||||
|
||||
|
@ -1363,7 +1363,6 @@ static void CreatePipelines()
|
|||
for (int i = 0; i < RP_COUNT; ++i)
|
||||
{
|
||||
vk_drawModelPipelineFan[i].topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
vk_drawModelPipelineFan[i].blendOpts.blendEnable = VK_TRUE;
|
||||
QVk_CreatePipeline(samplerUboDsLayouts, 2, &vertInfoRGB_RGBA_RG, &vk_drawModelPipelineFan[i], &vk_renderpasses[i], shaders, 2);
|
||||
QVk_DebugSetObjectName((uint64_t)vk_drawModelPipelineFan[i].layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT,
|
||||
va("Pipeline Layout: draw model: fan (%s)", renderpassObjectNames[i]));
|
||||
|
@ -2071,18 +2070,10 @@ VkResult QVk_BeginFrame(const VkViewport* viewport, const VkRect2D* scissor)
|
|||
|
||||
ReleaseSwapBuffers();
|
||||
|
||||
static int restartcount;
|
||||
VkResult result = vkAcquireNextImageKHR(vk_device.logical, vk_swapchain.sc, 500000000, vk_imageAvailableSemaphores[vk_activeBufferIdx], VK_NULL_HANDLE, &vk_imageIndex);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_SURFACE_LOST_KHR || result == VK_TIMEOUT)
|
||||
{
|
||||
if (restartcount > 2)
|
||||
{
|
||||
Sys_Error("%s(): tried to restart 3 times after vkAcquireNextImageKHR: %s", __func__, QVk_GetError(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
restartcount++;
|
||||
}
|
||||
vk_recreateSwapchainNeeded = true;
|
||||
|
||||
// for VK_OUT_OF_DATE_KHR and VK_SUBOPTIMAL_KHR it'd be fine to just rebuild the swapchain but let's take the easy way out and restart Vulkan.
|
||||
R_Printf(PRINT_ALL, "%s(): received %s after vkAcquireNextImageKHR - restarting video!\n", __func__, QVk_GetError(result));
|
||||
|
@ -2093,7 +2084,6 @@ VkResult QVk_BeginFrame(const VkViewport* viewport, const VkRect2D* scissor)
|
|||
Sys_Error("%s(): unexpected error after vkAcquireNextImageKHR: %s", __func__, QVk_GetError(result));
|
||||
}
|
||||
|
||||
restartcount = 0;
|
||||
vk_activeCmdbuffer = vk_commandbuffers[vk_activeBufferIdx];
|
||||
|
||||
// swap dynamic buffers
|
||||
|
@ -2185,7 +2175,7 @@ VkResult QVk_EndFrame(qboolean force)
|
|||
if (renderResult == VK_ERROR_OUT_OF_DATE_KHR || renderResult == VK_SUBOPTIMAL_KHR || renderResult == VK_ERROR_SURFACE_LOST_KHR)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "%s(): received %s after vkQueuePresentKHR - will restart video!\n", __func__, QVk_GetError(renderResult));
|
||||
vk_restartNeeded = true;
|
||||
vk_recreateSwapchainNeeded = true;
|
||||
}
|
||||
else if (renderResult != VK_SUCCESS)
|
||||
{
|
||||
|
@ -2266,22 +2256,45 @@ void QVk_BeginRenderpass(qvkrenderpasstype_t rpType)
|
|||
vk_state.current_renderpass = rpType;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void QVk_RecreateSwapchain()
|
||||
qboolean QVk_RecreateSwapchain()
|
||||
{
|
||||
VkResult result = VK_SUCCESS;
|
||||
vkDeviceWaitIdle( vk_device.logical );
|
||||
|
||||
DestroyFramebuffers();
|
||||
DestroyImageViews();
|
||||
VK_VERIFY(QVk_CreateSwapchain());
|
||||
|
||||
if (!QVk_CheckExtent())
|
||||
return false;
|
||||
|
||||
VK_VERIFY(result = QVk_CreateSwapchain());
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
return false;
|
||||
|
||||
vk_viewport.width = (float)vid.width;
|
||||
vk_viewport.height = (float)vid.height;
|
||||
vk_scissor.extent = vk_swapchain.extent;
|
||||
|
||||
DestroyDrawBuffers();
|
||||
CreateDrawBuffers();
|
||||
VK_VERIFY(CreateImageViews());
|
||||
VK_VERIFY(CreateFramebuffers());
|
||||
|
||||
VK_VERIFY(result = CreateImageViews());
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
return false;
|
||||
|
||||
VK_VERIFY(result = CreateFramebuffers());
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
return false;
|
||||
|
||||
QVk_UpdateTextureSampler(&vk_colorbuffer, S_NEAREST_UNNORMALIZED, false);
|
||||
QVk_UpdateTextureSampler(&vk_colorbufferWarp, S_NEAREST_UNNORMALIZED, false);
|
||||
|
||||
vk_recreateSwapchainNeeded = false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t *QVk_GetVertexBuffer(VkDeviceSize size, VkBuffer *dstBuffer, VkDeviceSize *dstOffset)
|
||||
{
|
||||
|
|
|
@ -270,13 +270,11 @@ RE_Draw_StretchRaw
|
|||
*/
|
||||
extern unsigned r_rawpalette[256];
|
||||
extern qvktexture_t vk_rawTexture;
|
||||
static int scaled_size = 512;
|
||||
|
||||
void RE_Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data)
|
||||
{
|
||||
|
||||
int i, j;
|
||||
int hscale, vscale;
|
||||
unsigned *dest;
|
||||
byte *source;
|
||||
byte *image_scaled;
|
||||
|
@ -313,45 +311,36 @@ void RE_Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *d
|
|||
image_scaled = data;
|
||||
}
|
||||
|
||||
if (vk_rawTexture.resource.image == VK_NULL_HANDLE)
|
||||
{
|
||||
// get power of two image size,
|
||||
// could be updated only size only after recreate texture
|
||||
for (scaled_size = 512; scaled_size < cols && scaled_size < rows; scaled_size <<= 1)
|
||||
;
|
||||
}
|
||||
|
||||
raw_image32 = malloc(scaled_size * scaled_size * sizeof(unsigned));
|
||||
|
||||
hscale = cols * 0x10000 / scaled_size;
|
||||
vscale = rows * 0x10000 / scaled_size;
|
||||
raw_image32 = malloc(cols * rows * sizeof(unsigned));
|
||||
|
||||
source = image_scaled;
|
||||
dest = raw_image32;
|
||||
for (i = 0; i < scaled_size; i++)
|
||||
for (i = 0; i < rows; ++i)
|
||||
{
|
||||
for (j = 0; j < scaled_size; j++)
|
||||
int rowOffset = i * cols;
|
||||
for (j = 0; j < cols; ++j)
|
||||
{
|
||||
*dest = r_rawpalette[*(source + ((j * hscale) >> 16))];
|
||||
dest ++;
|
||||
byte palIdx = source[rowOffset + j];
|
||||
dest[rowOffset + j] = r_rawpalette[palIdx];
|
||||
}
|
||||
source = image_scaled + (((i * vscale) >> 16) * cols);
|
||||
}
|
||||
|
||||
if (vk_retexturing->value)
|
||||
{
|
||||
free(image_scaled);
|
||||
SmoothColorImage(raw_image32, scaled_size * scaled_size, scaled_size >> 7);
|
||||
|
||||
int scaled_size = cols * rows;
|
||||
SmoothColorImage(raw_image32, scaled_size, (scaled_size) >> 7);
|
||||
}
|
||||
|
||||
if (vk_rawTexture.resource.image != VK_NULL_HANDLE)
|
||||
{
|
||||
QVk_UpdateTextureData(&vk_rawTexture, (unsigned char*)raw_image32, 0, 0, scaled_size, scaled_size);
|
||||
QVk_UpdateTextureData(&vk_rawTexture, (unsigned char*)raw_image32, 0, 0, cols, rows);
|
||||
}
|
||||
else
|
||||
{
|
||||
QVVKTEXTURE_CLEAR(vk_rawTexture);
|
||||
QVk_CreateTexture(&vk_rawTexture, (unsigned char*)raw_image32, scaled_size, scaled_size,
|
||||
QVk_CreateTexture(&vk_rawTexture, (unsigned char*)raw_image32, cols, rows,
|
||||
vk_current_sampler, false);
|
||||
QVk_DebugSetObjectName((uint64_t)vk_rawTexture.resource.image,
|
||||
VK_OBJECT_TYPE_IMAGE, "Image: raw texture");
|
||||
|
|
|
@ -846,11 +846,78 @@ static void Vk_LightScaleTexture (byte *in, int inwidth, int inheight)
|
|||
|
||||
/*
|
||||
===============
|
||||
Vk_Upload32
|
||||
Vk_Upload32Native
|
||||
|
||||
Returns number of mip levels
|
||||
Returns number of mip levels and scales native resolution
|
||||
if vk_picmip is set. Does not use power of 2 scaling.
|
||||
===============
|
||||
*/
|
||||
static uint32_t Vk_Upload32Native (byte *data, int width, int height, imagetype_t type,
|
||||
byte **texBuffer, int *upload_width, int *upload_height)
|
||||
{
|
||||
int scaled_width = width, scaled_height = height;
|
||||
int miplevel = 1;
|
||||
|
||||
*texBuffer = NULL;
|
||||
|
||||
if (type != it_pic)
|
||||
{
|
||||
// let people sample down the world textures for speed
|
||||
scaled_width >>= (int)vk_picmip->value;
|
||||
scaled_height >>= (int)vk_picmip->value;
|
||||
}
|
||||
|
||||
if (scaled_width < 1)
|
||||
scaled_width = 1;
|
||||
if (scaled_height < 1)
|
||||
scaled_height = 1;
|
||||
|
||||
if (scaled_width == width && scaled_height == height)
|
||||
{
|
||||
// We can just send the data back and avoid an extra allocation/copy
|
||||
*texBuffer = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
*texBuffer = malloc(scaled_width * scaled_height * 4);
|
||||
if (!*texBuffer)
|
||||
ri.Sys_Error(ERR_DROP, "%s: too big", __func__);
|
||||
|
||||
ResizeSTB(data, width, height,
|
||||
*texBuffer, scaled_width, scaled_height);
|
||||
}
|
||||
|
||||
*upload_width = scaled_width;
|
||||
*upload_height = scaled_height;
|
||||
|
||||
// world textures
|
||||
if (type != it_pic && type != it_sky)
|
||||
{
|
||||
Vk_LightScaleTexture(*texBuffer, scaled_width, scaled_height);
|
||||
}
|
||||
|
||||
while (scaled_width > 1 || scaled_height > 1)
|
||||
{
|
||||
scaled_width >>= 1;
|
||||
scaled_height >>= 1;
|
||||
if (scaled_width < 1)
|
||||
scaled_width = 1;
|
||||
if (scaled_height < 1)
|
||||
scaled_height = 1;
|
||||
miplevel++;
|
||||
}
|
||||
|
||||
return miplevel;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Vk_Upload32
|
||||
|
||||
Returns number of mip levels and scales to nearest power of 2.
|
||||
===============
|
||||
*/
|
||||
#if 0
|
||||
static uint32_t Vk_Upload32 (byte *data, int width, int height, imagetype_t type,
|
||||
byte **texBuffer, int *upload_width, int *upload_height)
|
||||
{
|
||||
|
@ -911,6 +978,7 @@ static uint32_t Vk_Upload32 (byte *data, int width, int height, imagetype_t type
|
|||
|
||||
return miplevel;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
===============
|
||||
|
@ -977,8 +1045,12 @@ static uint32_t Vk_Upload8 (byte *data, int width, int height, imagetype_t type,
|
|||
SmoothColorImage(trans, s, s >> 7);
|
||||
}
|
||||
|
||||
miplevel = Vk_Upload32((byte *)trans, width, height, type, texBuffer, upload_width, upload_height);
|
||||
free(trans);
|
||||
miplevel = Vk_Upload32Native((byte *)trans, width, height, type, texBuffer, upload_width, upload_height);
|
||||
|
||||
// Only free if *texBuffer isn't the image data we sent
|
||||
if (!texBuffer || *texBuffer != (byte *)trans)
|
||||
free(trans);
|
||||
|
||||
return miplevel;
|
||||
}
|
||||
|
||||
|
@ -1058,7 +1130,7 @@ Vk_LoadPic(char *name, byte *pic, int width, int realwidth,
|
|||
}
|
||||
}
|
||||
else
|
||||
image->vk_texture.mipLevels = Vk_Upload32(pic, width, height, image->type, &texBuffer, &upload_width, &upload_height);
|
||||
image->vk_texture.mipLevels = Vk_Upload32Native(pic, width, height, image->type, &texBuffer, &upload_width, &upload_height);
|
||||
|
||||
image->upload_width = upload_width; // after power of 2 and scales
|
||||
image->upload_height = upload_height;
|
||||
|
@ -1075,7 +1147,7 @@ Vk_LoadPic(char *name, byte *pic, int width, int realwidth,
|
|||
QVk_DebugSetObjectName((uint64_t)image->vk_texture.resource.memory,
|
||||
VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: game textures");
|
||||
|
||||
if (texBuffer)
|
||||
if (texBuffer && texBuffer != pic)
|
||||
{
|
||||
free(texBuffer);
|
||||
}
|
||||
|
|
|
@ -1385,36 +1385,9 @@ RE_BeginFrame( float camera_separation )
|
|||
return;
|
||||
}
|
||||
|
||||
/* Some GPU drivers set a maximum extent size of 0x0 when
|
||||
the window is minimized. But a swapchain with an extent
|
||||
size of 0x0 is invalid. This leads to the following
|
||||
problem:
|
||||
|
||||
1. The window is minimized, the extent size changes and
|
||||
the Vulkan state get's corrupted. QVk_EndFrame()
|
||||
above or QVk_BeginFrame() below detect the Vulkan
|
||||
state as corrupted, set vk_frameStated to false and
|
||||
request a restart by setting vk_restartNeeded to
|
||||
true.
|
||||
2. RE_EndFrame() triggers the restart. QVk_Shutdown()
|
||||
is successfull, but QVk_Init() can't create a valid
|
||||
swapchains and errors out. An incomplete internal
|
||||
renderer state is left behind. The only way out is
|
||||
to trigger a full render restart.
|
||||
3. The full renderer restart would lead to a restart
|
||||
loop: Restart -> QVk_Init() fails -> restart -> ...
|
||||
The only alternative is not to restart. Instead the
|
||||
renderer could error out, that would print an error
|
||||
message and quit the client.
|
||||
|
||||
Work around this by not starting the frame or restarting
|
||||
the renderer, as long as the maximum extent size is 0x0.
|
||||
This is part 1 (the state corruption war detect in the
|
||||
last frame), part 2 (the state corruption was detected in
|
||||
the current frame) is in RE_EndFrame(). */
|
||||
if (vk_restartNeeded)
|
||||
if (vk_recreateSwapchainNeeded)
|
||||
{
|
||||
if (!QVk_CheckExtent())
|
||||
if (QVk_RecreateSwapchain() != true)
|
||||
{
|
||||
vk_frameStarted = false;
|
||||
return;
|
||||
|
@ -1422,8 +1395,7 @@ RE_BeginFrame( float camera_separation )
|
|||
}
|
||||
|
||||
// if ri.Sys_Error() had been issued mid-frame, we might end up here without properly submitting the image, so call QVk_EndFrame to be safe
|
||||
if (QVk_EndFrame(true) != VK_SUCCESS)
|
||||
vk_restartNeeded = true;
|
||||
QVk_EndFrame(true);
|
||||
|
||||
/*
|
||||
** change modes if necessary
|
||||
|
@ -1450,9 +1422,7 @@ RE_BeginFrame( float camera_separation )
|
|||
}
|
||||
}
|
||||
|
||||
if (QVk_BeginFrame(&vk_viewport, &vk_scissor) != VK_SUCCESS)
|
||||
vk_restartNeeded = true;
|
||||
else
|
||||
if (QVk_BeginFrame(&vk_viewport, &vk_scissor) == VK_SUCCESS)
|
||||
QVk_BeginRenderpass(RP_WORLD);
|
||||
}
|
||||
|
||||
|
@ -1464,23 +1434,10 @@ RE_EndFrame
|
|||
static void
|
||||
RE_EndFrame( void )
|
||||
{
|
||||
if (QVk_EndFrame(false) != VK_SUCCESS)
|
||||
vk_restartNeeded = true;
|
||||
QVk_EndFrame(false);
|
||||
|
||||
// world has not rendered yet
|
||||
world_rendered = false;
|
||||
|
||||
/* Part two of the 'maximum extent size may be 0x0'
|
||||
* work around. See the explanation in RE_BeginFrame()
|
||||
* for details. */
|
||||
if (vk_restartNeeded)
|
||||
{
|
||||
if (QVk_CheckExtent())
|
||||
{
|
||||
QVk_Restart();
|
||||
vk_restartNeeded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -239,7 +239,7 @@ VkResult QVk_CreateSwapchain()
|
|||
return res;
|
||||
|
||||
VK_VERIFY(vkGetSwapchainImagesKHR(vk_device.logical, vk_swapchain.sc, &imageCount, NULL));
|
||||
vk_swapchain.images = (VkImage *)malloc(imageCount * sizeof(VkImage));
|
||||
vk_swapchain.images = (VkImage *)realloc(vk_swapchain.images, imageCount * sizeof(VkImage));
|
||||
vk_swapchain.imageCount = imageCount;
|
||||
res = vkGetSwapchainImagesKHR(vk_device.logical, vk_swapchain.sc, &imageCount, vk_swapchain.images);
|
||||
|
||||
|
|
Loading…
Reference in a new issue