vk: improve traditional blending universally

it is now almost on par with the gl renderer
This commit is contained in:
Ivan 'provod' Avdeev 2023-02-25 12:09:20 -08:00
parent ce27bdb1b1
commit 9f72a804e0
8 changed files with 120 additions and 82 deletions

View File

@ -390,8 +390,8 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f
.emissive = { color[0], color[1], color[2] },
};
VK_RenderModelDynamicBegin( render_mode, color, "beam" /* TODO its name */ );
vk_render_type_e render_type = render_mode == kRenderNormal ? kVkRenderTypeSolid : kVkRenderType_A_1_R;
VK_RenderModelDynamicBegin( render_type, color, "beam" /* TODO its name */ );
VK_RenderModelDynamicAddGeometry( &geometry );
VK_RenderModelDynamicCommit();
}

View File

@ -234,6 +234,20 @@ static void EmitWaterPolys( const cl_entity_t *ent, const msurface_t *warp, qboo
// FIXME VK GL_SetupFogColorForSurfaces();
}
static vk_render_type_e brushRenderModeToRenderType( int render_mode ) {
switch (render_mode) {
case kRenderNormal: return kVkRenderTypeSolid;
case kRenderTransColor: return kVkRenderType_A_1mA_RW;
case kRenderTransTexture: return kVkRenderType_A_1mA_R;
case kRenderGlow: return kVkRenderType_A_1mA_R;
case kRenderTransAlpha: return kVkRenderType_AT;
case kRenderTransAdd: return kVkRenderType_A_1_R;
default: ASSERT(!"Unxpected render_mode");
}
return kVkRenderTypeSolid;
}
static void brushDrawWaterSurfaces( const cl_entity_t *ent, const vec4_t color )
{
const model_t *model = ent->model;
@ -258,7 +272,7 @@ static void brushDrawWaterSurfaces( const cl_entity_t *ent, const vec4_t color )
// if( R_CullBox( mins, maxs ))
// return;
VK_RenderModelDynamicBegin( ent->curstate.rendermode, color, "%s water", model->name );
VK_RenderModelDynamicBegin( brushRenderModeToRenderType(ent->curstate.rendermode), color, "%s water", model->name );
// Iterate through all surfaces, find *TURB*
for( int i = 0; i < model->nummodelsurfaces; i++ )
@ -389,18 +403,7 @@ void VK_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, co
}
}
if (render_mode == kRenderTransColor) {
Vector4Set(bmodel->render_model.color,
ent->curstate.rendercolor.r / 255.f,
ent->curstate.rendercolor.g / 255.f,
ent->curstate.rendercolor.b / 255.f,
blend);
} else {
// Other render modes are not affected by entity current state color
Vector4Set(bmodel->render_model.color, 1, 1, 1, blend);
}
bmodel->render_model.render_mode = render_mode;
bmodel->render_model.render_type = brushRenderModeToRenderType(render_mode);
VK_RenderModelDraw(ent, &bmodel->render_model);
}
@ -700,7 +703,7 @@ qboolean VK_BrushModelLoad( model_t *mod, qboolean map )
vk_brush_model_t *bmodel = Mem_Calloc(vk_core.pool, model_size);
mod->cache.data = bmodel;
Q_strncpy(bmodel->render_model.debug_name, mod->name, sizeof(bmodel->render_model.debug_name));
bmodel->render_model.render_mode = kRenderNormal;
bmodel->render_model.render_type = kVkRenderTypeSolid;
bmodel->render_model.static_map = map;
bmodel->num_water_surfaces = sizes.water_surfaces;

View File

@ -7,6 +7,7 @@
#include "crtlib.h"
#define ASSERT(x) if(!( x )) gEngine.Host_Error( "assert %s failed at %s:%d\n", #x, __FILE__, __LINE__ )
// TODO ASSERTF(x, fmt, ...)
#define Mem_Malloc( pool, size ) gEngine._Mem_Alloc( pool, size, false, __FILE__, __LINE__ )
#define Mem_Calloc( pool, size ) gEngine._Mem_Alloc( pool, size, true, __FILE__, __LINE__ )

View File

@ -444,31 +444,30 @@ void VK_RayFrameAddModel( vk_ray_model_t *model, const vk_render_model_t *render
memcpy(draw_model->transform_row, *transform_row, sizeof(draw_model->transform_row));
}
switch (render_model->render_mode) {
case kRenderNormal:
switch (render_model->render_type) {
case kVkRenderTypeSolid:
draw_model->material_mode = MaterialMode_Opaque;
break;
// C = (1 - alpha) * DST + alpha * SRC (TODO is this right?)
case kRenderTransColor:
case kRenderTransTexture:
HACK_reflective = true;
draw_model->material_mode = MaterialMode_Refractive;
break;
// Additive blending: C = SRC * alpha + DST
case kRenderGlow:
case kRenderTransAdd:
case kVkRenderType_A_1mA_RW: // blend: scr*a + dst*(1-a), depth: RW
case kVkRenderType_A_1mA_R: // blend: scr*a + dst*(1-a), depth test
// FIXME proper trasnlucency
//HACK_reflective = true;
//draw_model->material_mode = MaterialMode_Refractive;
draw_model->material_mode = MaterialMode_Additive;
break;
// Alpha test (TODO additive? mixing?)
case kRenderTransAlpha:
case kVkRenderType_A_1: // blend: scr*a + dst, no depth test or write
case kVkRenderType_A_1_R: // blend: scr*a + dst, depth test
case kVkRenderType_1_1_R: // blend: scr + dst, depth test
draw_model->material_mode = MaterialMode_Additive;
break;
case kVkRenderType_AT: // no blend, depth RW, alpha test
draw_model->material_mode = MaterialMode_Opaque_AlphaTest;
break;
default:
gEngine.Host_Error("Unexpected render mode %d\n", render_model->render_mode);
gEngine.Host_Error("Unexpected render type %d\n", render_model->render_type);
}
// TODO optimize:

View File

@ -30,7 +30,7 @@ typedef struct {
static struct {
VkPipelineLayout pipeline_layout;
VkPipeline pipelines[kRenderTransAdd + 1];
VkPipeline pipelines[kVkRenderType_COUNT];
vk_buffer_t uniform_buffer;
uint32_t ubo_align;
@ -121,20 +121,20 @@ static qboolean createPipelines( void )
.cullMode = VK_CULL_MODE_FRONT_BIT,
};
for (int i = 0; i < ARRAYSIZE(g_render.pipelines); ++i)
for (int i = 0; i < kVkRenderType_COUNT; ++i)
{
const char *name = "UNDEFINED";
switch (i)
{
case kRenderNormal:
case kVkRenderTypeSolid:
spec_data.alpha_test_threshold = 0.f;
ci.blendEnable = VK_FALSE;
ci.depthWriteEnable = VK_TRUE;
ci.depthTestEnable = VK_TRUE;
name = "kRenderNormal";
name = "kVkRenderTypeSolid";
break;
case kRenderTransColor:
case kVkRenderType_A_1mA_RW:
spec_data.alpha_test_threshold = 0.f;
ci.depthWriteEnable = VK_TRUE;
ci.depthTestEnable = VK_TRUE;
@ -142,10 +142,10 @@ static qboolean createPipelines( void )
ci.colorBlendOp = VK_BLEND_OP_ADD;
ci.srcAlphaBlendFactor = ci.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
ci.dstAlphaBlendFactor = ci.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
name = "kRenderTransColor";
name = "kVkRenderType_A_1mA_RW";
break;
case kRenderTransTexture:
case kVkRenderType_A_1mA_R:
spec_data.alpha_test_threshold = 0.f;
ci.depthWriteEnable = VK_FALSE;
ci.depthTestEnable = VK_TRUE;
@ -153,10 +153,10 @@ static qboolean createPipelines( void )
ci.colorBlendOp = VK_BLEND_OP_ADD;
ci.srcAlphaBlendFactor = ci.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
ci.dstAlphaBlendFactor = ci.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
name = "kRenderTransTexture";
name = "kVkRenderType_A_1mA_R";
break;
case kRenderGlow:
case kVkRenderType_A_1:
spec_data.alpha_test_threshold = 0.f;
ci.depthWriteEnable = VK_FALSE;
ci.depthTestEnable = VK_FALSE; // Fake bloom, should be over geometry too
@ -164,19 +164,10 @@ static qboolean createPipelines( void )
ci.colorBlendOp = VK_BLEND_OP_ADD;
ci.srcAlphaBlendFactor = ci.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
ci.dstAlphaBlendFactor = ci.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
name = "kRenderGlow";
name = "kVkRenderType_A_1";
break;
case kRenderTransAlpha:
// FIXME sprites are different: they don't do alpha test, but do blending
spec_data.alpha_test_threshold = .25f;
ci.depthWriteEnable = VK_TRUE;
ci.depthTestEnable = VK_TRUE;
ci.blendEnable = VK_FALSE;
name = "kRenderTransAlpha(test)";
break;
case kRenderTransAdd:
case kVkRenderType_A_1_R:
spec_data.alpha_test_threshold = 0.f;
ci.depthWriteEnable = VK_FALSE;
ci.depthTestEnable = VK_TRUE;
@ -184,7 +175,26 @@ static qboolean createPipelines( void )
ci.colorBlendOp = VK_BLEND_OP_ADD;
ci.srcAlphaBlendFactor = ci.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
ci.dstAlphaBlendFactor = ci.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
name = "kRenderTransAdd";
name = "kVkRenderType_A_1_R";
break;
case kVkRenderType_AT:
spec_data.alpha_test_threshold = .25f;
ci.depthWriteEnable = VK_TRUE;
ci.depthTestEnable = VK_TRUE;
ci.blendEnable = VK_FALSE;
name = "kVkRenderType_AT";
break;
case kVkRenderType_1_1_R:
spec_data.alpha_test_threshold = 0.f;
ci.depthWriteEnable = VK_FALSE;
ci.depthTestEnable = VK_TRUE;
ci.blendEnable = VK_TRUE;
ci.colorBlendOp = VK_BLEND_OP_ADD;
ci.srcAlphaBlendFactor = ci.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
ci.dstAlphaBlendFactor = ci.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
name = "kVkRenderType_1_1_R";
break;
default:
@ -228,7 +238,7 @@ typedef struct {
typedef struct render_draw_s {
int lightmap, texture;
int render_mode;
int pipeline_index;
uint32_t element_count;
uint32_t index_offset, vertex_offset;
/* TODO this should be a separate thing? */ struct { float r, g, b; } emissive;
@ -443,8 +453,8 @@ static void drawCmdPushDraw( const render_draw_t *draw )
{
draw_command_t *draw_command;
ASSERT(draw->render_mode >= 0);
ASSERT(draw->render_mode < ARRAYSIZE(g_render.pipelines));
ASSERT(draw->pipeline_index >= 0);
ASSERT(draw->pipeline_index < ARRAYSIZE(g_render.pipelines));
ASSERT(draw->lightmap >= 0);
ASSERT(draw->texture >= 0);
@ -581,8 +591,8 @@ void VK_RenderEnd( VkCommandBuffer cmdbuf )
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 0, 1, vk_desc.ubo_sets, 1, &ubo_offset);
}
if (pipeline != draw->draw.draw.render_mode) {
pipeline = draw->draw.draw.render_mode;
if (pipeline != draw->draw.draw.pipeline_index) {
pipeline = draw->draw.draw.pipeline_index;
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipelines[pipeline]);
}
@ -710,7 +720,7 @@ void VK_RenderModelDraw( const cl_entity_t *ent, vk_render_model_t* model ) {
render_draw_t draw = {
.lightmap = lightmap,
.texture = current_texture,
.render_mode = model->render_mode,
.pipeline_index = model->render_type,
.element_count = element_count,
.vertex_offset = vertex_offset,
.index_offset = index_offset,
@ -734,7 +744,7 @@ void VK_RenderModelDraw( const cl_entity_t *ent, vk_render_model_t* model ) {
const render_draw_t draw = {
.lightmap = lightmap,
.texture = current_texture,
.render_mode = model->render_mode,
.pipeline_index = model->render_type,
.element_count = element_count,
.vertex_offset = vertex_offset,
.index_offset = index_offset,
@ -753,7 +763,7 @@ static struct {
vk_render_geometry_t geometries[MAX_DYNAMIC_GEOMETRY];
} g_dynamic_model = {0};
void VK_RenderModelDynamicBegin( int render_mode, const vec4_t color, const char *debug_name_fmt, ... ) {
void VK_RenderModelDynamicBegin( vk_render_type_e render_type, const vec4_t color, const char *debug_name_fmt, ... ) {
va_list argptr;
va_start( argptr, debug_name_fmt );
vsnprintf(g_dynamic_model.model.debug_name, sizeof(g_dynamic_model.model.debug_name), debug_name_fmt, argptr );
@ -762,7 +772,7 @@ void VK_RenderModelDynamicBegin( int render_mode, const vec4_t color, const char
ASSERT(!g_dynamic_model.model.geometries);
g_dynamic_model.model.geometries = g_dynamic_model.geometries;
g_dynamic_model.model.num_geometries = 0;
g_dynamic_model.model.render_mode = render_mode;
g_dynamic_model.model.render_type = render_type;
g_dynamic_model.model.lightmap = 0;
Vector4Copy(color, g_dynamic_model.model.color);
}

View File

@ -62,12 +62,22 @@ struct vk_ray_model_s;
#define MAX_MODEL_NAME_LENGTH 64
typedef enum {
kVkRenderTypeSolid, // no blending, depth RW
kVkRenderType_A_1mA_RW, // blend: src*a + dst*(1-a), depth: RW
kVkRenderType_A_1mA_R, // blend: src*a + dst*(1-a), depth test
kVkRenderType_A_1, // blend: src*a + dst, no depth test or write
kVkRenderType_A_1_R, // blend: src*a + dst, depth test
kVkRenderType_AT, // no blend, depth RW, alpha test
kVkRenderType_1_1_R, // blend: src + dst, depth test
kVkRenderType_COUNT
} vk_render_type_e;
struct rt_light_add_polygon_s;
typedef struct vk_render_model_s {
char debug_name[MAX_MODEL_NAME_LENGTH];
// FIXME: brushes, sprites, studio models, etc all treat render_mode differently
int render_mode;
vk_render_type_e render_type;
vec4_t color;
int lightmap; // <= 0 if no lightmap
@ -93,7 +103,7 @@ qboolean VK_RenderModelInit( vk_render_model_t* model );
void VK_RenderModelDestroy( vk_render_model_t* model );
void VK_RenderModelDraw( const cl_entity_t *ent, vk_render_model_t* model );
void VK_RenderModelDynamicBegin( int render_mode, const vec4_t color, const char *debug_name_fmt, ... );
void VK_RenderModelDynamicBegin( vk_render_type_e render_type, const vec4_t color, const char *debug_name_fmt, ... );
void VK_RenderModelDynamicAddGeometry( const vk_render_geometry_t *geom );
void VK_RenderModelDynamicCommit( void );

View File

@ -643,6 +643,20 @@ static qboolean spriteIsOccluded( const cl_entity_t *e, vec3_t origin, float *ps
return false;
}
static vk_render_type_e spriteRenderModeToRenderType( int render_mode ) {
switch (render_mode) {
case kRenderNormal: return kVkRenderTypeSolid;
case kRenderTransColor: return kVkRenderType_A_1mA_RW;
case kRenderTransTexture: return kVkRenderType_A_1mA_RW;
case kRenderGlow: return kVkRenderType_A_1;
case kRenderTransAlpha: return kVkRenderType_A_1mA_R;
case kRenderTransAdd: return kVkRenderType_A_1_R;
default: ASSERT(!"Unxpected render_mode");
}
return kVkRenderTypeSolid;
}
static void R_DrawSpriteQuad( const char *debug_name, mspriteframe_t *frame, vec3_t org, vec3_t v_right, vec3_t v_up, float scale, int texture, int render_mode, const vec4_t color ) {
r_geometry_buffer_lock_t buffer;
if (!R_GeometryBufferAllocAndLock( &buffer, 4, 6, LifetimeSingleFrame )) {
@ -719,7 +733,7 @@ static void R_DrawSpriteQuad( const char *debug_name, mspriteframe_t *frame, vec
.emissive = {color[0], color[1], color[2]},
};
VK_RenderModelDynamicBegin( render_mode, color, "%s", debug_name );
VK_RenderModelDynamicBegin( spriteRenderModeToRenderType(render_mode), color, "%s", debug_name );
VK_RenderModelDynamicAddGeometry( &geometry );
VK_RenderModelDynamicCommit();
}

View File

@ -2066,6 +2066,20 @@ _inline void R_StudioDrawChromeMesh( short *ptricmds, vec3_t *pstudionorms, floa
}
*/
static vk_render_type_e studioRenderModeToRenderType( int render_mode ) {
switch (render_mode) {
case kRenderNormal: return kVkRenderTypeSolid;
case kRenderTransColor: return kVkRenderType_A_1mA_RW;
case kRenderTransTexture: return kVkRenderType_A_1mA_RW;
case kRenderGlow: return kVkRenderType_A_1mA_RW;
case kRenderTransAlpha: return kVkRenderType_A_1mA_RW;
case kRenderTransAdd: return kVkRenderType_1_1_R;
default: ASSERT(!"Unxpected render_mode");
}
return kVkRenderTypeSolid;
}
static void R_StudioDrawPoints( void )
{
int i, j, k, m_skinnum;
@ -2082,24 +2096,11 @@ static void R_StudioDrawPoints( void )
if( !m_pStudioHeader ) return;
vec4_t color = {1, 1, 1, 1};
switch (g_studio.rendermode2) {
case kRenderNormal:
break;
case kRenderTransColor:
// TODO pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
break;
case kRenderTransAdd:
// TODO pglBlendFunc( GL_ONE, GL_ONE );
// TODO pglDepthMask( GL_FALSE );
Vector4Set(color, g_studio.blend, g_studio.blend, g_studio.blend, 1.f);
break;
default:
// TODO pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
Vector4Set(color, 1.f, 1.f, 1.f, g_studio.blend);
break;
vec4_t color = {1, 1, 1, g_studio.blend};
if (g_studio.rendermode2 == kRenderTransAdd) {
Vector4Set(color, g_studio.blend, g_studio.blend, g_studio.blend, 1.f);
}
VK_RenderModelDynamicBegin( RI.currententity->curstate.rendermode, color, "%s", m_pSubModel->name );
VK_RenderModelDynamicBegin( studioRenderModeToRenderType(RI.currententity->curstate.rendermode), color, "%s", m_pSubModel->name );
g_studio.numverts = g_studio.numelems = 0;