vkd3d-shader: Use a hash to build the filename when dumping shaders.

This way the same shader is always dumped to the same path and when
launching the same program over and over we avoid both creating new
copies of the same file each time and overwriting different dumped
shaders.
This commit is contained in:
Giovanni Mascellani 2024-08-12 15:17:30 +02:00 committed by Henri Verbeet
parent 0e72aba0bc
commit 1a0d6a4db4
Notes: Henri Verbeet 2024-08-29 19:26:26 +02:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/992
4 changed files with 70 additions and 26 deletions

View File

@ -33,6 +33,11 @@
* will fill a supplied 16-byte array with the digest. * will fill a supplied 16-byte array with the digest.
*/ */
/*
* DXBC uses a variation of the MD5 algorithm, which only changes the way
* the message is padded in the final step.
*/
#include "vkd3d_shader_private.h" #include "vkd3d_shader_private.h"
#define DXBC_CHECKSUM_BLOCK_SIZE 64 #define DXBC_CHECKSUM_BLOCK_SIZE 64
@ -230,10 +235,9 @@ static void md5_update(struct md5_ctx *ctx, const unsigned char *buf, unsigned i
memcpy(ctx->in, buf, len); memcpy(ctx->in, buf, len);
} }
static void dxbc_checksum_final(struct md5_ctx *ctx) static void md5_final(struct md5_ctx *ctx, enum vkd3d_md5_variant variant)
{ {
unsigned int padding; unsigned int padding;
unsigned int length;
unsigned int count; unsigned int count;
unsigned char *p; unsigned char *p;
@ -260,7 +264,7 @@ static void dxbc_checksum_final(struct md5_ctx *ctx)
/* Now fill the next block */ /* Now fill the next block */
memset(ctx->in, 0, DXBC_CHECKSUM_BLOCK_SIZE); memset(ctx->in, 0, DXBC_CHECKSUM_BLOCK_SIZE);
} }
else else if (variant == VKD3D_MD5_DXBC)
{ {
/* Make place for bitcount at the beginning of the block */ /* Make place for bitcount at the beginning of the block */
memmove(&ctx->in[4], ctx->in, count); memmove(&ctx->in[4], ctx->in, count);
@ -268,33 +272,44 @@ static void dxbc_checksum_final(struct md5_ctx *ctx)
/* Pad block to 60 bytes */ /* Pad block to 60 bytes */
memset(p + 4, 0, padding - 4); memset(p + 4, 0, padding - 4);
} }
else
{
/* Pad block to 56 bytes */
memset(p, 0, padding - 8);
}
/* Append length in bits and transform */ /* Append length in bits and transform */
length = ctx->i[0]; if (variant == VKD3D_MD5_DXBC)
memcpy(&ctx->in[0], &length, sizeof(length)); {
byte_reverse(&ctx->in[4], 14); unsigned int length;
length = ctx->i[0] >> 2 | 0x1;
memcpy(&ctx->in[DXBC_CHECKSUM_BLOCK_SIZE - 4], &length, sizeof(length)); length = ctx->i[0];
memcpy(&ctx->in[0], &length, sizeof(length));
byte_reverse(&ctx->in[4], 14);
length = ctx->i[0] >> 2 | 0x1;
memcpy(&ctx->in[DXBC_CHECKSUM_BLOCK_SIZE - 4], &length, sizeof(length));
}
else
{
byte_reverse(ctx->in, 14);
((unsigned int *)ctx->in)[14] = ctx->i[0];
((unsigned int *)ctx->in)[15] = ctx->i[1];
}
md5_transform(ctx->buf, (unsigned int *)ctx->in); md5_transform(ctx->buf, (unsigned int *)ctx->in);
byte_reverse((unsigned char *)ctx->buf, 4); byte_reverse((unsigned char *)ctx->buf, 4);
memcpy(ctx->digest, ctx->buf, 16); memcpy(ctx->digest, ctx->buf, 16);
} }
#define DXBC_CHECKSUM_SKIP_BYTE_COUNT 20 void vkd3d_compute_md5(const void *data, size_t size, uint32_t checksum[4], enum vkd3d_md5_variant variant)
void vkd3d_compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4])
{ {
const uint8_t *ptr = dxbc; const uint8_t *ptr = data;
struct md5_ctx ctx; struct md5_ctx ctx;
VKD3D_ASSERT(size > DXBC_CHECKSUM_SKIP_BYTE_COUNT);
ptr += DXBC_CHECKSUM_SKIP_BYTE_COUNT;
size -= DXBC_CHECKSUM_SKIP_BYTE_COUNT;
md5_init(&ctx); md5_init(&ctx);
md5_update(&ctx, ptr, size); md5_update(&ctx, ptr, size);
dxbc_checksum_final(&ctx); md5_final(&ctx, variant);
memcpy(checksum, ctx.digest, sizeof(ctx.digest)); memcpy(checksum, ctx.digest, sizeof(ctx.digest));
} }

View File

@ -20,6 +20,19 @@
#include "vkd3d_shader_private.h" #include "vkd3d_shader_private.h"
#define DXBC_CHECKSUM_SKIP_BYTE_COUNT 20
static void compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4])
{
const uint8_t *ptr = dxbc;
VKD3D_ASSERT(size > DXBC_CHECKSUM_SKIP_BYTE_COUNT);
ptr += DXBC_CHECKSUM_SKIP_BYTE_COUNT;
size -= DXBC_CHECKSUM_SKIP_BYTE_COUNT;
vkd3d_compute_md5(ptr, size, checksum, VKD3D_MD5_DXBC);
}
void dxbc_writer_init(struct dxbc_writer *dxbc) void dxbc_writer_init(struct dxbc_writer *dxbc)
{ {
memset(dxbc, 0, sizeof(*dxbc)); memset(dxbc, 0, sizeof(*dxbc));
@ -72,7 +85,7 @@ int vkd3d_shader_serialize_dxbc(size_t section_count, const struct vkd3d_shader_
} }
set_u32(&buffer, size_position, bytecode_get_size(&buffer)); set_u32(&buffer, size_position, bytecode_get_size(&buffer));
vkd3d_compute_dxbc_checksum(buffer.data, buffer.size, checksum); compute_dxbc_checksum(buffer.data, buffer.size, checksum);
for (i = 0; i < 4; ++i) for (i = 0; i < 4; ++i)
set_u32(&buffer, checksum_position + i * sizeof(uint32_t), checksum[i]); set_u32(&buffer, checksum_position + i * sizeof(uint32_t), checksum[i]);
@ -188,7 +201,7 @@ static int parse_dxbc(const struct vkd3d_shader_code *dxbc, struct vkd3d_shader_
checksum[3] = read_u32(&ptr); checksum[3] = read_u32(&ptr);
if (!(flags & VKD3D_SHADER_PARSE_DXBC_IGNORE_CHECKSUM)) if (!(flags & VKD3D_SHADER_PARSE_DXBC_IGNORE_CHECKSUM))
{ {
vkd3d_compute_dxbc_checksum(data, data_size, calculated_checksum); compute_dxbc_checksum(data, data_size, calculated_checksum);
if (memcmp(checksum, calculated_checksum, sizeof(checksum))) if (memcmp(checksum, calculated_checksum, sizeof(checksum)))
{ {
WARN("Checksum {0x%08x, 0x%08x, 0x%08x, 0x%08x} does not match " WARN("Checksum {0x%08x, 0x%08x, 0x%08x, 0x%08x} does not match "
@ -1488,7 +1501,7 @@ int vkd3d_shader_serialize_root_signature(const struct vkd3d_shader_versioned_ro
dxbc->code = context.buffer.data; dxbc->code = context.buffer.data;
dxbc->size = total_size; dxbc->size = total_size;
vkd3d_compute_dxbc_checksum(dxbc->code, dxbc->size, checksum); compute_dxbc_checksum(dxbc->code, dxbc->size, checksum);
for (i = 0; i < 4; ++i) for (i = 0; i < 4; ++i)
set_u32(&context.buffer, (i + 1) * sizeof(uint32_t), checksum[i]); set_u32(&context.buffer, (i + 1) * sizeof(uint32_t), checksum[i]);

View File

@ -448,17 +448,27 @@ void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char
static void vkd3d_shader_dump_blob(const char *path, const char *profile, static void vkd3d_shader_dump_blob(const char *path, const char *profile,
const char *suffix, const void *data, size_t size) const char *suffix, const void *data, size_t size)
{ {
static unsigned int shader_id = 0; static const char hexadecimal_digits[] = "0123456789abcdef";
char str_checksum[33];
uint8_t checksum[16];
char filename[1024]; char filename[1024];
unsigned int id; unsigned int i;
FILE *f; FILE *f;
id = vkd3d_atomic_increment_u32(&shader_id) - 1; vkd3d_compute_md5(data, size, (uint32_t *)checksum, VKD3D_MD5_STANDARD);
for (i = 0; i < ARRAY_SIZE(checksum); ++i)
{
str_checksum[2 * i] = hexadecimal_digits[checksum[i] >> 4];
str_checksum[2 * i + 1] = hexadecimal_digits[checksum[i] & 0xf];
}
str_checksum[32] = '\0';
if (profile) if (profile)
snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%u-%s.%s", path, id, profile, suffix); snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%s-%s.%s", path, str_checksum, profile, suffix);
else else
snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%u.%s", path, id, suffix); snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%s.%s", path, str_checksum, suffix);
TRACE("Dumping shader to \"%s\".\n", filename);
if ((f = fopen(filename, "wb"))) if ((f = fopen(filename, "wb")))
{ {
if (fwrite(data, 1, size, f) != size) if (fwrite(data, 1, size, f) != size)

View File

@ -1580,7 +1580,13 @@ int spirv_compile(struct vsir_program *program, uint64_t config_flags,
const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context);
void vkd3d_compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4]); enum vkd3d_md5_variant
{
VKD3D_MD5_STANDARD,
VKD3D_MD5_DXBC,
};
void vkd3d_compute_md5(const void *dxbc, size_t size, uint32_t checksum[4], enum vkd3d_md5_variant variant);
int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info, int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context);