Files
LNXRNT/Kinc/Backends/Graphics4/Direct3D9/Sources/kinc/backend/graphics4/pipeline.cpp
2025-01-29 10:55:49 +01:00

366 lines
12 KiB
C++

#include <kinc/graphics4/graphics.h>
#include <kinc/graphics4/pipeline.h>
#include <kinc/graphics4/shader.h>
#include <kinc/graphics4/vertexstructure.h>
#include <kinc/log.h>
#include <kinc/system.h>
#include <kinc/backend/SystemMicrosoft.h>
#include "Direct3D9.h"
#include <assert.h>
#include <malloc.h>
namespace {
_D3DBLEND convert_blend_factor(kinc_g4_blending_factor_t factor) {
switch (factor) {
case KINC_G4_BLEND_ONE:
return D3DBLEND_ONE;
case KINC_G4_BLEND_ZERO:
return D3DBLEND_ZERO;
case KINC_G4_BLEND_SOURCE_ALPHA:
return D3DBLEND_SRCALPHA;
case KINC_G4_BLEND_DEST_ALPHA:
return D3DBLEND_DESTALPHA;
case KINC_G4_BLEND_INV_SOURCE_ALPHA:
return D3DBLEND_INVSRCALPHA;
case KINC_G4_BLEND_INV_DEST_ALPHA:
return D3DBLEND_INVDESTALPHA;
case KINC_G4_BLEND_CONSTANT:
return D3DBLEND_BLENDFACTOR;
case KINC_G4_BLEND_INV_CONSTANT:
return D3DBLEND_INVBLENDFACTOR;
default:
assert(false);
return D3DBLEND_SRCALPHA;
}
}
_D3DBLENDOP convert_blend_operation(kinc_g4_blending_operation_t op) {
switch (op) {
case KINC_G4_BLENDOP_ADD:
return D3DBLENDOP_ADD;
case KINC_G4_BLENDOP_SUBTRACT:
return D3DBLENDOP_SUBTRACT;
case KINC_G4_BLENDOP_REVERSE_SUBTRACT:
return D3DBLENDOP_REVSUBTRACT;
case KINC_G4_BLENDOP_MIN:
return D3DBLENDOP_MIN;
case KINC_G4_BLENDOP_MAX:
return D3DBLENDOP_MAX;
default:
assert(false);
return D3DBLENDOP_ADD;
}
}
_D3DCMPFUNC convert(kinc_g4_compare_mode_t mode) {
switch (mode) {
default:
case KINC_G4_COMPARE_ALWAYS:
return D3DCMP_ALWAYS;
case KINC_G4_COMPARE_NEVER:
return D3DCMP_NEVER;
case KINC_G4_COMPARE_EQUAL:
return D3DCMP_EQUAL;
case KINC_G4_COMPARE_NOT_EQUAL:
return D3DCMP_NOTEQUAL;
case KINC_G4_COMPARE_LESS:
return D3DCMP_LESS;
case KINC_G4_COMPARE_LESS_EQUAL:
return D3DCMP_LESSEQUAL;
case KINC_G4_COMPARE_GREATER:
return D3DCMP_GREATER;
case KINC_G4_COMPARE_GREATER_EQUAL:
return D3DCMP_GREATEREQUAL;
}
}
}
void kinc_g4_pipeline_init(kinc_g4_pipeline_t *state) {
memset(state, 0, sizeof(kinc_g4_pipeline));
kinc_g4_internal_pipeline_set_defaults(state);
}
void kinc_g4_pipeline_destroy(kinc_g4_pipeline_t *state) {}
static int find_attribute(struct ShaderAttribute *attributes, const char *name) {
for (int i = 0; i < KINC_INTERNAL_MAX_ATTRIBUTES; ++i) {
if (attributes[i].name == 0) {
return -1;
}
if (strcmp(attributes[i].name, name) == 0) {
return i;
}
}
return -1;
}
static int find_constant(struct ShaderRegister *constants, const char *name) {
for (int i = 0; i < KINC_INTERNAL_MAX_CONSTANTS; ++i) {
if (constants[i].name == 0) {
return -1;
}
if (strcmp(constants[i].name, name) == 0) {
return i;
}
}
return -1;
}
void kinc_g4_pipeline_compile(kinc_g4_pipeline_t *state) {
int highestIndex = 0;
for (int i = 0;; ++i) {
if (state->vertex_shader->impl.attributes[i].name[0] == 0) {
break;
}
int index = state->vertex_shader->impl.attributes[i].index;
if (index > highestIndex) {
highestIndex = index;
}
}
int all = 0;
for (int stream = 0; state->input_layout[stream] != nullptr; ++stream) {
for (int index = 0; index < state->input_layout[stream]->size; ++index) {
if (state->input_layout[stream]->elements[index].data == KINC_G4_VERTEX_DATA_F32_4X4) {
all += 4;
}
else {
all += 1;
}
}
}
D3DVERTEXELEMENT9 *elements = (D3DVERTEXELEMENT9 *)_alloca(sizeof(D3DVERTEXELEMENT9) * (all + 1));
int i = 0;
for (int stream = 0; state->input_layout[stream] != nullptr; ++stream) {
int stride = 0;
for (int index = 0; index < state->input_layout[stream]->size; ++index) {
if (state->input_layout[stream]->elements[index].data != KINC_G4_VERTEX_DATA_F32_4X4) {
elements[i].Stream = stream;
elements[i].Offset = stride;
}
stride += kinc_g4_vertex_data_size(state->input_layout[stream]->elements[index].data);
switch (state->input_layout[stream]->elements[index].data) {
case KINC_G4_VERTEX_DATA_F32_1X:
elements[i].Type = D3DDECLTYPE_FLOAT1;
break;
case KINC_G4_VERTEX_DATA_F32_2X:
elements[i].Type = D3DDECLTYPE_FLOAT2;
break;
case KINC_G4_VERTEX_DATA_F32_3X:
elements[i].Type = D3DDECLTYPE_FLOAT3;
break;
case KINC_G4_VERTEX_DATA_F32_4X:
elements[i].Type = D3DDECLTYPE_FLOAT4;
break;
case KINC_G4_VERTEX_DATA_U8_4X:
elements[i].Type = D3DDECLTYPE_UBYTE4;
break;
case KINC_G4_VERTEX_DATA_U8_4X_NORMALIZED:
elements[i].Type = D3DDECLTYPE_UBYTE4N;
break;
case KINC_G4_VERTEX_DATA_I16_2X:
elements[i].Type = D3DDECLTYPE_SHORT2;
break;
case KINC_G4_VERTEX_DATA_I16_2X_NORMALIZED:
elements[i].Type = D3DDECLTYPE_SHORT2N;
break;
case KINC_G4_VERTEX_DATA_U16_2X_NORMALIZED:
elements[i].Type = D3DDECLTYPE_USHORT2N;
break;
case KINC_G4_VERTEX_DATA_I16_4X:
elements[i].Type = D3DDECLTYPE_SHORT4;
break;
case KINC_G4_VERTEX_DATA_I16_4X_NORMALIZED:
elements[i].Type = D3DDECLTYPE_SHORT4N;
break;
case KINC_G4_VERTEX_DATA_U16_4X_NORMALIZED:
elements[i].Type = D3DDECLTYPE_USHORT4N;
break;
case KINC_G4_VERTEX_DATA_I8_1X:
case KINC_G4_VERTEX_DATA_U8_1X:
case KINC_G4_VERTEX_DATA_I8_1X_NORMALIZED:
case KINC_G4_VERTEX_DATA_U8_1X_NORMALIZED:
case KINC_G4_VERTEX_DATA_I8_2X:
case KINC_G4_VERTEX_DATA_U8_2X:
case KINC_G4_VERTEX_DATA_I8_2X_NORMALIZED:
case KINC_G4_VERTEX_DATA_U8_2X_NORMALIZED:
case KINC_G4_VERTEX_DATA_I8_4X:
case KINC_G4_VERTEX_DATA_I8_4X_NORMALIZED:
case KINC_G4_VERTEX_DATA_I16_1X:
case KINC_G4_VERTEX_DATA_U16_1X:
case KINC_G4_VERTEX_DATA_I16_1X_NORMALIZED:
case KINC_G4_VERTEX_DATA_U16_1X_NORMALIZED:
case KINC_G4_VERTEX_DATA_U16_2X:
case KINC_G4_VERTEX_DATA_U16_4X:
case KINC_G4_VERTEX_DATA_I32_1X:
case KINC_G4_VERTEX_DATA_U32_1X:
case KINC_G4_VERTEX_DATA_I32_2X:
case KINC_G4_VERTEX_DATA_U32_2X:
case KINC_G4_VERTEX_DATA_I32_3X:
case KINC_G4_VERTEX_DATA_U32_3X:
case KINC_G4_VERTEX_DATA_I32_4X:
case KINC_G4_VERTEX_DATA_U32_4X:
elements[i].Type = D3DDECLTYPE_UNUSED;
assert(false);
break;
case KINC_G4_VERTEX_DATA_F32_4X4:
for (int i2 = 0; i2 < 4; ++i2) {
elements[i].Stream = stream;
elements[i].Offset = stride;
elements[i].Type = D3DDECLTYPE_FLOAT4;
elements[i].Method = D3DDECLMETHOD_DEFAULT;
elements[i].Usage = D3DDECLUSAGE_TEXCOORD;
char name[101];
strcpy(name, state->input_layout[stream]->elements[index].name);
strcat(name, "_");
size_t length = strlen(name);
_itoa(i2, &name[length], 10);
name[length + 1] = 0;
int attribute_index = find_attribute(state->vertex_shader->impl.attributes, name);
if (attribute_index < 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not find attribute %s.", name);
elements[i].UsageIndex = ++highestIndex;
}
else {
elements[i].UsageIndex = state->vertex_shader->impl.attributes[attribute_index].index;
}
++i;
}
break;
}
if (state->input_layout[stream]->elements[index].data != KINC_G4_VERTEX_DATA_F32_4X4) {
elements[i].Method = D3DDECLMETHOD_DEFAULT;
elements[i].Usage = D3DDECLUSAGE_TEXCOORD;
int attribute_index = find_attribute(state->vertex_shader->impl.attributes, state->input_layout[stream]->elements[index].name);
if (attribute_index < 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not find attribute %s.", state->input_layout[stream]->elements[index].name);
elements[i].UsageIndex = ++highestIndex;
}
else {
elements[i].UsageIndex = state->vertex_shader->impl.attributes[attribute_index].index;
}
++i;
}
}
}
elements[all].Stream = 0xff;
elements[all].Offset = 0;
elements[all].Type = D3DDECLTYPE_UNUSED;
elements[all].Method = 0;
elements[all].Usage = 0;
elements[all].UsageIndex = 0;
state->impl.vertexDecleration = nullptr;
kinc_microsoft_affirm(device->CreateVertexDeclaration(elements, &state->impl.vertexDecleration));
int constant_index = find_constant(state->vertex_shader->impl.constants, "gl_HalfPixel");
state->impl.halfPixelLocation = state->vertex_shader->impl.constants[constant_index].regindex;
}
void kinc_g4_internal_set_pipeline(kinc_g4_pipeline_t *pipeline) {
kinc_microsoft_affirm(device->SetVertexShader((IDirect3DVertexShader9 *)pipeline->vertex_shader->impl.shader));
kinc_microsoft_affirm(device->SetPixelShader((IDirect3DPixelShader9 *)pipeline->fragment_shader->impl.shader));
kinc_microsoft_affirm(device->SetVertexDeclaration(pipeline->impl.vertexDecleration));
// TODO (DK) System::screenWidth/Height are only main-window dimensions, what about other windows?
float floats[4];
floats[0] = 1.0f / kinc_width();
floats[1] = 1.0f / kinc_height();
floats[2] = floats[0];
floats[3] = floats[1];
kinc_microsoft_affirm(device->SetVertexShaderConstantF(pipeline->impl.halfPixelLocation, floats, 1));
DWORD flags = 0;
if (pipeline->color_write_mask_red[0]) {
flags |= D3DCOLORWRITEENABLE_RED;
}
if (pipeline->color_write_mask_green[0]) {
flags |= D3DCOLORWRITEENABLE_GREEN;
}
if (pipeline->color_write_mask_blue[0]) {
flags |= D3DCOLORWRITEENABLE_BLUE;
}
if (pipeline->color_write_mask_alpha[0]) {
flags |= D3DCOLORWRITEENABLE_ALPHA;
}
device->SetRenderState(D3DRS_COLORWRITEENABLE, flags);
device->SetRenderState(D3DRS_ALPHABLENDENABLE,
(pipeline->blend_source != KINC_G4_BLEND_ONE || pipeline->blend_destination != KINC_G4_BLEND_ZERO) ? TRUE : FALSE);
device->SetRenderState(D3DRS_SRCBLEND, convert_blend_factor(pipeline->blend_source));
device->SetRenderState(D3DRS_DESTBLEND, convert_blend_factor(pipeline->blend_destination));
device->SetRenderState(D3DRS_BLENDOP, convert_blend_operation(pipeline->blend_operation));
switch (pipeline->cull_mode) {
case KINC_G4_CULL_CLOCKWISE:
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
break;
case KINC_G4_CULL_COUNTER_CLOCKWISE:
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
break;
case KINC_G4_CULL_NOTHING:
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
break;
}
device->SetRenderState(D3DRS_ZENABLE, pipeline->depth_mode != KINC_G4_COMPARE_ALWAYS ? TRUE : FALSE);
device->SetRenderState(D3DRS_ZFUNC, convert(pipeline->depth_mode));
device->SetRenderState(D3DRS_ZWRITEENABLE, pipeline->depth_write ? TRUE : FALSE);
/*
case AlphaTestState:
device->SetRenderState(D3DRS_ALPHATESTENABLE, on ? TRUE : FALSE);
device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
break;
case AlphaReferenceState:
device->SetRenderState(D3DRS_ALPHAREF, (DWORD)v);
break;
*/
}
kinc_g4_constant_location_t kinc_g4_pipeline_get_constant_location(kinc_g4_pipeline_t *state, const char *name) {
kinc_g4_constant_location_t location;
int fragment_index = find_constant(state->fragment_shader->impl.constants, name);
int vertex_index = find_constant(state->vertex_shader->impl.constants, name);
if (fragment_index >= 0) {
location.impl.reg = state->fragment_shader->impl.constants[fragment_index];
location.impl.shaderType = 1;
}
else if (vertex_index >= 0) {
location.impl.reg = state->vertex_shader->impl.constants[vertex_index];
location.impl.shaderType = 0;
}
else {
location.impl.shaderType = -1;
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not find uniform %s.", name);
}
return location;
}
kinc_g4_texture_unit_t kinc_g4_pipeline_get_texture_unit(kinc_g4_pipeline_t *state, const char *name) {
int fragment_index = find_constant(state->fragment_shader->impl.constants, name);
int vertex_index = find_constant(state->vertex_shader->impl.constants, name);
kinc_g4_texture_unit_t unit;
for (int i = 0; i < KINC_G4_SHADER_TYPE_COUNT; ++i) {
unit.stages[i] = -1;
}
if (fragment_index >= 0) {
unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT] = state->fragment_shader->impl.constants[fragment_index].regindex;
}
if (vertex_index >= 0) {
unit.stages[KINC_G4_SHADER_TYPE_VERTEX] = state->vertex_shader->impl.constants[vertex_index].regindex;
}
return unit;
}