1
0
Fork 0

Vulkan: refactored image creation/uploading

This commit is contained in:
Eugene 2022-02-07 19:18:44 +02:00
parent 9557e5fdf5
commit 5a67e8538f
5 changed files with 67 additions and 54 deletions

View File

@ -1108,21 +1108,11 @@ void RE_UploadCinematic( int w, int h, int cols, int rows, byte *data, int clien
// if the scratchImage isn't in the format we want, specify it as a new texture
if ( cols != image->width || rows != image->height ) {
byte *buffer;
int bytes_per_pixel;
image->width = image->uploadWidth = cols;
image->height = image->uploadHeight = rows;
#ifdef USE_VULKAN
qvkDestroyImage( vk.device, image->handle, NULL );
qvkDestroyImageView( vk.device, image->view, NULL );
vk_create_image( cols, rows, image->internalFormat, 1, image );
buffer = resample_image_data( image, data, cols * rows * 4, &bytes_per_pixel );
vk_upload_image_data( image->handle, 0, 0, cols, rows, qfalse, buffer, bytes_per_pixel );
if ( buffer != data ) {
ri.Hunk_FreeTempMemory( buffer );
}
vk_create_image( image, cols, rows, 1 );
vk_upload_image_data( image, 0, 0, cols, rows, 1, data, cols * rows * 4 );
#else
qglTexImage2D( GL_TEXTURE_2D, 0, image->internalFormat, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
@ -1131,17 +1121,10 @@ void RE_UploadCinematic( int w, int h, int cols, int rows, byte *data, int clien
qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl_clamp_mode );
#endif
} else if ( dirty ) {
byte *buffer;
int bytes_per_pixel;
// otherwise, just subimage upload it so that drivers can tell we are going to be changing
// it and don't try and do a texture compression
#ifdef USE_VULKAN
buffer = resample_image_data( image, data, cols * rows * 4, &bytes_per_pixel );
vk_upload_image_data( image->handle, 0, 0, cols, rows, qfalse, buffer, bytes_per_pixel );
if ( buffer != data ) {
ri.Hunk_FreeTempMemory( buffer );
}
vk_upload_image_data( image, 0, 0, cols, rows, 1, data, cols * rows * 4 );
#else
qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
#endif

View File

@ -366,7 +366,7 @@ static void R_LoadMergedLightmaps( const lump_t *l, byte *image )
R_ProcessLightmap( image, buf + offs, maxIntensity );
#ifdef USE_VULKAN
vk_upload_image_data( tr.lightmaps[ i ]->handle, x * LIGHTMAP_LEN, y * LIGHTMAP_LEN, LIGHTMAP_LEN, LIGHTMAP_LEN, qfalse, image, 4 );
vk_upload_image_data( tr.lightmaps[ i ], x * LIGHTMAP_LEN, y * LIGHTMAP_LEN, LIGHTMAP_LEN, LIGHTMAP_LEN, 1, image, LIGHTMAP_LEN * LIGHTMAP_LEN * 4 );
#else
R_UploadSubImage( image, x * LIGHTMAP_LEN, y * LIGHTMAP_LEN, LIGHTMAP_LEN, LIGHTMAP_LEN, tr.lightmaps[ i ] );
#endif

View File

@ -182,6 +182,10 @@ void R_ImageList_f( void ) {
format = "RGBA ";
estSize *= 4;
break;
case VK_FORMAT_R8G8B8_UNORM:
format = "RGB ";
estSize *= 3;
break;
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
format = "RGBA ";
estSize *= 2;
@ -743,7 +747,7 @@ byte *resample_image_data( const image_t *image, byte *data, const int data_size
{
byte *buffer;
uint16_t *p;
int i;
int i, n;
switch ( image->internalFormat ) {
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
@ -788,6 +792,17 @@ byte *resample_image_data( const image_t *image, byte *data, const int data_size
*bytes_per_pixel = 4;
return buffer;
case VK_FORMAT_R8G8B8_UNORM: {
buffer = (byte*)ri.Hunk_AllocateTempMemory( (data_size * 3) / 4 );
for ( i = 0, n = 0; i < data_size; i += 4, n += 3 ) {
buffer[n + 0] = data[i + 0];
buffer[n + 1] = data[i + 1];
buffer[n + 2] = data[i + 2];
}
*bytes_per_pixel = 3;
return buffer;
}
default:
*bytes_per_pixel = 4;
return data;
@ -795,17 +810,21 @@ byte *resample_image_data( const image_t *image, byte *data, const int data_size
}
static void upload_vk_image( Image_Upload_Data *upload_data, image_t *image ) {
int w = upload_data->base_level_width;
int h = upload_data->base_level_height;
int bytes_per_pixel;
byte *buffer;
static void upload_vk_image( image_t *image, byte *pic ) {
Image_Upload_Data upload_data;
int w, h;
generate_image_upload_data( image, pic, &upload_data );
w = upload_data.base_level_width;
h = upload_data.base_level_height;
if ( r_texturebits->integer > 16 || r_texturebits->integer == 0 || ( image->flags & IMGFLAG_LIGHTMAP ) ) {
image->internalFormat = VK_FORMAT_R8G8B8A8_UNORM;
//image->internalFormat = VK_FORMAT_B8G8R8A8_UNORM;
} else {
qboolean has_alpha = RawImage_HasAlpha( upload_data->buffer, w * h );
qboolean has_alpha = RawImage_HasAlpha( upload_data.buffer, w * h );
image->internalFormat = has_alpha ? VK_FORMAT_B4G4R4A4_UNORM_PACK16 : VK_FORMAT_A1R5G5B5_UNORM_PACK16;
}
@ -813,15 +832,13 @@ static void upload_vk_image( Image_Upload_Data *upload_data, image_t *image ) {
image->view = VK_NULL_HANDLE;
image->descriptor = VK_NULL_HANDLE;
image->uploadWidth = upload_data->base_level_width;
image->uploadHeight = upload_data->base_level_height;
image->uploadWidth = w;
image->uploadHeight = h;
vk_create_image( w, h, image->internalFormat, upload_data->mip_levels, image );
buffer = resample_image_data( image, upload_data->buffer, upload_data->buffer_size, &bytes_per_pixel );
vk_upload_image_data( image->handle, 0, 0, w, h, upload_data->mip_levels > 1, buffer, bytes_per_pixel );
if ( buffer != upload_data->buffer ) {
ri.Hunk_FreeTempMemory( buffer );
}
vk_create_image( image, w, h, upload_data.mip_levels );
vk_upload_image_data( image, 0, 0, w, h, upload_data.mip_levels, upload_data.buffer, upload_data.buffer_size );
ri.Hunk_FreeTempMemory( upload_data.buffer );
}
#else // !USE_VULKAN
@ -1058,9 +1075,7 @@ Picture data may be modified in-place during mipmap processing
image_t *R_CreateImage( const char *name, const char *name2, byte *pic, int width, int height, imgFlags_t flags ) {
image_t *image;
long hash;
#ifdef USE_VULKAN
Image_Upload_Data upload_data;
#else
#ifndef USE_VULKAN
GLint glWrapClampMode;
GLuint currTexture;
int currTMU;
@ -1119,11 +1134,7 @@ image_t *R_CreateImage( const char *name, const char *name2, byte *pic, int widt
else
image->wrapClampMode = VK_SAMPLER_ADDRESS_MODE_REPEAT;
generate_image_upload_data( image, pic, &upload_data );
upload_vk_image( &upload_data, image );
ri.Hunk_FreeTempMemory( upload_data.buffer );
upload_vk_image( image, pic );
#else
if ( flags & IMGFLAG_RGB )
image->internalFormat = GL_RGB;

View File

@ -4167,7 +4167,18 @@ static void record_buffer_memory_barrier(VkCommandBuffer cb, VkBuffer buffer, Vk
}
void vk_create_image( int width, int height, VkFormat format, int mip_levels, image_t *image ) {
void vk_create_image( image_t *image, int width, int height, int mip_levels ) {
VkFormat format = image->internalFormat;
if ( image->handle ) {
qvkDestroyImage( vk.device, image->handle, NULL );
}
if ( image->view ) {
qvkDestroyImageView( vk.device, image->view, NULL );
}
// create image
{
VkImageCreateInfo desc;
@ -4240,15 +4251,19 @@ void vk_create_image( int width, int height, VkFormat format, int mip_levels, im
}
void vk_upload_image_data( VkImage image, int x, int y, int width, int height, qboolean mipmap, const uint8_t *pixels, int bytes_per_pixel ) {
void vk_upload_image_data( image_t *image, int x, int y, int width, int height, int mipmaps, byte *pixels, int size ) {
VkCommandBuffer command_buffer;
VkBufferImageCopy regions[16];
VkBufferImageCopy region;
byte *buf;
int bpp;
int num_regions = 0;
int buffer_size = 0;
buf = resample_image_data( image, pixels, size, &bpp );
while (qtrue) {
Com_Memset(&region, 0, sizeof(region));
region.bufferOffset = buffer_size;
@ -4268,9 +4283,9 @@ void vk_upload_image_data( VkImage image, int x, int y, int width, int height, q
regions[num_regions] = region;
num_regions++;
buffer_size += width * height * bytes_per_pixel;
buffer_size += width * height * bpp;
if ( !mipmap || (width == 1 && height == 1) || num_regions >= ARRAY_LEN( regions ) )
if ( num_regions >= mipmaps || (width == 1 && height == 1) || num_regions >= ARRAY_LEN( regions ) )
break;
x >>= 1;
@ -4284,16 +4299,20 @@ void vk_upload_image_data( VkImage image, int x, int y, int width, int height, q
}
ensure_staging_buffer_allocation(buffer_size);
Com_Memcpy( vk_world.staging_buffer_ptr, pixels, buffer_size );
Com_Memcpy( vk_world.staging_buffer_ptr, buf, buffer_size );
command_buffer = begin_command_buffer();
record_buffer_memory_barrier( command_buffer, vk_world.staging_buffer, VK_WHOLE_SIZE, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT );
record_image_layout_transition( command_buffer, image, VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_IMAGE_LAYOUT_UNDEFINED, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL );
qvkCmdCopyBufferToImage( command_buffer, vk_world.staging_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, num_regions, regions );
record_image_layout_transition( command_buffer, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL );
record_image_layout_transition( command_buffer, image->handle, VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_IMAGE_LAYOUT_UNDEFINED, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL );
qvkCmdCopyBufferToImage( command_buffer, vk_world.staging_buffer, image->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, num_regions, regions );
record_image_layout_transition( command_buffer, image->handle, VK_IMAGE_ASPECT_COLOR_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL );
end_command_buffer( command_buffer );
if ( buf != pixels ) {
ri.Hunk_FreeTempMemory( buf );
}
}

View File

@ -198,8 +198,8 @@ void vk_wait_idle( void );
//
// Resources allocation.
//
void vk_create_image( int width, int height, VkFormat format, int mip_levels, image_t *image );
void vk_upload_image_data( VkImage image, int x, int y, int width, int height, qboolean mipmap, const uint8_t* pixels, int bytes_per_pixel );
void vk_create_image( image_t *image, int width, int height, int mip_levels );
void vk_upload_image_data( image_t *image, int x, int y, int width, int height, int miplevels, byte *pixels, int size );
byte *resample_image_data( const image_t *image, byte *data, const int data_size, int *bytes_per_pixel );
void vk_update_descriptor_set( image_t *image, qboolean mipmap );