diff --git a/libs/vkd3d-shader/checksum.c b/libs/vkd3d-shader/checksum.c index d9560628..45de1c92 100644 --- a/libs/vkd3d-shader/checksum.c +++ b/libs/vkd3d-shader/checksum.c @@ -33,6 +33,11 @@ * 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" #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); } -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 length; unsigned int count; unsigned char *p; @@ -260,7 +264,7 @@ static void dxbc_checksum_final(struct md5_ctx *ctx) /* Now fill the next block */ 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 */ 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 */ memset(p + 4, 0, padding - 4); } + else + { + /* Pad block to 56 bytes */ + memset(p, 0, padding - 8); + } /* Append length in bits and transform */ - 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)); + if (variant == VKD3D_MD5_DXBC) + { + unsigned int 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); byte_reverse((unsigned char *)ctx->buf, 4); memcpy(ctx->digest, ctx->buf, 16); } -#define DXBC_CHECKSUM_SKIP_BYTE_COUNT 20 - -void vkd3d_compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksum[4]) +void vkd3d_compute_md5(const void *data, size_t size, uint32_t checksum[4], enum vkd3d_md5_variant variant) { - const uint8_t *ptr = dxbc; + const uint8_t *ptr = data; 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_update(&ctx, ptr, size); - dxbc_checksum_final(&ctx); + md5_final(&ctx, variant); memcpy(checksum, ctx.digest, sizeof(ctx.digest)); } diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index 184788dc..93fc993e 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -20,6 +20,19 @@ #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) { 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)); - vkd3d_compute_dxbc_checksum(buffer.data, buffer.size, checksum); + compute_dxbc_checksum(buffer.data, buffer.size, checksum); for (i = 0; i < 4; ++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); 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))) { 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->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) set_u32(&context.buffer, (i + 1) * sizeof(uint32_t), checksum[i]); diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 353288b3..cd3c3b24 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -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, 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]; - unsigned int id; + unsigned int i; 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) - 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 - 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 (fwrite(data, 1, size, f) != size) diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 8c2d2f95..44dc5272 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1580,7 +1580,13 @@ int spirv_compile(struct vsir_program *program, uint64_t config_flags, const struct vkd3d_shader_compile_info *compile_info, 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, struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context);