Fixed r_fastsky and preparation to fix the rest of sky rendering.
This commit is contained in:
parent
a5d410fd9f
commit
ab32f499f8
|
|
@ -429,23 +429,24 @@ void RB_BeginDrawingView (void) {
|
|||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
float color[4] = { 0.8f, 0.7f, 0.4f, 1.0f }; // FIXME: get color of sky
|
||||
float sky_color[4] = { 0.8f, 0.7f, 0.4f, 1.0f }; // FIXME: get color of sky
|
||||
#else
|
||||
float color[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; // FIXME: get color of sky
|
||||
float sky_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; // FIXME: get color of sky
|
||||
#endif
|
||||
|
||||
bool clear_color = r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL );
|
||||
if ( clear_color )
|
||||
bool fast_sky = r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL );
|
||||
if ( fast_sky )
|
||||
{
|
||||
clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used
|
||||
qglClearColor(color[0], color[1], color[2], color[3]);
|
||||
qglClearColor(sky_color[0], sky_color[1], sky_color[2], sky_color[3]);
|
||||
}
|
||||
|
||||
qglClear( clearBits );
|
||||
|
||||
// VULKAN
|
||||
if (glState.vk_dirty_attachments) {
|
||||
if (glState.vk_dirty_attachments || fast_sky) {
|
||||
VkClearAttachment attachments[2];
|
||||
uint32_t attachment_count = clear_color ? 2 : 1;
|
||||
uint32_t attachment_count = fast_sky ? 2 : 1;
|
||||
|
||||
attachments[0].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
attachments[0].clearValue.depthStencil.depth = 1.0f;
|
||||
|
|
@ -454,18 +455,33 @@ void RB_BeginDrawingView (void) {
|
|||
attachments[0].aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
attachments[0].clearValue.depthStencil.stencil = 0;
|
||||
}
|
||||
if (clear_color) {
|
||||
if (fast_sky) {
|
||||
attachments[1].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
attachments[1].colorAttachment = 0;
|
||||
attachments[1].clearValue.color = { color[0], color[1], color[2], color[3] };
|
||||
attachments[1].clearValue.color = { sky_color[0], sky_color[1], sky_color[2], sky_color[3] };
|
||||
}
|
||||
|
||||
VkClearRect clear_rect;
|
||||
clear_rect.rect = vk_get_viewport_rect();
|
||||
clear_rect.baseArrayLayer = 0;
|
||||
clear_rect.layerCount = 1;
|
||||
VkClearRect clear_rect[2];
|
||||
clear_rect[0].rect = vk_get_viewport_rect();
|
||||
clear_rect[0].baseArrayLayer = 0;
|
||||
clear_rect[0].layerCount = 1;
|
||||
int rect_count = 1;
|
||||
|
||||
vkCmdClearAttachments(vk.command_buffer, attachment_count, attachments, 1, &clear_rect);
|
||||
// Split viewport rectangle into two non-overlapping rectangles.
|
||||
// It's a HACK to prevent Vulkan validation layer's performance warning:
|
||||
// "vkCmdClearAttachments() issued on command buffer object XXX prior to any Draw Cmds.
|
||||
// It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw."
|
||||
//
|
||||
if (fast_sky) {
|
||||
uint32_t h = clear_rect[0].rect.extent.height / 2;
|
||||
clear_rect[0].rect.extent.height = h;
|
||||
|
||||
clear_rect[1] = clear_rect[0];
|
||||
clear_rect[1].rect.offset.y = h;
|
||||
rect_count = 2;
|
||||
}
|
||||
|
||||
vkCmdClearAttachments(vk.command_buffer, attachment_count, attachments, rect_count, clear_rect);
|
||||
}
|
||||
|
||||
if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )
|
||||
|
|
@ -922,34 +938,8 @@ const void *RB_DrawBuffer( const void *data ) {
|
|||
|
||||
qglDrawBuffer( cmd->buffer );
|
||||
|
||||
// clear screen for debugging
|
||||
if ( r_clear->integer ) {
|
||||
qglClearColor( 1, 0, 0.5, 1 );
|
||||
qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
}
|
||||
|
||||
// VULKAN
|
||||
VkResult result = vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, vulkan_demo->image_acquired, VK_NULL_HANDLE, &vulkan_demo->swapchain_image_index);
|
||||
check_vk_result(result, "vkAcquireNextImageKHR");
|
||||
|
||||
result = vkWaitForFences(vk.device, 1, &vulkan_demo->rendering_finished_fence, VK_FALSE, 1e9);
|
||||
check_vk_result(result, "vkWaitForFences");
|
||||
result = vkResetFences(vk.device, 1, &vulkan_demo->rendering_finished_fence);
|
||||
check_vk_result(result, "vkResetFences");
|
||||
|
||||
VkCommandBufferBeginInfo begin_info;
|
||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
begin_info.pNext = nullptr;
|
||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
begin_info.pInheritanceInfo = nullptr;
|
||||
|
||||
extern FILE* vk_log_file;
|
||||
if (r_logFile->integer)
|
||||
fprintf(vk_log_file, "begin\n");
|
||||
|
||||
result = vkBeginCommandBuffer(vk.command_buffer, &begin_info);
|
||||
check_vk_result(result, "vkBeginCommandBuffer");
|
||||
vulkan_demo->begin_frame();
|
||||
vk_begin_frame();
|
||||
|
||||
return (const void *)(cmd + 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ cvar_t *r_picmip;
|
|||
cvar_t *r_showtris;
|
||||
cvar_t *r_showsky;
|
||||
cvar_t *r_shownormals;
|
||||
cvar_t *r_clear;
|
||||
cvar_t *r_swapInterval;
|
||||
cvar_t *r_textureMode;
|
||||
cvar_t *r_offsetFactor;
|
||||
|
|
@ -899,7 +898,6 @@ void R_Register( void )
|
|||
r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT);
|
||||
r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT);
|
||||
r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT);
|
||||
r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT);
|
||||
r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT );
|
||||
r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT );
|
||||
r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT );
|
||||
|
|
|
|||
|
|
@ -1045,7 +1045,6 @@ extern cvar_t *r_logFile; // number of frames to emit GL logs
|
|||
extern cvar_t *r_showtris; // enables wireframe rendering of the world
|
||||
extern cvar_t *r_showsky; // forces sky in front of all surfaces
|
||||
extern cvar_t *r_shownormals; // draws wireframe normals
|
||||
extern cvar_t *r_clear; // force screen clear every frame
|
||||
|
||||
extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection
|
||||
extern cvar_t *r_flares; // light flares
|
||||
|
|
|
|||
|
|
@ -841,7 +841,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
|
|||
}
|
||||
|
||||
// VULKAN
|
||||
vk_bind_stage_specific_resources(pStage->vk_pipeline, multitexture);
|
||||
vk_bind_stage_specific_resources(pStage->vk_pipeline, multitexture, input->shader->isSky == qtrue);
|
||||
vkCmdDrawIndexed(vk.command_buffer, tess.numIndexes, 1, 0, 0, 0);
|
||||
glState.vk_dirty_attachments = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -504,43 +504,14 @@ static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean ad
|
|||
}
|
||||
}
|
||||
|
||||
static void FillCloudBox( const shader_t *shader, int stage )
|
||||
static void FillCloudBox( int stage )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i =0; i < 6; i++ )
|
||||
for ( int i = 0; i < 5; i++ )
|
||||
{
|
||||
int sky_mins_subd[2], sky_maxs_subd[2];
|
||||
int s, t;
|
||||
float MIN_T;
|
||||
|
||||
if ( 1 ) // FIXME? shader->sky.fullClouds )
|
||||
{
|
||||
MIN_T = -HALF_SKY_SUBDIVISIONS;
|
||||
|
||||
// still don't want to draw the bottom, even if fullClouds
|
||||
if ( i == 5 )
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( i )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
MIN_T = -1;
|
||||
break;
|
||||
case 5:
|
||||
// don't draw clouds beneath you
|
||||
continue;
|
||||
case 4: // top
|
||||
default:
|
||||
MIN_T = -HALF_SKY_SUBDIVISIONS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
float MIN_T = -HALF_SKY_SUBDIVISIONS;
|
||||
|
||||
sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
|
||||
sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
|
||||
|
|
@ -625,7 +596,7 @@ void R_BuildCloudData( shaderCommands_t *input )
|
|||
if ( !tess.xstages[i] ) {
|
||||
break;
|
||||
}
|
||||
FillCloudBox( input->shader, i );
|
||||
FillCloudBox( i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -265,29 +265,27 @@ static VkSwapchainKHR create_swapchain(VkPhysicalDevice physical_device, VkDevic
|
|||
return swapchain;
|
||||
}
|
||||
|
||||
// TODO: pass device, color format, depth format. Physical device is not needed.
|
||||
static VkRenderPass create_render_pass(VkPhysicalDevice physical_device, VkDevice device) {
|
||||
VkAttachmentDescription color_attachment;
|
||||
color_attachment.flags = 0;
|
||||
color_attachment.format = vk.surface_format.format;
|
||||
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
static VkRenderPass create_render_pass(VkDevice device, VkFormat color_format, VkFormat depth_format) {
|
||||
VkAttachmentDescription attachments[2];
|
||||
attachments[0].flags = 0;
|
||||
attachments[0].format = color_format;
|
||||
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
VkAttachmentDescription depth_attachment;
|
||||
depth_attachment.flags = 0;
|
||||
depth_attachment.format = find_depth_format(physical_device);
|
||||
depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
depth_attachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].flags = 0;
|
||||
attachments[1].format = depth_format;
|
||||
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkAttachmentReference color_attachment_ref;
|
||||
color_attachment_ref.attachment = 0;
|
||||
|
|
@ -309,13 +307,12 @@ static VkRenderPass create_render_pass(VkPhysicalDevice physical_device, VkDevic
|
|||
subpass.preserveAttachmentCount = 0;
|
||||
subpass.pPreserveAttachments = nullptr;
|
||||
|
||||
std::array<VkAttachmentDescription, 2> attachments{color_attachment, depth_attachment};
|
||||
VkRenderPassCreateInfo desc;
|
||||
desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
desc.pNext = nullptr;
|
||||
desc.flags = 0;
|
||||
desc.attachmentCount = static_cast<uint32_t>(attachments.size());
|
||||
desc.pAttachments = attachments.data();
|
||||
desc.attachmentCount = sizeof(attachments) / sizeof(attachments[0]);
|
||||
desc.pAttachments = attachments;
|
||||
desc.subpassCount = 1;
|
||||
desc.pSubpasses = &subpass;
|
||||
desc.dependencyCount = 0;
|
||||
|
|
@ -408,7 +405,9 @@ bool vk_initialize(HWND hwnd) {
|
|||
});
|
||||
}
|
||||
|
||||
g.render_pass = create_render_pass(g.physical_device, g.device);
|
||||
VkFormat depth_format = find_depth_format(vk.physical_device);
|
||||
|
||||
vk.render_pass = create_render_pass(vk.device, vk.surface_format.format, depth_format);
|
||||
|
||||
{
|
||||
std::array<VkImageView, 2> attachments = {VK_NULL_HANDLE, vk.depth_image_view};
|
||||
|
|
@ -1173,7 +1172,7 @@ void vk_bind_resources_shared_between_stages(int num_passes) {
|
|||
vkCmdPushConstants(vk.command_buffer, vk.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 64, mvp);
|
||||
}
|
||||
|
||||
void vk_bind_stage_specific_resources(VkPipeline pipeline, bool multitexture) {
|
||||
void vk_bind_stage_specific_resources(VkPipeline pipeline, bool multitexture, bool sky) {
|
||||
//
|
||||
// Specify color/st for each draw call since they are regenerated for each Q3 shader's stage.
|
||||
// xyz are specified only once for all stages.
|
||||
|
|
@ -1243,9 +1242,65 @@ void vk_bind_stage_specific_resources(VkPipeline pipeline, bool multitexture) {
|
|||
viewport.maxDepth = 0.3f;
|
||||
}
|
||||
|
||||
if (sky) {
|
||||
if (r_showsky->integer) {
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 0.0f;
|
||||
} else {
|
||||
viewport.minDepth = 1.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
vkCmdSetViewport(vk.command_buffer, 0, 1, &viewport);
|
||||
|
||||
if (tess.shader->polygonOffset) {
|
||||
vkCmdSetDepthBias(vk.command_buffer, r_offsetUnits->value, 0.0f, r_offsetFactor->value);
|
||||
}
|
||||
}
|
||||
|
||||
void vk_begin_frame() {
|
||||
extern FILE* vk_log_file;
|
||||
if (r_logFile->integer)
|
||||
fprintf(vk_log_file, "vk_begin_frame\n");
|
||||
|
||||
VkResult result = vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, vulkan_demo->image_acquired, VK_NULL_HANDLE, &vulkan_demo->swapchain_image_index);
|
||||
check_vk_result(result, "vkAcquireNextImageKHR");
|
||||
|
||||
result = vkWaitForFences(vk.device, 1, &vulkan_demo->rendering_finished_fence, VK_FALSE, 1e9);
|
||||
check_vk_result(result, "vkWaitForFences");
|
||||
result = vkResetFences(vk.device, 1, &vulkan_demo->rendering_finished_fence);
|
||||
check_vk_result(result, "vkResetFences");
|
||||
|
||||
VkCommandBufferBeginInfo begin_info;
|
||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
begin_info.pNext = nullptr;
|
||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
begin_info.pInheritanceInfo = nullptr;
|
||||
|
||||
result = vkBeginCommandBuffer(vk.command_buffer, &begin_info);
|
||||
check_vk_result(result, "vkBeginCommandBuffer");
|
||||
|
||||
VkClearValue clear_values[2];
|
||||
/// ignore clear_values[0] which corresponds to color attachment
|
||||
clear_values[1].depthStencil.depth = 1.0;
|
||||
clear_values[1].depthStencil.stencil = 0;
|
||||
|
||||
VkRenderPassBeginInfo render_pass_begin_info;
|
||||
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
render_pass_begin_info.pNext = nullptr;
|
||||
render_pass_begin_info.renderPass = vk.render_pass;
|
||||
render_pass_begin_info.framebuffer = vk.framebuffers[vulkan_demo->swapchain_image_index];
|
||||
render_pass_begin_info.renderArea.offset = { 0, 0 };
|
||||
render_pass_begin_info.renderArea.extent = { (uint32_t)glConfig.vidWidth, (uint32_t)glConfig.vidHeight };
|
||||
render_pass_begin_info.clearValueCount = 2;
|
||||
render_pass_begin_info.pClearValues = clear_values;
|
||||
|
||||
vkCmdBeginRenderPass(vk.command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vk.xyz_elements = 0;
|
||||
vk.color_st_elements = 0;
|
||||
vk.index_buffer_offset = 0;
|
||||
|
||||
glState.vk_dirty_attachments = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ VkRect2D vk_get_viewport_rect();
|
|||
void vk_get_mvp_transform(float mvp[16]);
|
||||
|
||||
void vk_bind_resources_shared_between_stages(int num_passes);
|
||||
void vk_bind_stage_specific_resources(VkPipeline pipeline, bool multitexture);
|
||||
void vk_bind_stage_specific_resources(VkPipeline pipeline, bool multitexture, bool sky);
|
||||
|
||||
void vk_begin_frame();
|
||||
|
||||
struct Vk_Staging_Buffer {
|
||||
VkBuffer handle = VK_NULL_HANDLE;
|
||||
|
|
|
|||
|
|
@ -107,30 +107,3 @@ void Vulkan_Demo::create_texture_sampler() {
|
|||
|
||||
texture_image_sampler = get_resource_manager()->create_sampler(desc);
|
||||
}
|
||||
|
||||
void Vulkan_Demo::begin_frame() {
|
||||
if (r_logFile->integer)
|
||||
fprintf(vk_log_file, "begin_frame\n");
|
||||
|
||||
std::array<VkClearValue, 2> clear_values;
|
||||
clear_values[0].color = {1.0f, 0.3f, 0.3f, 0.0f};
|
||||
clear_values[1].depthStencil = {1.0, 0};
|
||||
|
||||
VkRenderPassBeginInfo render_pass_begin_info;
|
||||
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
render_pass_begin_info.pNext = nullptr;
|
||||
render_pass_begin_info.renderPass = vk.render_pass;
|
||||
render_pass_begin_info.framebuffer = vk.framebuffers[swapchain_image_index];
|
||||
render_pass_begin_info.renderArea.offset = {0, 0};
|
||||
render_pass_begin_info.renderArea.extent = {(uint32_t)window_width, (uint32_t)window_height};
|
||||
render_pass_begin_info.clearValueCount = static_cast<uint32_t>(clear_values.size());
|
||||
render_pass_begin_info.pClearValues = clear_values.data();
|
||||
|
||||
vkCmdBeginRenderPass(vk.command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vk.xyz_elements = 0;
|
||||
vk.color_st_elements = 0;
|
||||
vk.index_buffer_offset = 0;
|
||||
|
||||
glState.vk_dirty_attachments = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ class Vulkan_Demo {
|
|||
public:
|
||||
Vulkan_Demo(int window_width, int window_height);
|
||||
|
||||
void begin_frame();
|
||||
|
||||
public:
|
||||
VkImage create_texture(const uint8_t* pixels, int bytes_per_pixel, int width, int height, VkImageView& image_view);
|
||||
void create_texture_sampler();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user