mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-12-15 13:41:33 +01:00
300 lines
8.3 KiB
C
300 lines
8.3 KiB
C
#include "vk_overlay.h"
|
|
|
|
#include "vk_buffer.h"
|
|
#include "vk_core.h"
|
|
#include "vk_common.h"
|
|
#include "vk_textures.h"
|
|
#include "vk_framectl.h"
|
|
#include "vk_renderstate.h"
|
|
#include "vk_pipeline.h"
|
|
#include "vk_descriptor.h"
|
|
|
|
#include "com_strings.h"
|
|
#include "eiface.h"
|
|
|
|
|
|
typedef struct vertex_2d_s {
|
|
float x, y;
|
|
float u, v;
|
|
color_rgba8_t color;
|
|
} vertex_2d_t;
|
|
|
|
// TODO should these be dynamic?
|
|
#define MAX_PICS 16384
|
|
#define MAX_VERTICES (MAX_PICS * 6)
|
|
#define MAX_BATCHES 256
|
|
|
|
typedef struct {
|
|
uint32_t vertex_offset, vertex_count;
|
|
int texture;
|
|
int blending_mode;
|
|
} batch_t;
|
|
|
|
static struct {
|
|
VkPipelineLayout pipeline_layout;
|
|
VkPipeline pipelines[kRenderTransAdd + 1];
|
|
|
|
vk_buffer_t pics_buffer;
|
|
r_flipping_buffer_t pics_buffer_alloc;
|
|
qboolean exhausted_this_frame;
|
|
|
|
batch_t batch[MAX_BATCHES];
|
|
int batch_count;
|
|
|
|
// TODO texture bindings?
|
|
} g2d;
|
|
|
|
static vertex_2d_t* allocQuadVerts(int blending_mode, int texnum) {
|
|
const uint32_t pics_offset = R_FlippingBuffer_Alloc(&g2d.pics_buffer_alloc, 6, 1);
|
|
vertex_2d_t* const ptr = ((vertex_2d_t*)(g2d.pics_buffer.mapped)) + pics_offset;
|
|
batch_t *batch = g2d.batch + (g2d.batch_count-1);
|
|
|
|
if (pics_offset == ALO_ALLOC_FAILED) {
|
|
if (!g2d.exhausted_this_frame) {
|
|
gEngine.Con_Printf(S_ERROR "2d: ran out of vertex memory\n");
|
|
g2d.exhausted_this_frame = true;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
if (batch->texture != texnum
|
|
|| batch->blending_mode != blending_mode
|
|
|| batch->vertex_offset > pics_offset) {
|
|
if (batch->vertex_count != 0) {
|
|
if (g2d.batch_count == MAX_BATCHES) {
|
|
if (!g2d.exhausted_this_frame) {
|
|
gEngine.Con_Printf(S_ERROR "2d: ran out of batch memory\n");
|
|
g2d.exhausted_this_frame = true;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
++g2d.batch_count;
|
|
batch++;
|
|
}
|
|
|
|
batch->vertex_offset = pics_offset;
|
|
batch->vertex_count = 0;
|
|
batch->texture = texnum;
|
|
batch->blending_mode = blending_mode;
|
|
}
|
|
|
|
batch->vertex_count += 6;
|
|
ASSERT(batch->vertex_count + batch->vertex_offset <= MAX_VERTICES);
|
|
return ptr;
|
|
}
|
|
|
|
void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum )
|
|
{
|
|
vertex_2d_t *const p = allocQuadVerts(vk_renderstate.blending_mode, texnum);
|
|
|
|
if (!p) {
|
|
/* gEngine.Con_Printf(S_ERROR "VK FIXME %s(%f, %f, %f, %f, %f, %f, %f, %f, %d(%s))\n", __FUNCTION__, */
|
|
/* x, y, w, h, s1, t1, s2, t2, texnum, findTexture(texnum)->name); */
|
|
return;
|
|
}
|
|
|
|
{
|
|
// TODO do this in shader bro
|
|
const float vw = vk_frame.width;
|
|
const float vh = vk_frame.height;
|
|
const float x1 = (x / vw)*2.f - 1.f;
|
|
const float y1 = (y / vh)*2.f - 1.f;
|
|
const float x2 = ((x + w) / vw)*2.f - 1.f;
|
|
const float y2 = ((y + h) / vh)*2.f - 1.f;
|
|
const color_rgba8_t color = vk_renderstate.tri_color;
|
|
|
|
p[0] = (vertex_2d_t){x1, y1, s1, t1, color};
|
|
p[1] = (vertex_2d_t){x1, y2, s1, t2, color};
|
|
p[2] = (vertex_2d_t){x2, y1, s2, t1, color};
|
|
p[3] = (vertex_2d_t){x2, y1, s2, t1, color};
|
|
p[4] = (vertex_2d_t){x1, y2, s1, t2, color};
|
|
p[5] = (vertex_2d_t){x2, y2, s2, t2, color};
|
|
}
|
|
}
|
|
|
|
static void drawFill( float x, float y, float w, float h, int r, int g, int b, int a, int blending_mode )
|
|
{
|
|
const color_rgba8_t prev_color = vk_renderstate.tri_color;
|
|
const int prev_blending = vk_renderstate.blending_mode;
|
|
vk_renderstate.blending_mode = blending_mode;
|
|
vk_renderstate.tri_color = (color_rgba8_t){r, g, b, a};
|
|
R_DrawStretchPic(x, y, w, h, 0, 0, 1, 1, VK_FindTexture(REF_WHITE_TEXTURE));
|
|
vk_renderstate.tri_color = prev_color;
|
|
vk_renderstate.blending_mode = prev_blending;
|
|
}
|
|
|
|
static void clearAccumulated( void ) {
|
|
R_FlippingBuffer_Flip(&g2d.pics_buffer_alloc);
|
|
|
|
g2d.batch_count = 1;
|
|
g2d.batch[0].texture = -1;
|
|
g2d.batch[0].vertex_offset = 0;
|
|
g2d.batch[0].vertex_count = 0;
|
|
g2d.exhausted_this_frame = false;
|
|
}
|
|
|
|
static qboolean createPipelines( void )
|
|
{
|
|
{
|
|
/* VkPushConstantRange push_const = { */
|
|
/* .offset = 0, */
|
|
/* .size = sizeof(AVec3f), */
|
|
/* .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, */
|
|
/* }; */
|
|
|
|
VkDescriptorSetLayout descriptor_layouts[] = {
|
|
vk_desc.one_texture_layout,
|
|
};
|
|
|
|
VkPipelineLayoutCreateInfo plci = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
.setLayoutCount = ARRAYSIZE(descriptor_layouts),
|
|
.pSetLayouts = descriptor_layouts,
|
|
/* .pushConstantRangeCount = 1, */
|
|
/* .pPushConstantRanges = &push_const, */
|
|
};
|
|
|
|
XVK_CHECK(vkCreatePipelineLayout(vk_core.device, &plci, NULL, &g2d.pipeline_layout));
|
|
}
|
|
|
|
{
|
|
const VkVertexInputAttributeDescription attribs[] = {
|
|
{.binding = 0, .location = 0, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(vertex_2d_t, x)},
|
|
{.binding = 0, .location = 1, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(vertex_2d_t, u)},
|
|
{.binding = 0, .location = 2, .format = VK_FORMAT_R8G8B8A8_UNORM, .offset = offsetof(vertex_2d_t, color)},
|
|
};
|
|
|
|
const vk_shader_stage_t shader_stages[] = {
|
|
{
|
|
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
.filename = "2d.vert.spv",
|
|
}, {
|
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
.filename = "2d.frag.spv",
|
|
}};
|
|
|
|
vk_pipeline_graphics_create_info_t pci = {
|
|
.layout = g2d.pipeline_layout,
|
|
.attribs = attribs,
|
|
.num_attribs = ARRAYSIZE(attribs),
|
|
.stages = shader_stages,
|
|
.num_stages = ARRAYSIZE(shader_stages),
|
|
.vertex_stride = sizeof(vertex_2d_t),
|
|
.depthTestEnable = VK_FALSE,
|
|
.depthWriteEnable = VK_FALSE,
|
|
.depthCompareOp = VK_COMPARE_OP_ALWAYS,
|
|
.cullMode = VK_CULL_MODE_NONE,
|
|
};
|
|
|
|
for (int i = 0; i < ARRAYSIZE(g2d.pipelines); ++i)
|
|
{
|
|
switch (i)
|
|
{
|
|
case kRenderNormal:
|
|
pci.blendEnable = VK_FALSE;
|
|
break;
|
|
|
|
case kRenderTransColor:
|
|
case kRenderTransTexture:
|
|
pci.blendEnable = VK_TRUE;
|
|
pci.colorBlendOp = VK_BLEND_OP_ADD;
|
|
pci.srcAlphaBlendFactor = pci.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
pci.dstAlphaBlendFactor = pci.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
break;
|
|
|
|
case kRenderTransAlpha:
|
|
pci.blendEnable = VK_FALSE;
|
|
// FIXME pglEnable( GL_ALPHA_TEST );
|
|
break;
|
|
|
|
case kRenderGlow:
|
|
case kRenderTransAdd:
|
|
pci.blendEnable = VK_TRUE;
|
|
pci.colorBlendOp = VK_BLEND_OP_ADD;
|
|
pci.srcAlphaBlendFactor = pci.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
pci.dstAlphaBlendFactor = pci.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
break;
|
|
}
|
|
|
|
g2d.pipelines[i] = VK_PipelineGraphicsCreate(&pci);
|
|
|
|
if (!g2d.pipelines[i])
|
|
{
|
|
// TODO complain
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
qboolean R_VkOverlay_Init( void ) {
|
|
if (!createPipelines())
|
|
return false;
|
|
|
|
// TODO this doesn't need to be host visible, could use staging too
|
|
if (!VK_BufferCreate("2d pics_buffer", &g2d.pics_buffer, sizeof(vertex_2d_t) * MAX_VERTICES,
|
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT ))
|
|
// FIXME cleanup
|
|
return false;
|
|
|
|
R_FlippingBuffer_Init(&g2d.pics_buffer_alloc, MAX_VERTICES);
|
|
|
|
return true;
|
|
}
|
|
|
|
void R_VkOverlay_Shutdown( void ) {
|
|
VK_BufferDestroy(&g2d.pics_buffer);
|
|
for (int i = 0; i < ARRAYSIZE(g2d.pipelines); ++i)
|
|
vkDestroyPipeline(vk_core.device, g2d.pipelines[i], NULL);
|
|
|
|
vkDestroyPipelineLayout(vk_core.device, g2d.pipeline_layout, NULL);
|
|
}
|
|
|
|
void R_VkOverlay_DrawAndFlip( VkCommandBuffer cmdbuf ) {
|
|
DEBUG_BEGIN(cmdbuf, "2d overlay");
|
|
|
|
{
|
|
const VkDeviceSize offset = 0;
|
|
vkCmdBindVertexBuffers(cmdbuf, 0, 1, &g2d.pics_buffer.buffer, &offset);
|
|
}
|
|
|
|
for (int i = 0; i < g2d.batch_count && g2d.batch[i].vertex_count > 0; ++i)
|
|
{
|
|
vk_texture_t *texture = findTexture(g2d.batch[i].texture);
|
|
const VkPipeline pipeline = g2d.pipelines[g2d.batch[i].blending_mode];
|
|
if (texture->vk.descriptor)
|
|
{
|
|
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
|
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g2d.pipeline_layout, 0, 1, &texture->vk.descriptor, 0, NULL);
|
|
vkCmdDraw(cmdbuf, g2d.batch[i].vertex_count, 1, g2d.batch[i].vertex_offset, 0);
|
|
} // FIXME else what?
|
|
}
|
|
|
|
DEBUG_END(cmdbuf);
|
|
|
|
clearAccumulated();
|
|
}
|
|
|
|
void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty )
|
|
{
|
|
PRINT_NOT_IMPLEMENTED();
|
|
}
|
|
|
|
void R_DrawTileClear( int texnum, int x, int y, int w, int h )
|
|
{
|
|
PRINT_NOT_IMPLEMENTED_ARGS("%s", findTexture(texnum)->name );
|
|
}
|
|
|
|
void CL_FillRGBA( float x, float y, float w, float h, int r, int g, int b, int a )
|
|
{
|
|
drawFill(x, y, w, h, r, g, b, a, kRenderTransAdd);
|
|
}
|
|
|
|
void CL_FillRGBABlend( float x, float y, float w, float h, int r, int g, int b, int a )
|
|
{
|
|
drawFill(x, y, w, h, r, g, b, a, kRenderTransColor);
|
|
}
|