2023-11-05 13:07:01 -08:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2023-11-10 16:14:03 -08:00
|
|
|
static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
|
2023-11-05 13:07:01 -08:00
|
|
|
{
|
|
|
|
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); /* Annotation count. */
|
2023-11-10 16:14:03 -08:00
|
|
|
put_u32(buffer, 0); /* Assignment count. */
|
|
|
|
}
|
|
|
|
|
|
|
|
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, count = 0;
|
|
|
|
struct hlsl_ir_var *pass;
|
|
|
|
uint32_t count_offset;
|
|
|
|
|
|
|
|
name_offset = fx_put_raw_string(fx, var->name);
|
|
|
|
put_u32(buffer, name_offset);
|
|
|
|
count_offset = put_u32(buffer, 0);
|
|
|
|
put_u32(buffer, 0); /* Annotation count. */
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(pass, &var->scope->vars, struct hlsl_ir_var, scope_entry)
|
|
|
|
{
|
|
|
|
write_pass(pass, fx);
|
|
|
|
++count;
|
|
|
|
}
|
2023-11-05 13:07:01 -08:00
|
|
|
|
2023-11-10 16:14:03 -08:00
|
|
|
set_u32(buffer, count_offset, count);
|
2023-11-05 13:07:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|