2019-02-20 20:21:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Copyright(C) 2010-2016 Christoph Oelckers
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// This program 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 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program 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 program. If not, see http://www.gnu.org/licenses/
|
|
|
|
//
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "volk/volk.h"
|
|
|
|
|
|
|
|
#include "v_video.h"
|
|
|
|
#include "m_png.h"
|
|
|
|
#include "templates.h"
|
|
|
|
#include "r_videoscale.h"
|
|
|
|
#include "actor.h"
|
|
|
|
|
|
|
|
#include "hwrenderer/utility/hw_clock.h"
|
|
|
|
#include "hwrenderer/utility/hw_vrmodes.h"
|
2019-02-21 11:31:14 +00:00
|
|
|
#include "hwrenderer/models/hw_models.h"
|
|
|
|
#include "hwrenderer/scene/hw_skydome.h"
|
|
|
|
#include "hwrenderer/data/hw_viewpointbuffer.h"
|
|
|
|
#include "hwrenderer/data/flatvertices.h"
|
2019-02-26 10:27:29 +00:00
|
|
|
#include "hwrenderer/data/shaderuniforms.h"
|
2019-02-21 11:31:14 +00:00
|
|
|
#include "hwrenderer/dynlights/hw_lightbuffer.h"
|
2019-02-20 20:21:57 +00:00
|
|
|
|
2019-02-27 14:37:37 +00:00
|
|
|
#include "swrenderer/r_swscene.h"
|
|
|
|
|
2019-02-20 20:21:57 +00:00
|
|
|
#include "vk_framebuffer.h"
|
2019-02-21 11:31:14 +00:00
|
|
|
#include "vk_buffers.h"
|
2019-02-21 21:49:00 +00:00
|
|
|
#include "vulkan/renderer/vk_renderstate.h"
|
2019-02-26 10:27:29 +00:00
|
|
|
#include "vulkan/renderer/vk_renderpass.h"
|
2019-02-21 21:49:00 +00:00
|
|
|
#include "vulkan/shaders/vk_shader.h"
|
2019-02-20 20:21:57 +00:00
|
|
|
#include "vulkan/textures/vk_samplers.h"
|
2019-02-26 14:29:08 +00:00
|
|
|
#include "vulkan/textures/vk_hwtexture.h"
|
2019-02-20 23:25:51 +00:00
|
|
|
#include "vulkan/system/vk_builders.h"
|
2019-02-21 09:19:59 +00:00
|
|
|
#include "vulkan/system/vk_swapchain.h"
|
2019-02-20 23:25:51 +00:00
|
|
|
#include "doomerrors.h"
|
|
|
|
|
2019-02-21 21:49:00 +00:00
|
|
|
void Draw2D(F2DDrawer *drawer, FRenderState &state);
|
2019-02-20 20:21:57 +00:00
|
|
|
|
|
|
|
EXTERN_CVAR(Bool, vid_vsync)
|
|
|
|
EXTERN_CVAR(Bool, r_drawvoxels)
|
|
|
|
EXTERN_CVAR(Int, gl_tonemap)
|
|
|
|
|
|
|
|
VulkanFrameBuffer::VulkanFrameBuffer(void *hMonitor, bool fullscreen, VulkanDevice *dev) :
|
|
|
|
Super(hMonitor, fullscreen)
|
|
|
|
{
|
2019-02-21 09:19:59 +00:00
|
|
|
device = dev;
|
|
|
|
SetViewportRects(nullptr);
|
|
|
|
}
|
2019-02-20 23:25:51 +00:00
|
|
|
|
2019-02-21 09:19:59 +00:00
|
|
|
VulkanFrameBuffer::~VulkanFrameBuffer()
|
|
|
|
{
|
2019-02-26 19:19:54 +00:00
|
|
|
delete MatricesUBO;
|
|
|
|
delete ColorsUBO;
|
|
|
|
delete GlowingWallsUBO;
|
|
|
|
delete mVertexData;
|
|
|
|
delete mSkyData;
|
|
|
|
delete mViewpoints;
|
|
|
|
delete mLights;
|
2019-02-26 14:29:08 +00:00
|
|
|
for (auto tex : AllTextures)
|
|
|
|
tex->Reset();
|
2019-02-21 09:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanFrameBuffer::InitializeState()
|
|
|
|
{
|
2019-02-26 19:19:54 +00:00
|
|
|
gl_vendorstring = "Vulkan";
|
|
|
|
hwcaps = RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE;
|
|
|
|
|
2019-02-26 10:58:03 +00:00
|
|
|
mUploadSemaphore.reset(new VulkanSemaphore(device));
|
2019-02-21 11:31:14 +00:00
|
|
|
mGraphicsCommandPool.reset(new VulkanCommandPool(device, device->graphicsFamily));
|
|
|
|
|
|
|
|
mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight());
|
|
|
|
mSkyData = new FSkyVertexBuffer;
|
|
|
|
mViewpoints = new GLViewpointBuffer;
|
|
|
|
mLights = new FLightBuffer();
|
|
|
|
|
2019-02-26 15:50:54 +00:00
|
|
|
// To do: move this to HW renderer interface maybe?
|
|
|
|
MatricesUBO = (VKDataBuffer*)CreateDataBuffer(1234, false);
|
|
|
|
ColorsUBO = (VKDataBuffer*)CreateDataBuffer(1234, false);
|
|
|
|
GlowingWallsUBO = (VKDataBuffer*)CreateDataBuffer(1234, false);
|
2019-02-26 19:19:54 +00:00
|
|
|
MatricesUBO->SetData(sizeof(MatricesUBO) * 128, nullptr, false);
|
|
|
|
ColorsUBO->SetData(sizeof(ColorsUBO) * 128, nullptr, false);
|
|
|
|
GlowingWallsUBO->SetData(sizeof(GlowingWallsUBO) * 128, nullptr, false);
|
2019-02-26 15:50:54 +00:00
|
|
|
|
2019-02-22 10:30:48 +00:00
|
|
|
mShaderManager.reset(new VkShaderManager(device));
|
2019-02-21 09:19:59 +00:00
|
|
|
mSamplerManager.reset(new VkSamplerManager(device));
|
2019-02-26 10:27:29 +00:00
|
|
|
mRenderPassManager.reset(new VkRenderPassManager());
|
2019-02-21 21:49:00 +00:00
|
|
|
mRenderState.reset(new VkRenderState());
|
2019-02-20 20:21:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanFrameBuffer::Update()
|
|
|
|
{
|
|
|
|
twoD.Reset();
|
|
|
|
Flush3D.Reset();
|
|
|
|
|
|
|
|
Flush3D.Clock();
|
|
|
|
|
2019-02-21 09:19:59 +00:00
|
|
|
int newWidth = GetClientWidth();
|
|
|
|
int newHeight = GetClientHeight();
|
|
|
|
if (lastSwapWidth != newWidth || lastSwapHeight != newHeight)
|
2019-02-20 20:21:57 +00:00
|
|
|
{
|
2019-02-21 09:19:59 +00:00
|
|
|
device->windowResized();
|
|
|
|
lastSwapWidth = newWidth;
|
|
|
|
lastSwapHeight = newHeight;
|
2019-02-20 20:21:57 +00:00
|
|
|
}
|
2019-02-21 09:19:59 +00:00
|
|
|
|
|
|
|
device->beginFrame();
|
|
|
|
|
|
|
|
Draw2D();
|
|
|
|
Clear2D();
|
2019-02-26 10:27:29 +00:00
|
|
|
|
|
|
|
mRenderState->EndRenderPass();
|
|
|
|
|
2019-02-21 09:19:59 +00:00
|
|
|
//DrawPresentTexture(mOutputLetterbox, true);
|
2019-02-26 11:25:17 +00:00
|
|
|
{
|
|
|
|
auto sceneColor = mRenderPassManager->SceneColor.get();
|
|
|
|
|
|
|
|
PipelineBarrier barrier0;
|
|
|
|
barrier0.addImage(sceneColor, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
|
2019-02-27 14:37:37 +00:00
|
|
|
barrier0.execute(GetDrawCommands(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
2019-02-26 11:25:17 +00:00
|
|
|
|
|
|
|
VkImageBlit blit = {};
|
|
|
|
blit.srcOffsets[0] = { 0, 0, 0 };
|
|
|
|
blit.srcOffsets[1] = { sceneColor->width, sceneColor->height, 1 };
|
|
|
|
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
blit.srcSubresource.mipLevel = 0;
|
|
|
|
blit.srcSubresource.baseArrayLayer = 0;
|
|
|
|
blit.srcSubresource.layerCount = 1;
|
|
|
|
blit.dstOffsets[0] = { 0, 0, 0 };
|
|
|
|
blit.dstOffsets[1] = { (int32_t)device->swapChain->actualExtent.width, (int32_t)device->swapChain->actualExtent.height, 1 };
|
|
|
|
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
blit.dstSubresource.mipLevel = 0;
|
|
|
|
blit.dstSubresource.baseArrayLayer = 0;
|
|
|
|
blit.dstSubresource.layerCount = 1;
|
2019-02-27 14:37:37 +00:00
|
|
|
GetDrawCommands()->blitImage(
|
2019-02-26 11:25:17 +00:00
|
|
|
sceneColor->image, VK_IMAGE_LAYOUT_GENERAL,
|
|
|
|
device->swapChain->swapChainImages[device->presentImageIndex], VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
|
|
|
|
1, &blit, VK_FILTER_NEAREST);
|
|
|
|
}
|
2019-02-21 09:19:59 +00:00
|
|
|
|
2019-02-27 14:37:37 +00:00
|
|
|
mDrawCommands->end();
|
2019-02-21 09:19:59 +00:00
|
|
|
|
2019-02-26 10:58:03 +00:00
|
|
|
if (mUploadCommands)
|
|
|
|
{
|
2019-02-26 19:19:54 +00:00
|
|
|
mUploadCommands->end();
|
|
|
|
|
2019-02-26 10:58:03 +00:00
|
|
|
// Submit upload commands immediately
|
|
|
|
VkSubmitInfo submitInfo = {};
|
|
|
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
|
|
submitInfo.commandBufferCount = 1;
|
|
|
|
submitInfo.pCommandBuffers = &mUploadCommands->buffer;
|
|
|
|
submitInfo.signalSemaphoreCount = 1;
|
|
|
|
submitInfo.pSignalSemaphores = &mUploadSemaphore->semaphore;
|
|
|
|
VkResult result = vkQueueSubmit(device->graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
I_FatalError("Failed to submit command buffer!\n");
|
|
|
|
|
|
|
|
// Wait for upload commands to finish, then submit render commands
|
|
|
|
VkSemaphore waitSemaphores[] = { mUploadSemaphore->semaphore, device->imageAvailableSemaphore->semaphore };
|
|
|
|
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
|
|
|
submitInfo.waitSemaphoreCount = 2;
|
|
|
|
submitInfo.pWaitSemaphores = waitSemaphores;
|
|
|
|
submitInfo.pWaitDstStageMask = waitStages;
|
|
|
|
submitInfo.commandBufferCount = 1;
|
2019-02-27 14:37:37 +00:00
|
|
|
submitInfo.pCommandBuffers = &mDrawCommands->buffer;
|
2019-02-26 10:58:03 +00:00
|
|
|
submitInfo.signalSemaphoreCount = 1;
|
|
|
|
submitInfo.pSignalSemaphores = &device->renderFinishedSemaphore->semaphore;
|
|
|
|
result = vkQueueSubmit(device->graphicsQueue, 1, &submitInfo, device->renderFinishedFence->fence);
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
I_FatalError("Failed to submit command buffer!\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
VkSemaphore waitSemaphores[] = { device->imageAvailableSemaphore->semaphore };
|
|
|
|
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
|
|
|
|
|
|
|
VkSubmitInfo submitInfo = {};
|
|
|
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
|
|
submitInfo.waitSemaphoreCount = 1;
|
|
|
|
submitInfo.pWaitSemaphores = waitSemaphores;
|
|
|
|
submitInfo.pWaitDstStageMask = waitStages;
|
|
|
|
submitInfo.commandBufferCount = 1;
|
2019-02-27 14:37:37 +00:00
|
|
|
submitInfo.pCommandBuffers = &mDrawCommands->buffer;
|
2019-02-26 10:58:03 +00:00
|
|
|
submitInfo.signalSemaphoreCount = 1;
|
|
|
|
submitInfo.pSignalSemaphores = &device->renderFinishedSemaphore->semaphore;
|
|
|
|
VkResult result = vkQueueSubmit(device->graphicsQueue, 1, &submitInfo, device->renderFinishedFence->fence);
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
I_FatalError("Failed to submit command buffer!\n");
|
|
|
|
}
|
2019-02-21 09:19:59 +00:00
|
|
|
|
|
|
|
Flush3D.Unclock();
|
|
|
|
|
|
|
|
Finish.Reset();
|
|
|
|
Finish.Clock();
|
|
|
|
device->presentFrame();
|
|
|
|
device->waitPresent();
|
|
|
|
|
2019-02-27 14:37:37 +00:00
|
|
|
mDrawCommands.reset();
|
2019-02-21 09:19:59 +00:00
|
|
|
mUploadCommands.reset();
|
2019-02-26 19:19:54 +00:00
|
|
|
mFrameDeleteList.clear();
|
2019-02-21 09:19:59 +00:00
|
|
|
|
|
|
|
Finish.Unclock();
|
|
|
|
|
|
|
|
Super::Update();
|
2019-02-20 20:21:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height)
|
|
|
|
{
|
|
|
|
if (!V_IsHardwareRenderer())
|
|
|
|
Super::WriteSavePic(player, file, width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
sector_t *VulkanFrameBuffer::RenderView(player_t *player)
|
|
|
|
{
|
2019-02-27 14:37:37 +00:00
|
|
|
mRenderState->SetVertexBuffer(screen->mVertexData);
|
|
|
|
screen->mVertexData->Reset();
|
|
|
|
|
|
|
|
if (!V_IsHardwareRenderer())
|
|
|
|
{
|
|
|
|
if (!swdrawer) swdrawer.reset(new SWSceneDrawer);
|
|
|
|
return swdrawer->RenderView(player);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2019-02-20 20:21:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t VulkanFrameBuffer::GetCaps()
|
|
|
|
{
|
|
|
|
if (!V_IsHardwareRenderer())
|
|
|
|
return Super::GetCaps();
|
|
|
|
|
|
|
|
// describe our basic feature set
|
|
|
|
ActorRenderFeatureFlags FlagSet = RFF_FLATSPRITES | RFF_MODELS | RFF_SLOPE3DFLOORS |
|
|
|
|
RFF_TILTPITCH | RFF_ROLLSPRITES | RFF_POLYGONAL | RFF_MATSHADER | RFF_POSTSHADER | RFF_BRIGHTMAP;
|
|
|
|
if (r_drawvoxels)
|
|
|
|
FlagSet |= RFF_VOXELS;
|
|
|
|
|
|
|
|
if (gl_tonemap != 5) // not running palette tonemap shader
|
|
|
|
FlagSet |= RFF_TRUECOLOR;
|
|
|
|
|
|
|
|
return (uint32_t)FlagSet;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanFrameBuffer::SetVSync(bool vsync)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanFrameBuffer::CleanForRestart()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-02-26 14:29:08 +00:00
|
|
|
IHardwareTexture *VulkanFrameBuffer::CreateHardwareTexture()
|
|
|
|
{
|
|
|
|
auto texture = new VkHardwareTexture();
|
|
|
|
AllTextures.Push(texture);
|
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
2019-02-20 20:21:57 +00:00
|
|
|
FModelRenderer *VulkanFrameBuffer::CreateModelRenderer(int mli)
|
|
|
|
{
|
2019-02-21 11:31:14 +00:00
|
|
|
I_FatalError("VulkanFrameBuffer::CreateModelRenderer not implemented\n");
|
2019-02-20 20:21:57 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-02-21 11:31:14 +00:00
|
|
|
IShaderProgram *VulkanFrameBuffer::CreateShaderProgram()
|
2019-02-20 20:21:57 +00:00
|
|
|
{
|
2019-02-21 11:31:14 +00:00
|
|
|
I_FatalError("VulkanFrameBuffer::CreateShaderProgram not implemented\n");
|
2019-02-20 20:21:57 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-02-21 11:31:14 +00:00
|
|
|
IVertexBuffer *VulkanFrameBuffer::CreateVertexBuffer()
|
|
|
|
{
|
|
|
|
return new VKVertexBuffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
IIndexBuffer *VulkanFrameBuffer::CreateIndexBuffer()
|
|
|
|
{
|
|
|
|
return new VKIndexBuffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
IDataBuffer *VulkanFrameBuffer::CreateDataBuffer(int bindingpoint, bool ssbo)
|
|
|
|
{
|
2019-02-26 10:27:29 +00:00
|
|
|
auto buffer = new VKDataBuffer(bindingpoint, ssbo);
|
|
|
|
if (bindingpoint == VIEWPOINT_BINDINGPOINT)
|
|
|
|
{
|
|
|
|
ViewpointUBO = buffer;
|
|
|
|
}
|
|
|
|
else if (bindingpoint == LIGHTBUF_BINDINGPOINT)
|
|
|
|
{
|
|
|
|
LightBufferSSO = buffer;
|
|
|
|
}
|
|
|
|
return buffer;
|
2019-02-20 20:21:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanFrameBuffer::UnbindTexUnit(int no)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanFrameBuffer::TextureFilterChanged()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanFrameBuffer::BlurScene(float amount)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanFrameBuffer::UpdatePalette()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanFrameBuffer::BeginFrame()
|
|
|
|
{
|
2019-02-26 10:27:29 +00:00
|
|
|
mRenderPassManager->BeginFrame();
|
2019-02-20 20:21:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanFrameBuffer::Draw2D()
|
|
|
|
{
|
2019-02-21 21:49:00 +00:00
|
|
|
::Draw2D(&m2DDrawer, *mRenderState);
|
2019-02-20 20:21:57 +00:00
|
|
|
}
|
2019-02-21 11:31:14 +00:00
|
|
|
|
|
|
|
VulkanCommandBuffer *VulkanFrameBuffer::GetUploadCommands()
|
|
|
|
{
|
|
|
|
if (!mUploadCommands)
|
|
|
|
{
|
|
|
|
mUploadCommands = mGraphicsCommandPool->createBuffer();
|
|
|
|
mUploadCommands->begin();
|
|
|
|
}
|
|
|
|
return mUploadCommands.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
VulkanCommandBuffer *VulkanFrameBuffer::GetDrawCommands()
|
|
|
|
{
|
2019-02-27 14:37:37 +00:00
|
|
|
if (!mDrawCommands)
|
|
|
|
{
|
|
|
|
mDrawCommands = mGraphicsCommandPool->createBuffer();
|
|
|
|
mDrawCommands->begin();
|
|
|
|
}
|
|
|
|
return mDrawCommands.get();
|
2019-02-21 11:31:14 +00:00
|
|
|
}
|