vkd3d-shader/tpf: Add initial support for writing fx_4_0/fx_4_1 binaries.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
This commit is contained in:
Nikolay Sivov 2023-11-05 22:07:01 +01:00 committed by Alexandre Julliard
parent 9494b72224
commit a0207436f2
Notes: Alexandre Julliard 2024-01-11 23:13:27 +01:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Zebediah Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/443
8 changed files with 208 additions and 9 deletions

View File

@ -294,6 +294,7 @@ libvkd3d_shader_la_SOURCES = \
libs/vkd3d-shader/d3dbc.c \
libs/vkd3d-shader/dxbc.c \
libs/vkd3d-shader/dxil.c \
libs/vkd3d-shader/fx.c \
libs/vkd3d-shader/glsl.c \
libs/vkd3d-shader/hlsl.c \
libs/vkd3d-shader/hlsl.h \

158
libs/vkd3d-shader/fx.c Normal file
View File

@ -0,0 +1,158 @@
/*
* FX (Direct3D 9/10/11 effect) support
*
* Copyright 2023 Nikolay Sivov for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "hlsl.h"
struct fx_write_context
{
struct vkd3d_bytecode_buffer unstructured;
struct vkd3d_bytecode_buffer structured;
uint32_t technique_count;
int status;
};
static uint32_t fx_put_raw_string(struct fx_write_context *fx, const char *string)
{
/* NULLs are emitted as empty strings using the same 4 bytes at the start of the section. */
return string ? put_string(&fx->unstructured, string) : 0;
}
static void write_technique(struct hlsl_ir_var *var, struct fx_write_context *fx)
{
struct vkd3d_bytecode_buffer *buffer = &fx->structured;
uint32_t name_offset;
name_offset = fx_put_raw_string(fx, var->name);
put_u32(buffer, name_offset);
put_u32(buffer, 0); /* Pass count. */
put_u32(buffer, 0); /* Annotation count. */
/* TODO: passes */
}
static void set_status(struct fx_write_context *fx, int status)
{
if (fx->status < 0)
return;
if (status < 0)
fx->status = status;
}
static void write_techniques(struct hlsl_scope *scope, struct fx_write_context *fx)
{
struct hlsl_ir_var *var;
LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
{
const struct hlsl_type *type = var->data_type;
if (type->base_type == HLSL_TYPE_TECHNIQUE && type->e.version == 10)
{
write_technique(var, fx);
++fx->technique_count;
}
}
set_status(fx, fx->unstructured.status);
set_status(fx, fx->structured.status);
}
static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
{
struct vkd3d_bytecode_buffer buffer = { 0 };
struct fx_write_context fx;
uint32_t size_offset, size;
memset(&fx, 0, sizeof(fx));
put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
/* TODO: buffers */
/* TODO: objects */
/* TODO: shared buffers */
/* TODO: shared objects */
write_techniques(ctx->globals, &fx);
put_u32(&buffer, ctx->profile->minor_version == 0 ? 0xfeff1001 : 0xfeff1011); /* Version. */
put_u32(&buffer, 0); /* Buffer count. */
put_u32(&buffer, 0); /* Variable count. */
put_u32(&buffer, 0); /* Object count. */
put_u32(&buffer, 0); /* Pool buffer count. */
put_u32(&buffer, 0); /* Pool variable count. */
put_u32(&buffer, 0); /* Pool object count. */
put_u32(&buffer, fx.technique_count);
size_offset = put_u32(&buffer, 0); /* Unstructured size. */
put_u32(&buffer, 0); /* String count. */
put_u32(&buffer, 0); /* Texture object count. */
put_u32(&buffer, 0); /* Depth stencil state count. */
put_u32(&buffer, 0); /* Blend state count. */
put_u32(&buffer, 0); /* Rasterizer state count. */
put_u32(&buffer, 0); /* Sampler state count. */
put_u32(&buffer, 0); /* Rendertarget view count. */
put_u32(&buffer, 0); /* Depth stencil view count. */
put_u32(&buffer, 0); /* Shader count. */
put_u32(&buffer, 0); /* Inline shader count. */
size = align(fx.unstructured.size, 4);
set_u32(&buffer, size_offset, size);
bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size);
bytecode_put_bytes(&buffer, fx.structured.data, fx.structured.size);
vkd3d_free(fx.unstructured.data);
vkd3d_free(fx.structured.data);
set_status(&fx, buffer.status);
if (!fx.status)
{
out->code = buffer.data;
out->size = buffer.size;
}
if (fx.status < 0)
ctx->result = fx.status;
return fx.status;
}
int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
{
if (ctx->profile->major_version == 2)
{
hlsl_fixme(ctx, &ctx->location, "Writing fx_2_0 binaries is not implemented.");
return VKD3D_ERROR_NOT_IMPLEMENTED;
}
else if (ctx->profile->major_version == 4)
{
return hlsl_fx_4_write(ctx, out);
}
else if (ctx->profile->major_version == 5)
{
hlsl_fixme(ctx, &ctx->location, "Writing fx_5_0 binaries is not implemented.");
return VKD3D_ERROR_NOT_IMPLEMENTED;
}
else
{
vkd3d_unreachable();
}
}

View File

@ -3679,6 +3679,14 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d
return VKD3D_ERROR_NOT_IMPLEMENTED;
}
if (ctx.profile->type == VKD3D_SHADER_TYPE_EFFECT)
{
ret = hlsl_emit_effect_binary(&ctx, out);
hlsl_ctx_cleanup(&ctx);
return ret;
}
if ((func = hlsl_get_function(&ctx, entry_point)))
{
LIST_FOR_EACH_ENTRY(decl, &func->overloads, struct hlsl_ir_function_decl, entry)

View File

@ -1168,6 +1168,7 @@ void hlsl_dump_function(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl
int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func,
enum vkd3d_shader_target_type target_type, struct vkd3d_shader_code *out);
int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out);
bool hlsl_init_deref_from_index_chain(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_node *chain);
bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struct hlsl_deref *other);

View File

@ -383,13 +383,42 @@ size_t bytecode_put_bytes(struct vkd3d_bytecode_buffer *buffer, const void *byte
return offset;
}
void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value)
size_t bytecode_reserve_bytes(struct vkd3d_bytecode_buffer *buffer, size_t size)
{
size_t offset = bytecode_align(buffer);
if (buffer->status)
return offset;
if (!vkd3d_array_reserve((void **)&buffer->data, &buffer->capacity, offset + size, 1))
{
buffer->status = VKD3D_ERROR_OUT_OF_MEMORY;
return offset;
}
memset(buffer->data + offset, 0, size);
buffer->size = offset + size;
return offset;
}
static void bytecode_set_bytes(struct vkd3d_bytecode_buffer *buffer, size_t offset,
const void *value, size_t size)
{
if (buffer->status)
return;
assert(vkd3d_bound_range(offset, sizeof(value), buffer->size));
memcpy(buffer->data + offset, &value, sizeof(value));
assert(vkd3d_bound_range(offset, size, buffer->size));
memcpy(buffer->data + offset, value, size);
}
void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value)
{
bytecode_set_bytes(buffer, offset, &value, sizeof(value));
}
void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char *string, size_t length)
{
bytecode_set_bytes(buffer, offset, string, length);
}
static void vkd3d_shader_dump_blob(const char *path, const char *profile,

View File

@ -1357,7 +1357,9 @@ struct vkd3d_bytecode_buffer
/* Align to the next 4-byte offset, and return that offset. */
size_t bytecode_align(struct vkd3d_bytecode_buffer *buffer);
size_t bytecode_put_bytes(struct vkd3d_bytecode_buffer *buffer, const void *bytes, size_t size);
size_t bytecode_reserve_bytes(struct vkd3d_bytecode_buffer *buffer, size_t size);
void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value);
void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char *string, size_t length);
static inline size_t put_u32(struct vkd3d_bytecode_buffer *buffer, uint32_t value)
{

View File

@ -86,7 +86,7 @@ technique10
}
% Effects without techniques are not allowed for fx_2_0
[effect fail]
[effect fail todo]
float4 f;
% fx_5_0 keyword fails with fx_2_0 profile

View File

@ -37,7 +37,7 @@ float4 main() : sv_target
return fxGroup;
}
[effect todo]
[effect]
technique
{
}
@ -47,11 +47,11 @@ technique10
}
% Effects without techniques are allowed for fx_4_0+
[effect todo]
[effect]
float4 f;
% fx_2_0 keyword is allowed with fx_4_0+ profiles
[effect todo]
[effect]
technique
{
}
@ -90,10 +90,10 @@ float4 technique10;
[effect fail]
float4 technique11;
[effect todo]
[effect]
float4 technIque10;
[effect todo]
[effect]
float4 technIque11;
% Regular shaders with technique blocks