mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-11 10:24:10 +01:00
[dxvk] Refactor swap chain blitter to use plain Vulkan
Temporarily disable the HUD until that is refactored too.
This commit is contained in:
parent
1c06431e18
commit
207e15eb24
@ -398,13 +398,16 @@ namespace dxvk {
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
|
||||
m_blitter->presentImage(m_context.ptr(),
|
||||
m_imageViews.at(imageIndex), VkRect2D(),
|
||||
m_swapImageView, VkRect2D());
|
||||
m_blitter->beginPresent(m_context->beginExternalRendering(),
|
||||
m_imageViews.at(imageIndex), m_colorspace, VkRect2D(),
|
||||
m_swapImageView, m_colorspace, VkRect2D());
|
||||
|
||||
if (m_hud != nullptr)
|
||||
m_hud->render(m_context, info.format, info.imageExtent);
|
||||
// if (m_hud != nullptr)
|
||||
// m_hud->render(m_context, info.format, info.imageExtent);
|
||||
|
||||
m_blitter->endPresent(m_context->beginExternalRendering(),
|
||||
m_imageViews.at(imageIndex));
|
||||
|
||||
SubmitPresent(immediateContext, sync, i);
|
||||
}
|
||||
|
||||
|
@ -847,12 +847,15 @@ namespace dxvk {
|
||||
{ int32_t(m_dstRect.left), int32_t(m_dstRect.top) },
|
||||
{ uint32_t(m_dstRect.right - m_dstRect.left), uint32_t(m_dstRect.bottom - m_dstRect.top) } };
|
||||
|
||||
m_blitter->presentImage(m_context.ptr(),
|
||||
m_wctx->imageViews.at(imageIndex), dstRect,
|
||||
swapImageView, srcRect);
|
||||
m_blitter->beginPresent(m_context->beginExternalRendering(),
|
||||
m_wctx->imageViews.at(imageIndex), m_colorspace, dstRect,
|
||||
swapImageView, m_colorspace, srcRect);
|
||||
|
||||
if (m_hud != nullptr)
|
||||
m_hud->render(m_context, info.format, info.imageExtent);
|
||||
// if (m_hud != nullptr)
|
||||
// m_hud->render(m_context, info.format, info.imageExtent);
|
||||
|
||||
m_blitter->endPresent(m_context->beginExternalRendering(),
|
||||
m_wctx->imageViews.at(imageIndex));
|
||||
|
||||
SubmitPresent(sync, i);
|
||||
}
|
||||
|
@ -4,30 +4,46 @@
|
||||
#include <dxvk_present_frag_blit.h>
|
||||
#include <dxvk_present_frag_ms.h>
|
||||
#include <dxvk_present_frag_ms_amd.h>
|
||||
#include <dxvk_present_frag_ms_blit.h>
|
||||
#include <dxvk_present_vert.h>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkSwapchainBlitter::DxvkSwapchainBlitter(const Rc<DxvkDevice>& device)
|
||||
: m_device(device) {
|
||||
: m_device(device),
|
||||
m_setLayout(createSetLayout()),
|
||||
m_pipelineLayout(createPipelineLayout()) {
|
||||
this->createSampler();
|
||||
this->createShaders();
|
||||
}
|
||||
|
||||
|
||||
DxvkSwapchainBlitter::~DxvkSwapchainBlitter() {
|
||||
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
for (const auto& p : m_pipelines)
|
||||
vk->vkDestroyPipeline(vk->device(), p.second, nullptr);
|
||||
|
||||
vk->vkDestroyShaderModule(vk->device(), m_shaderVsBlit.stageInfo.module, nullptr);
|
||||
vk->vkDestroyShaderModule(vk->device(), m_shaderFsBlit.stageInfo.module, nullptr);
|
||||
vk->vkDestroyShaderModule(vk->device(), m_shaderFsCopy.stageInfo.module, nullptr);
|
||||
vk->vkDestroyShaderModule(vk->device(), m_shaderFsMsBlit.stageInfo.module, nullptr);
|
||||
vk->vkDestroyShaderModule(vk->device(), m_shaderFsMsResolve.stageInfo.module, nullptr);
|
||||
|
||||
vk->vkDestroyPipelineLayout(vk->device(), m_pipelineLayout, nullptr);
|
||||
vk->vkDestroyDescriptorSetLayout(vk->device(), m_setLayout, nullptr);
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::presentImage(
|
||||
DxvkContext* ctx,
|
||||
void DxvkSwapchainBlitter::beginPresent(
|
||||
const DxvkContextObjects& ctx,
|
||||
const Rc<DxvkImageView>& dstView,
|
||||
VkColorSpaceKHR dstColorSpace,
|
||||
VkRect2D dstRect,
|
||||
const Rc<DxvkImageView>& srcView,
|
||||
VkColorSpaceKHR srcColorSpace,
|
||||
VkRect2D srcRect) {
|
||||
if (m_gammaDirty)
|
||||
this->updateGammaTexture(ctx);
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
||||
// Fix up default present areas if necessary
|
||||
if (!dstRect.extent.width || !dstRect.extent.height) {
|
||||
@ -44,244 +60,250 @@ namespace dxvk {
|
||||
srcView->image()->info().extent.height };
|
||||
}
|
||||
|
||||
bool sameSize = dstRect.extent == srcRect.extent;
|
||||
bool usedResolveImage = false;
|
||||
if (m_gammaBuffer)
|
||||
uploadGammaImage(ctx);
|
||||
|
||||
if (srcView->image()->info().sampleCount == VK_SAMPLE_COUNT_1_BIT) {
|
||||
this->draw(ctx, sameSize ? m_fsCopy : m_fsBlit,
|
||||
dstView, dstRect, srcView, srcRect);
|
||||
} else if (sameSize) {
|
||||
this->draw(ctx, m_fsResolve,
|
||||
dstView, dstRect, srcView, srcRect);
|
||||
} else {
|
||||
if (m_resolveImage == nullptr
|
||||
|| m_resolveImage->info().extent != srcView->image()->info().extent
|
||||
|| m_resolveImage->info().format != srcView->image()->info().format)
|
||||
this->createResolveImage(srcView->image()->info());
|
||||
VkImageMemoryBarrier2 barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
|
||||
barrier.dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
barrier.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
barrier.newLayout = dstView->image()->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = dstView->image()->handle();
|
||||
barrier.subresourceRange = dstView->imageSubresources();
|
||||
|
||||
this->resolve(ctx, m_resolveView, srcView);
|
||||
this->draw(ctx, m_fsBlit, dstView, dstRect, m_resolveView, srcRect);
|
||||
VkDependencyInfo depInfo = { VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
|
||||
depInfo.imageMemoryBarrierCount = 1;
|
||||
depInfo.pImageMemoryBarriers = &barrier;
|
||||
|
||||
usedResolveImage = true;
|
||||
ctx.cmd->cmdPipelineBarrier(DxvkCmdBuffer::ExecBuffer, &depInfo);
|
||||
|
||||
VkExtent3D dstExtent = dstView->mipLevelExtent(0u);
|
||||
|
||||
VkRenderingAttachmentInfo attachmentInfo = { VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO };
|
||||
attachmentInfo.imageView = dstView->handle();
|
||||
attachmentInfo.imageLayout = dstView->image()->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
if (srcRect.extent != dstRect.extent)
|
||||
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
|
||||
VkRenderingInfo renderInfo = { VK_STRUCTURE_TYPE_RENDERING_INFO };
|
||||
renderInfo.renderArea.offset = { 0u, 0u };
|
||||
renderInfo.renderArea.extent = { dstExtent.width, dstExtent.height };
|
||||
renderInfo.layerCount = 1u;
|
||||
renderInfo.colorAttachmentCount = 1;
|
||||
renderInfo.pColorAttachments = &attachmentInfo;
|
||||
|
||||
ctx.cmd->cmdBeginRendering(&renderInfo);
|
||||
|
||||
DxvkSwapchainPipelineKey key;
|
||||
key.srcSpace = srcColorSpace;
|
||||
key.srcSamples = srcView->image()->info().sampleCount;
|
||||
key.srcIsSrgb = srcView->formatInfo()->flags.test(DxvkFormatFlag::ColorSpaceSrgb);
|
||||
key.dstSpace = dstColorSpace;
|
||||
key.dstFormat = dstView->info().format;
|
||||
key.needsGamma = m_gammaView != nullptr;
|
||||
key.needsBlit = dstRect.extent != srcRect.extent;
|
||||
|
||||
VkPipeline pipeline = getPipeline(key);
|
||||
|
||||
VkViewport viewport = { };
|
||||
viewport.x = float(dstRect.offset.x);
|
||||
viewport.y = float(dstRect.offset.y);
|
||||
viewport.width = float(dstRect.extent.width);
|
||||
viewport.height = float(dstRect.extent.height);
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 0.0f;
|
||||
|
||||
ctx.cmd->cmdSetViewport(1, &viewport);
|
||||
ctx.cmd->cmdSetScissor(1, &dstRect);
|
||||
|
||||
ctx.cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
|
||||
VkDescriptorSet set = ctx.descriptorPool->alloc(m_setLayout);
|
||||
|
||||
VkDescriptorImageInfo imageDescriptor = { };
|
||||
imageDescriptor.sampler = m_samplerPresent->handle();
|
||||
imageDescriptor.imageView = srcView->handle();
|
||||
imageDescriptor.imageLayout = srcView->image()->info().layout;
|
||||
|
||||
VkDescriptorImageInfo gammaDescriptor = { };
|
||||
gammaDescriptor.sampler = m_samplerGamma->handle();
|
||||
|
||||
if (m_gammaView) {
|
||||
gammaDescriptor.imageView = m_gammaView->handle();
|
||||
gammaDescriptor.imageLayout = m_gammaView->image()->info().layout;
|
||||
}
|
||||
|
||||
if (!usedResolveImage)
|
||||
this->destroyResolveImage();
|
||||
std::array<VkWriteDescriptorSet, 2> descriptorWrites = {{
|
||||
{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr,
|
||||
set, 0, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageDescriptor },
|
||||
{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr,
|
||||
set, 1, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &gammaDescriptor },
|
||||
}};
|
||||
|
||||
ctx.cmd->updateDescriptorSets(descriptorWrites.size(), descriptorWrites.data());
|
||||
ctx.cmd->cmdBindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, set, 0, nullptr);
|
||||
|
||||
PushConstants args = { };
|
||||
args.srcOffset = srcRect.offset;
|
||||
args.srcExtent = srcRect.extent;
|
||||
args.dstOffset = dstRect.offset;
|
||||
|
||||
ctx.cmd->cmdPushConstants(m_pipelineLayout,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(args), &args);
|
||||
|
||||
ctx.cmd->cmdDraw(3, 1, 0, 0);
|
||||
|
||||
// Make sure to keep used resources alive
|
||||
ctx.cmd->trackResource<DxvkAccess::Read>(srcView->image());
|
||||
ctx.cmd->trackResource<DxvkAccess::Write>(dstView->image());
|
||||
|
||||
if (m_gammaImage)
|
||||
ctx.cmd->trackResource<DxvkAccess::Read>(m_gammaImage->getAllocation());
|
||||
|
||||
ctx.cmd->trackSampler(m_samplerGamma);
|
||||
ctx.cmd->trackSampler(m_samplerPresent);
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::endPresent(
|
||||
const DxvkContextObjects& ctx,
|
||||
const Rc<DxvkImageView>& dstView) {
|
||||
ctx.cmd->cmdEndRendering();
|
||||
|
||||
VkImageMemoryBarrier2 barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
|
||||
barrier.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT;
|
||||
barrier.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
|
||||
barrier.oldLayout = dstView->image()->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
barrier.newLayout = dstView->image()->info().layout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = dstView->image()->handle();
|
||||
barrier.subresourceRange = dstView->imageSubresources();
|
||||
|
||||
VkDependencyInfo depInfo = { VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
|
||||
depInfo.imageMemoryBarrierCount = 1;
|
||||
depInfo.pImageMemoryBarriers = &barrier;
|
||||
|
||||
ctx.cmd->cmdPipelineBarrier(DxvkCmdBuffer::ExecBuffer, &depInfo);
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::setGammaRamp(
|
||||
uint32_t cpCount,
|
||||
const DxvkGammaCp* cpData) {
|
||||
VkDeviceSize size = cpCount * sizeof(*cpData);
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
||||
if (cpCount) {
|
||||
if (!m_gammaBuffer || m_gammaBuffer->info().size < size) {
|
||||
DxvkBufferCreateInfo bufInfo;
|
||||
bufInfo.size = size;
|
||||
bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
bufInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
// Create temporary upload buffer for the curve
|
||||
DxvkBufferCreateInfo bufferInfo = { };
|
||||
bufferInfo.size = cpCount * sizeof(*cpData);
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufferInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
bufferInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
|
||||
m_gammaBuffer = m_device->createBuffer(bufInfo,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
m_gammaSlice = m_gammaBuffer->getAllocation();
|
||||
} else {
|
||||
m_gammaSlice = m_gammaBuffer->allocateSlice();
|
||||
}
|
||||
m_gammaBuffer = m_device->createBuffer(bufferInfo,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
m_gammaCpCount = cpCount;
|
||||
|
||||
std::memcpy(m_gammaSlice->mapPtr(), cpData, size);
|
||||
std::memcpy(m_gammaBuffer->mapPtr(0), cpData, cpCount * sizeof(*cpData));
|
||||
} else {
|
||||
// Destroy gamma image altogether
|
||||
m_gammaBuffer = nullptr;
|
||||
m_gammaSlice = nullptr;
|
||||
}
|
||||
|
||||
m_gammaCpCount = cpCount;
|
||||
m_gammaDirty = true;
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::draw(
|
||||
DxvkContext* ctx,
|
||||
const Rc<DxvkShader>& fs,
|
||||
const Rc<DxvkImageView>& dstView,
|
||||
VkRect2D dstRect,
|
||||
const Rc<DxvkImageView>& srcView,
|
||||
VkRect2D srcRect) {
|
||||
DxvkInputAssemblyState iaState;
|
||||
iaState.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
|
||||
iaState.primitiveRestart = VK_FALSE;
|
||||
iaState.patchVertexCount = 0;
|
||||
ctx->setInputAssemblyState(iaState);
|
||||
ctx->setInputLayout(0, nullptr, 0, nullptr);
|
||||
|
||||
DxvkRasterizerState rsState;
|
||||
rsState.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rsState.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||
rsState.depthClipEnable = VK_FALSE;
|
||||
rsState.depthBiasEnable = VK_FALSE;
|
||||
rsState.conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
|
||||
rsState.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
rsState.flatShading = VK_FALSE;
|
||||
rsState.lineMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT;
|
||||
ctx->setRasterizerState(rsState);
|
||||
|
||||
DxvkMultisampleState msState;
|
||||
msState.sampleMask = 0xffffffff;
|
||||
msState.enableAlphaToCoverage = VK_FALSE;
|
||||
ctx->setMultisampleState(msState);
|
||||
|
||||
VkStencilOpState stencilOp;
|
||||
stencilOp.failOp = VK_STENCIL_OP_KEEP;
|
||||
stencilOp.passOp = VK_STENCIL_OP_KEEP;
|
||||
stencilOp.depthFailOp = VK_STENCIL_OP_KEEP;
|
||||
stencilOp.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
stencilOp.compareMask = 0xFFFFFFFF;
|
||||
stencilOp.writeMask = 0xFFFFFFFF;
|
||||
stencilOp.reference = 0;
|
||||
|
||||
DxvkDepthStencilState dsState;
|
||||
dsState.enableDepthTest = VK_FALSE;
|
||||
dsState.enableDepthWrite = VK_FALSE;
|
||||
dsState.enableStencilTest = VK_FALSE;
|
||||
dsState.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
dsState.stencilOpFront = stencilOp;
|
||||
dsState.stencilOpBack = stencilOp;
|
||||
ctx->setDepthStencilState(dsState);
|
||||
|
||||
DxvkLogicOpState loState;
|
||||
loState.enableLogicOp = VK_FALSE;
|
||||
loState.logicOp = VK_LOGIC_OP_NO_OP;
|
||||
ctx->setLogicOpState(loState);
|
||||
|
||||
DxvkBlendMode blendMode;
|
||||
blendMode.enableBlending = VK_FALSE;
|
||||
blendMode.colorSrcFactor = VK_BLEND_FACTOR_ONE;
|
||||
blendMode.colorDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
blendMode.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
blendMode.alphaSrcFactor = VK_BLEND_FACTOR_ONE;
|
||||
blendMode.alphaDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
blendMode.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
blendMode.writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
|
||||
| VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
ctx->setBlendMode(0, blendMode);
|
||||
|
||||
VkViewport viewport;
|
||||
viewport.x = float(dstRect.offset.x);
|
||||
viewport.y = float(dstRect.offset.y);
|
||||
viewport.width = float(dstRect.extent.width);
|
||||
viewport.height = float(dstRect.extent.height);
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
ctx->setViewports(1, &viewport, &dstRect);
|
||||
|
||||
DxvkRenderTargets renderTargets;
|
||||
renderTargets.color[0].view = dstView;
|
||||
renderTargets.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
ctx->bindRenderTargets(std::move(renderTargets), 0u);
|
||||
|
||||
VkExtent2D dstExtent = {
|
||||
dstView->image()->info().extent.width,
|
||||
dstView->image()->info().extent.height };
|
||||
|
||||
if (dstRect.extent == dstExtent)
|
||||
ctx->discardImageView(dstView, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
else
|
||||
ctx->clearRenderTarget(dstView, VK_IMAGE_ASPECT_COLOR_BIT, VkClearValue());
|
||||
|
||||
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, BindingIds::Image, Rc<DxvkSampler>(m_samplerPresent));
|
||||
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, BindingIds::Gamma, Rc<DxvkSampler>(m_samplerGamma));
|
||||
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, BindingIds::Image, Rc<DxvkImageView>(srcView));
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, BindingIds::Gamma, Rc<DxvkImageView>(m_gammaView));
|
||||
|
||||
ctx->bindShader<VK_SHADER_STAGE_VERTEX_BIT>(Rc<DxvkShader>(m_vs));
|
||||
ctx->bindShader<VK_SHADER_STAGE_FRAGMENT_BIT>(Rc<DxvkShader>(fs));
|
||||
|
||||
PresenterArgs args;
|
||||
args.srcOffset = srcRect.offset;
|
||||
|
||||
if (dstRect.extent == srcRect.extent)
|
||||
args.dstOffset = dstRect.offset;
|
||||
else
|
||||
args.srcExtent = srcRect.extent;
|
||||
|
||||
ctx->pushConstants(0, sizeof(args), &args);
|
||||
|
||||
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, 0, srcView->image()->info().sampleCount);
|
||||
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, 1, m_gammaView != nullptr);
|
||||
ctx->draw(3, 1, 0, 0);
|
||||
}
|
||||
|
||||
void DxvkSwapchainBlitter::resolve(
|
||||
DxvkContext* ctx,
|
||||
const Rc<DxvkImageView>& dstView,
|
||||
const Rc<DxvkImageView>& srcView) {
|
||||
VkImageResolve resolve;
|
||||
resolve.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||
resolve.srcOffset = { 0, 0, 0 };
|
||||
resolve.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||
resolve.dstOffset = { 0, 0, 0 };
|
||||
resolve.extent = dstView->image()->info().extent;
|
||||
ctx->resolveImage(dstView->image(), srcView->image(), resolve, VK_FORMAT_UNDEFINED);
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::updateGammaTexture(DxvkContext* ctx) {
|
||||
uint32_t n = m_gammaCpCount;
|
||||
|
||||
if (n) {
|
||||
// Reuse existing image if possible
|
||||
if (m_gammaImage == nullptr || m_gammaImage->info().extent.width != n) {
|
||||
DxvkImageCreateInfo imgInfo;
|
||||
imgInfo.type = VK_IMAGE_TYPE_1D;
|
||||
imgInfo.format = VK_FORMAT_R16G16B16A16_UNORM;
|
||||
imgInfo.flags = 0;
|
||||
imgInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
imgInfo.extent = { n, 1, 1 };
|
||||
imgInfo.numLayers = 1;
|
||||
imgInfo.mipLevels = 1;
|
||||
imgInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||
| VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imgInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
imgInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT
|
||||
| VK_ACCESS_SHADER_READ_BIT;
|
||||
imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imgInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
m_gammaImage = m_device->createImage(
|
||||
imgInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.format = VK_FORMAT_R16G16B16A16_UNORM;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
viewInfo.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
|
||||
m_gammaView = m_gammaImage->createView(viewInfo);
|
||||
}
|
||||
|
||||
ctx->invalidateBuffer(m_gammaBuffer, std::move(m_gammaSlice));
|
||||
ctx->copyBufferToImage(m_gammaImage,
|
||||
VkImageSubresourceLayers { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 },
|
||||
VkOffset3D { 0, 0, 0 },
|
||||
VkExtent3D { n, 1, 1 },
|
||||
m_gammaBuffer, 0, 0, 0);
|
||||
} else {
|
||||
m_gammaImage = nullptr;
|
||||
m_gammaView = nullptr;
|
||||
m_gammaView = nullptr;
|
||||
m_gammaCpCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::uploadGammaImage(
|
||||
const DxvkContextObjects& ctx) {
|
||||
if (!m_gammaImage || m_gammaImage->info().extent.width != m_gammaCpCount) {
|
||||
DxvkImageCreateInfo imageInfo = { };
|
||||
imageInfo.type = VK_IMAGE_TYPE_1D;
|
||||
imageInfo.format = VK_FORMAT_R16G16B16A16_UNORM;
|
||||
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.extent = { m_gammaCpCount, 1u, 1u };
|
||||
imageInfo.numLayers = 1u;
|
||||
imageInfo.mipLevels = 1u;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
imageInfo.access = VK_ACCESS_2_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
m_gammaImage = m_device->createImage(imageInfo,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
DxvkImageViewKey viewInfo = { };
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.format = imageInfo.format;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
viewInfo.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.mipIndex = 0u;
|
||||
viewInfo.mipCount = 1u;
|
||||
viewInfo.layerIndex = 0u;
|
||||
viewInfo.layerCount = 1u;
|
||||
|
||||
m_gammaView = m_gammaImage->createView(viewInfo);
|
||||
}
|
||||
|
||||
m_gammaDirty = false;
|
||||
VkImageMemoryBarrier2 barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
|
||||
barrier.srcStageMask = m_gammaImage->info().stages;
|
||||
barrier.srcAccessMask = m_gammaImage->info().access;
|
||||
barrier.dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
barrier.newLayout = m_gammaImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = m_gammaImage->handle();
|
||||
barrier.subresourceRange = m_gammaImage->getAvailableSubresources();
|
||||
|
||||
VkDependencyInfo depInfo = { VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
|
||||
depInfo.imageMemoryBarrierCount = 1;
|
||||
depInfo.pImageMemoryBarriers = &barrier;
|
||||
|
||||
ctx.cmd->cmdPipelineBarrier(DxvkCmdBuffer::ExecBuffer, &depInfo);
|
||||
|
||||
DxvkBufferSliceHandle bufferSlice = m_gammaBuffer->getSliceHandle();
|
||||
|
||||
VkBufferImageCopy2 copyRegion = { VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2 };
|
||||
copyRegion.bufferOffset = bufferSlice.offset;
|
||||
copyRegion.imageExtent = { m_gammaCpCount, 1u, 1u };
|
||||
copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copyRegion.imageSubresource.layerCount = 1u;
|
||||
|
||||
VkCopyBufferToImageInfo2 copy = { VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2 };
|
||||
copy.srcBuffer = bufferSlice.handle;
|
||||
copy.dstImage = m_gammaImage->handle();
|
||||
copy.dstImageLayout = m_gammaImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
copy.regionCount = 1;
|
||||
copy.pRegions = ©Region;
|
||||
|
||||
ctx.cmd->cmdCopyBufferToImage(DxvkCmdBuffer::ExecBuffer, ©);
|
||||
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstStageMask = m_gammaImage->info().stages;
|
||||
barrier.dstAccessMask = m_gammaImage->info().access;
|
||||
barrier.oldLayout = barrier.newLayout;
|
||||
barrier.newLayout = m_gammaImage->info().layout;
|
||||
|
||||
ctx.cmd->cmdPipelineBarrier(DxvkCmdBuffer::ExecBuffer, &depInfo);
|
||||
|
||||
ctx.cmd->trackResource<DxvkAccess::Read>(m_gammaBuffer->getAllocation());
|
||||
ctx.cmd->trackResource<DxvkAccess::Write>(m_gammaImage->getAllocation());
|
||||
|
||||
m_gammaBuffer = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@ -306,80 +328,219 @@ namespace dxvk {
|
||||
m_samplerGamma = m_device->createSampler(samplerInfo);
|
||||
}
|
||||
|
||||
void DxvkSwapchainBlitter::createShaders() {
|
||||
SpirvCodeBuffer vsCode(dxvk_present_vert);
|
||||
SpirvCodeBuffer fsCodeBlit(dxvk_present_frag_blit);
|
||||
SpirvCodeBuffer fsCodeCopy(dxvk_present_frag);
|
||||
SpirvCodeBuffer fsCodeResolve(dxvk_present_frag_ms);
|
||||
SpirvCodeBuffer fsCodeResolveAmd(dxvk_present_frag_ms_amd);
|
||||
|
||||
const std::array<DxvkBindingInfo, 2> fsBindings = {{
|
||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, BindingIds::Image, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, BindingIds::Gamma, VK_IMAGE_VIEW_TYPE_1D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
void DxvkSwapchainBlitter::createShaders() {
|
||||
createShaderModule(m_shaderVsBlit, VK_SHADER_STAGE_VERTEX_BIT,
|
||||
sizeof(dxvk_present_vert), dxvk_present_vert);
|
||||
createShaderModule(m_shaderFsBlit, VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
sizeof(dxvk_present_frag_blit), dxvk_present_frag_blit);
|
||||
createShaderModule(m_shaderFsCopy, VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
sizeof(dxvk_present_frag), dxvk_present_frag);
|
||||
createShaderModule(m_shaderFsMsBlit, VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
sizeof(dxvk_present_frag_ms_blit), dxvk_present_frag_ms_blit);
|
||||
|
||||
if (m_device->features().amdShaderFragmentMask) {
|
||||
createShaderModule(m_shaderFsMsResolve, VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
sizeof(dxvk_present_frag_ms_amd), dxvk_present_frag_ms_amd);
|
||||
} else {
|
||||
createShaderModule(m_shaderFsMsResolve, VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
sizeof(dxvk_present_frag_ms), dxvk_present_frag_ms);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::createShaderModule(
|
||||
ShaderModule& shader,
|
||||
VkShaderStageFlagBits stage,
|
||||
size_t size,
|
||||
const uint32_t* code) {
|
||||
shader.moduleInfo.codeSize = size;
|
||||
shader.moduleInfo.pCode = code;
|
||||
|
||||
shader.stageInfo.stage = stage;
|
||||
shader.stageInfo.pName = "main";
|
||||
|
||||
if (m_device->features().khrMaintenance5.maintenance5
|
||||
|| m_device->features().extGraphicsPipelineLibrary.graphicsPipelineLibrary) {
|
||||
shader.stageInfo.pNext = &shader.moduleInfo;
|
||||
return;
|
||||
}
|
||||
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
VkResult vr = vk->vkCreateShaderModule(vk->device(),
|
||||
&shader.moduleInfo, nullptr, &shader.stageInfo.module);
|
||||
|
||||
if (vr != VK_SUCCESS)
|
||||
throw DxvkError(str::format("Failed to create swap chain blit shader module: ", vr));
|
||||
}
|
||||
|
||||
|
||||
VkDescriptorSetLayout DxvkSwapchainBlitter::createSetLayout() {
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
std::array<VkDescriptorSetLayoutBinding, 3> bindings = {{
|
||||
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT },
|
||||
{ 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT },
|
||||
{ 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT },
|
||||
}};
|
||||
|
||||
DxvkShaderCreateInfo vsInfo;
|
||||
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vsInfo.pushConstStages = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
vsInfo.pushConstSize = sizeof(PresenterArgs);
|
||||
vsInfo.outputMask = 0x1;
|
||||
m_vs = new DxvkShader(vsInfo, std::move(vsCode));
|
||||
|
||||
DxvkShaderCreateInfo fsInfo;
|
||||
fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fsInfo.bindingCount = fsBindings.size();
|
||||
fsInfo.bindings = fsBindings.data();
|
||||
fsInfo.pushConstStages = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fsInfo.pushConstSize = sizeof(PresenterArgs);
|
||||
fsInfo.inputMask = 0x1;
|
||||
fsInfo.outputMask = 0x1;
|
||||
m_fsBlit = new DxvkShader(fsInfo, std::move(fsCodeBlit));
|
||||
|
||||
fsInfo.inputMask = 0;
|
||||
m_fsCopy = new DxvkShader(fsInfo, std::move(fsCodeCopy));
|
||||
m_fsResolve = new DxvkShader(fsInfo, m_device->features().amdShaderFragmentMask
|
||||
? std::move(fsCodeResolveAmd)
|
||||
: std::move(fsCodeResolve));
|
||||
}
|
||||
VkDescriptorSetLayoutCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
|
||||
info.bindingCount = bindings.size();
|
||||
info.pBindings = bindings.data();
|
||||
|
||||
void DxvkSwapchainBlitter::createResolveImage(const DxvkImageCreateInfo& info) {
|
||||
DxvkImageCreateInfo newInfo;
|
||||
newInfo.type = VK_IMAGE_TYPE_2D;
|
||||
newInfo.format = info.format;
|
||||
newInfo.flags = 0;
|
||||
newInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
newInfo.extent = info.extent;
|
||||
newInfo.numLayers = 1;
|
||||
newInfo.mipLevels = 1;
|
||||
newInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
|
||||
| VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||
| VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
newInfo.stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
|
||||
| VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
newInfo.access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_TRANSFER_WRITE_BIT
|
||||
| VK_ACCESS_SHADER_READ_BIT;
|
||||
newInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
newInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
m_resolveImage = m_device->createImage(newInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
|
||||
VkResult vr = vk->vkCreateDescriptorSetLayout(vk->device(), &info, nullptr, &layout);
|
||||
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = info.format;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
viewInfo.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
m_resolveView = m_resolveImage->createView(viewInfo);
|
||||
if (vr != VK_SUCCESS)
|
||||
throw DxvkError(str::format("Failed to create swap chain blit descriptor set layout: ", vr));
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::destroyResolveImage() {
|
||||
m_resolveImage = nullptr;
|
||||
m_resolveView = nullptr;
|
||||
VkPipelineLayout DxvkSwapchainBlitter::createPipelineLayout() {
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
VkPushConstantRange pushConst = { };
|
||||
pushConst.size = sizeof(PushConstants);
|
||||
pushConst.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
VkPipelineLayoutCreateInfo info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
|
||||
info.setLayoutCount = 1;
|
||||
info.pSetLayouts = &m_setLayout;
|
||||
info.pushConstantRangeCount = 1;
|
||||
info.pPushConstantRanges = &pushConst;
|
||||
|
||||
VkPipelineLayout layout = VK_NULL_HANDLE;
|
||||
VkResult vr = vk->vkCreatePipelineLayout(vk->device(), &info, nullptr, &layout);
|
||||
|
||||
if (vr != VK_SUCCESS)
|
||||
throw DxvkError(str::format("Failed to create swap chain blit pipeline layout: ", vr));
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
|
||||
VkPipeline DxvkSwapchainBlitter::createPipeline(
|
||||
const DxvkSwapchainPipelineKey& key) {
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
static const std::array<VkSpecializationMapEntry, 6> specMap = {{
|
||||
{ 0, offsetof(SpecConstants, sampleCount), sizeof(VkSampleCountFlagBits) },
|
||||
{ 1, offsetof(SpecConstants, gammaBound), sizeof(VkBool32) },
|
||||
{ 2, offsetof(SpecConstants, srcSpace), sizeof(VkColorSpaceKHR) },
|
||||
{ 3, offsetof(SpecConstants, srcIsSrgb), sizeof(VkBool32) },
|
||||
{ 4, offsetof(SpecConstants, dstSpace), sizeof(VkColorSpaceKHR) },
|
||||
{ 5, offsetof(SpecConstants, dstIsSrgb), sizeof(VkBool32) },
|
||||
}};
|
||||
|
||||
SpecConstants specConstants = { };
|
||||
specConstants.sampleCount = key.srcSamples;
|
||||
specConstants.gammaBound = key.needsGamma && key.srcSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
specConstants.srcSpace = key.srcSpace;
|
||||
specConstants.srcIsSrgb = key.srcIsSrgb;
|
||||
specConstants.dstSpace = key.dstSpace;
|
||||
specConstants.dstIsSrgb = lookupFormatInfo(key.dstFormat)->flags.test(DxvkFormatFlag::ColorSpaceSrgb);
|
||||
|
||||
// Avoid redundant color space conversions if color spaces
|
||||
// and images properties match and we don't do a resolve
|
||||
if (specConstants.srcSpace == specConstants.dstSpace && key.srcSamples == VK_SAMPLE_COUNT_1_BIT) {
|
||||
specConstants.srcSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
|
||||
specConstants.dstSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
|
||||
}
|
||||
|
||||
VkSpecializationInfo specInfo = { };
|
||||
specInfo.mapEntryCount = specMap.size();
|
||||
specInfo.pMapEntries = specMap.data();
|
||||
specInfo.dataSize = sizeof(specConstants);
|
||||
specInfo.pData = &specConstants;
|
||||
|
||||
std::array<VkPipelineShaderStageCreateInfo, 2> blitStages = { };
|
||||
blitStages[0] = m_shaderVsBlit.stageInfo;
|
||||
|
||||
if (key.srcSamples == VK_SAMPLE_COUNT_1_BIT)
|
||||
blitStages[1] = key.needsBlit ? m_shaderFsBlit.stageInfo : m_shaderFsCopy.stageInfo;
|
||||
else
|
||||
blitStages[1] = key.needsBlit ? m_shaderFsMsBlit.stageInfo : m_shaderFsMsResolve.stageInfo;
|
||||
|
||||
blitStages[1].pSpecializationInfo = &specInfo;
|
||||
|
||||
VkPipelineRenderingCreateInfo rtInfo = { VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO };
|
||||
rtInfo.colorAttachmentCount = 1;
|
||||
rtInfo.pColorAttachmentFormats = &key.dstFormat;
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo viState = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo iaState = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
|
||||
iaState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
|
||||
VkPipelineViewportStateCreateInfo vpState = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rsState = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
rsState.cullMode = VK_CULL_MODE_NONE;
|
||||
rsState.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||
rsState.lineWidth = 1.0f;
|
||||
|
||||
constexpr uint32_t sampleMask = 0x1;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo msState = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
|
||||
msState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
msState.pSampleMask = &sampleMask;
|
||||
|
||||
VkPipelineColorBlendAttachmentState cbOpaqueAttachment = { };
|
||||
cbOpaqueAttachment.colorWriteMask =
|
||||
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo cbOpaqueState = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
|
||||
cbOpaqueState.attachmentCount = 1;
|
||||
cbOpaqueState.pAttachments = &cbOpaqueAttachment;
|
||||
|
||||
static const std::array<VkDynamicState, 2> dynStates = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT,
|
||||
VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT,
|
||||
};
|
||||
|
||||
VkPipelineDynamicStateCreateInfo dynState = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
|
||||
dynState.dynamicStateCount = dynStates.size();
|
||||
dynState.pDynamicStates = dynStates.data();
|
||||
|
||||
VkGraphicsPipelineCreateInfo blitInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &rtInfo };
|
||||
blitInfo.stageCount = blitStages.size();
|
||||
blitInfo.pStages = blitStages.data();
|
||||
blitInfo.pVertexInputState = &viState;
|
||||
blitInfo.pInputAssemblyState = &iaState;
|
||||
blitInfo.pViewportState = &vpState;
|
||||
blitInfo.pRasterizationState = &rsState;
|
||||
blitInfo.pMultisampleState = &msState;
|
||||
blitInfo.pColorBlendState = &cbOpaqueState;
|
||||
blitInfo.pDynamicState = &dynState;
|
||||
blitInfo.layout = m_pipelineLayout;
|
||||
blitInfo.basePipelineIndex = -1;
|
||||
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE,
|
||||
1, &blitInfo, nullptr, &pipeline);
|
||||
|
||||
if (vr != VK_SUCCESS)
|
||||
throw DxvkError(str::format("Failed to create swap chain blit pipeline: ", vr));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
|
||||
VkPipeline DxvkSwapchainBlitter::getPipeline(
|
||||
const DxvkSwapchainPipelineKey& key) {
|
||||
auto entry = m_pipelines.find(key);
|
||||
|
||||
if (entry != m_pipelines.end())
|
||||
return entry->second;
|
||||
|
||||
VkPipeline pipeline = createPipeline(key);
|
||||
m_pipelines.insert({ key, pipeline });
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../util/thread.h"
|
||||
|
||||
#include "../dxvk/dxvk_device.h"
|
||||
#include "../dxvk/dxvk_context.h"
|
||||
|
||||
@ -11,7 +17,57 @@ namespace dxvk {
|
||||
struct DxvkGammaCp {
|
||||
uint16_t r, g, b, a;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \brief Swap chain blitter pipeline key
|
||||
*
|
||||
* Used to look up specific pipelines.
|
||||
*/
|
||||
struct DxvkSwapchainPipelineKey {
|
||||
/// Input color space. If this does not match the output color
|
||||
/// space, the input will be converted to match the output.
|
||||
VkColorSpaceKHR srcSpace = VK_COLOR_SPACE_MAX_ENUM_KHR;
|
||||
/// Source image sample count. Used to determine the shader to
|
||||
/// use, and passed to it via a spec constant.
|
||||
VkSampleCountFlagBits srcSamples = VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM;
|
||||
/// Whether the source image uses an sRGB format. Relevant for
|
||||
/// automatic color space conversion.
|
||||
VkBool32 srcIsSrgb = VK_FALSE;
|
||||
/// Output color space.
|
||||
VkColorSpaceKHR dstSpace = VK_COLOR_SPACE_MAX_ENUM_KHR;
|
||||
/// Output image format. Used as pipeline state, but also to
|
||||
/// determine the sRGB-ness of the format.
|
||||
VkFormat dstFormat = VK_FORMAT_UNDEFINED;
|
||||
/// Bit indicating whether the input and output dimensions match.
|
||||
VkBool32 needsBlit = VK_FALSE;
|
||||
/// Bit indicating whether a gamma curve is to be applied.
|
||||
VkBool32 needsGamma = VK_FALSE;
|
||||
|
||||
size_t hash() const {
|
||||
DxvkHashState hash;
|
||||
hash.add(uint32_t(srcSpace));
|
||||
hash.add(uint32_t(srcSamples));
|
||||
hash.add(uint32_t(srcIsSrgb));
|
||||
hash.add(uint32_t(dstSpace));
|
||||
hash.add(uint32_t(dstFormat));
|
||||
hash.add(uint32_t(needsBlit));
|
||||
hash.add(uint32_t(needsGamma));
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool eq(const DxvkSwapchainPipelineKey& other) const {
|
||||
return srcSpace == other.srcSpace
|
||||
&& srcSamples == other.srcSamples
|
||||
&& srcIsSrgb == other.srcIsSrgb
|
||||
&& dstSpace == other.dstSpace
|
||||
&& dstFormat == other.dstFormat
|
||||
&& needsBlit == other.needsBlit
|
||||
&& needsGamma == other.needsGamma;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Swap chain blitter
|
||||
*
|
||||
@ -26,21 +82,39 @@ namespace dxvk {
|
||||
~DxvkSwapchainBlitter();
|
||||
|
||||
/**
|
||||
* \brief Records presentation commands
|
||||
* \brief Begins recording presentation commands
|
||||
*
|
||||
* \param [in] ctx Context
|
||||
* Sets up the swap chain image and all internal resources, and
|
||||
* blits the source image onto the swap chain appropriately.
|
||||
* The swap chain image will remain bound for rendering.
|
||||
* \param [in] ctx Context objects
|
||||
* \param [in] dstView Swap chain image view
|
||||
* \param [in] srcView Image to present
|
||||
* \param [in] dstColorSpace Swap chain color space
|
||||
* \param [in] dstRect Destination rectangle
|
||||
* \param [in] srcRect Back buffer rectangle
|
||||
* \param [in] srcView Image to present
|
||||
* \param [in] srcColorSpace Image color space
|
||||
* \param [in] srcRect Source rectangle to present
|
||||
*/
|
||||
void presentImage(
|
||||
DxvkContext* ctx,
|
||||
void beginPresent(
|
||||
const DxvkContextObjects& ctx,
|
||||
const Rc<DxvkImageView>& dstView,
|
||||
VkColorSpaceKHR dstColorSpace,
|
||||
VkRect2D dstRect,
|
||||
const Rc<DxvkImageView>& srcView,
|
||||
VkColorSpaceKHR srcColorSpace,
|
||||
VkRect2D srcRect);
|
||||
|
||||
/**
|
||||
* \brief Finalizes presentation commands
|
||||
*
|
||||
* Finishes rendering and prepares the image for presentation.
|
||||
* \param [in] ctx Context objects
|
||||
* \param [in] dstView Swap chain image view
|
||||
*/
|
||||
void endPresent(
|
||||
const DxvkContextObjects& ctx,
|
||||
const Rc<DxvkImageView>& dstView);
|
||||
|
||||
/**
|
||||
* \brief Sets gamma ramp
|
||||
*
|
||||
@ -56,62 +130,71 @@ namespace dxvk {
|
||||
|
||||
private:
|
||||
|
||||
enum BindingIds : uint32_t {
|
||||
Image = 0,
|
||||
Gamma = 1,
|
||||
struct SpecConstants {
|
||||
VkSampleCountFlagBits sampleCount;
|
||||
VkBool32 gammaBound;
|
||||
VkColorSpaceKHR srcSpace;
|
||||
VkBool32 srcIsSrgb;
|
||||
VkColorSpaceKHR dstSpace;
|
||||
VkBool32 dstIsSrgb;
|
||||
};
|
||||
|
||||
struct PresenterArgs {
|
||||
struct PushConstants {
|
||||
VkOffset2D srcOffset;
|
||||
union {
|
||||
VkExtent2D srcExtent;
|
||||
VkOffset2D dstOffset;
|
||||
};
|
||||
VkExtent2D srcExtent;
|
||||
VkOffset2D dstOffset;
|
||||
};
|
||||
|
||||
struct ShaderModule {
|
||||
VkShaderModuleCreateInfo moduleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
|
||||
VkPipelineShaderStageCreateInfo stageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
|
||||
};
|
||||
|
||||
Rc<DxvkDevice> m_device;
|
||||
|
||||
Rc<DxvkShader> m_fsCopy;
|
||||
Rc<DxvkShader> m_fsBlit;
|
||||
Rc<DxvkShader> m_fsResolve;
|
||||
Rc<DxvkShader> m_vs;
|
||||
ShaderModule m_shaderVsBlit;
|
||||
ShaderModule m_shaderFsCopy;
|
||||
ShaderModule m_shaderFsBlit;
|
||||
ShaderModule m_shaderFsMsResolve;
|
||||
ShaderModule m_shaderFsMsBlit;
|
||||
|
||||
dxvk::mutex m_mutex;
|
||||
Rc<DxvkBuffer> m_gammaBuffer;
|
||||
Rc<DxvkImage> m_gammaImage;
|
||||
Rc<DxvkImageView> m_gammaView;
|
||||
uint32_t m_gammaCpCount = 0;
|
||||
bool m_gammaDirty = false;
|
||||
Rc<DxvkResourceAllocation> m_gammaSlice = { };
|
||||
|
||||
Rc<DxvkImage> m_resolveImage;
|
||||
Rc<DxvkImageView> m_resolveView;
|
||||
|
||||
Rc<DxvkSampler> m_samplerPresent;
|
||||
Rc<DxvkSampler> m_samplerGamma;
|
||||
|
||||
void draw(
|
||||
DxvkContext* ctx,
|
||||
const Rc<DxvkShader>& fs,
|
||||
const Rc<DxvkImageView>& dstView,
|
||||
VkRect2D dstRect,
|
||||
const Rc<DxvkImageView>& srcView,
|
||||
VkRect2D srcRect);
|
||||
VkDescriptorSetLayout m_setLayout = VK_NULL_HANDLE;
|
||||
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
|
||||
|
||||
void resolve(
|
||||
DxvkContext* ctx,
|
||||
const Rc<DxvkImageView>& dstView,
|
||||
const Rc<DxvkImageView>& srcView);
|
||||
std::unordered_map<DxvkSwapchainPipelineKey,
|
||||
VkPipeline, DxvkHash, DxvkEq> m_pipelines;
|
||||
|
||||
void updateGammaTexture(DxvkContext* ctx);
|
||||
void uploadGammaImage(
|
||||
const DxvkContextObjects& ctx);
|
||||
|
||||
void createSampler();
|
||||
|
||||
void createShaders();
|
||||
|
||||
void createResolveImage(
|
||||
const DxvkImageCreateInfo& info);
|
||||
void createShaderModule(
|
||||
ShaderModule& shader,
|
||||
VkShaderStageFlagBits stage,
|
||||
size_t size,
|
||||
const uint32_t* code);
|
||||
|
||||
void destroyResolveImage();
|
||||
VkDescriptorSetLayout createSetLayout();
|
||||
|
||||
VkPipelineLayout createPipelineLayout();
|
||||
|
||||
VkPipeline createPipeline(
|
||||
const DxvkSwapchainPipelineKey& key);
|
||||
|
||||
VkPipeline getPipeline(
|
||||
const DxvkSwapchainPipelineKey& key);
|
||||
|
||||
};
|
||||
|
||||
|
@ -37,6 +37,7 @@ dxvk_shaders = files([
|
||||
'shaders/dxvk_present_frag_blit.frag',
|
||||
'shaders/dxvk_present_frag_ms.frag',
|
||||
'shaders/dxvk_present_frag_ms_amd.frag',
|
||||
'shaders/dxvk_present_frag_ms_blit.frag',
|
||||
'shaders/dxvk_present_vert.vert',
|
||||
|
||||
'shaders/dxvk_resolve_frag_d.frag',
|
||||
|
81
src/dxvk/shaders/dxvk_color_space.glsl
Normal file
81
src/dxvk/shaders/dxvk_color_space.glsl
Normal file
@ -0,0 +1,81 @@
|
||||
#define VK_COLOR_SPACE_SRGB_NONLINEAR_KHR (0)
|
||||
#define VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT (1000104002)
|
||||
#define VK_COLOR_SPACE_HDR10_ST2084_EXT (1000104008)
|
||||
#define VK_COLOR_SPACE_PASS_THROUGH_EXT (1000104013)
|
||||
|
||||
#define SDR_NITS (203.0f)
|
||||
|
||||
const mat3 rec709_to_xyz = mat3(
|
||||
0.4123908, 0.2126390, 0.0193308,
|
||||
0.3575843, 0.7151687, 0.1191948,
|
||||
0.1804808, 0.0721923, 0.9505322);
|
||||
|
||||
const mat3 xyz_to_rec2020 = mat3(
|
||||
1.7166512, -0.6666844, 0.0176399,
|
||||
-0.3556708, 1.6164812, -0.0427706,
|
||||
-0.2533663, 0.0157685, 0.9421031);
|
||||
|
||||
mat3 rec709_to_rec2020 = xyz_to_rec2020 * rec709_to_xyz;
|
||||
mat3 rec2020_to_rec709 = inverse(rec709_to_rec2020);
|
||||
|
||||
|
||||
// sRGB functions
|
||||
vec3 linear_to_srgb(vec3 linear) {
|
||||
bvec3 isLo = lessThanEqual(linear, vec3(0.0031308f));
|
||||
|
||||
vec3 loPart = linear * 12.92f;
|
||||
vec3 hiPart = pow(linear, vec3(5.0f / 12.0f)) * 1.055f - 0.055f;
|
||||
return mix(hiPart, loPart, isLo);
|
||||
}
|
||||
|
||||
vec3 srgb_to_linear(vec3 srgb) {
|
||||
bvec3 isLo = lessThanEqual(srgb, vec3(0.04045f));
|
||||
|
||||
vec3 loPart = srgb / 12.92f;
|
||||
vec3 hiPart = pow((srgb + 0.055f) / 1.055f, vec3(12.0f / 5.0f));
|
||||
return mix(hiPart, loPart, isLo);
|
||||
}
|
||||
|
||||
|
||||
// Perceptual quantizer conversion
|
||||
vec3 nits_to_pq(vec3 nits) {
|
||||
const float c1 = 0.8359375f;
|
||||
const float c2 = 18.8515625f;
|
||||
const float c3 = 18.6875f;
|
||||
const float m1 = 0.1593017578125f;
|
||||
const float m2 = 78.84375f;
|
||||
|
||||
vec3 y = clamp(nits / 10000.0f, vec3(0.0f), vec3(1.0f));
|
||||
vec3 y_m1 = pow(y, vec3(m1));
|
||||
|
||||
vec3 num = c1 + c2 * y_m1;
|
||||
vec3 den = 1.0f + c3 * y_m1;
|
||||
|
||||
return pow(num / den, vec3(m2));
|
||||
}
|
||||
|
||||
vec3 pq_to_nits(vec3 pq) {
|
||||
const float c1 = 0.8359375f;
|
||||
const float c2 = 18.8515625f;
|
||||
const float c3 = 18.6875f;
|
||||
const float m1 = 0.1593017578125f;
|
||||
const float m2 = 78.84375f;
|
||||
|
||||
vec3 pq_m2 = pow(pq, vec3(1.0f / m2));
|
||||
|
||||
vec3 num = max(pq_m2 - c1, 0.0f);
|
||||
vec3 den = c2 - c3 * pq_m2;
|
||||
|
||||
vec3 y = pow(num / den, vec3(1.0f / m1));
|
||||
return 10000.0f * y;
|
||||
}
|
||||
|
||||
|
||||
// scRGB conversion
|
||||
vec3 nits_to_sc_rgb(vec3 nits) {
|
||||
return nits / 80.0f;
|
||||
}
|
||||
|
||||
vec3 sc_rgb_to_nits(vec3 sc_rgb) {
|
||||
return sc_rgb * 80.0f;
|
||||
}
|
100
src/dxvk/shaders/dxvk_present_common.glsl
Normal file
100
src/dxvk/shaders/dxvk_present_common.glsl
Normal file
@ -0,0 +1,100 @@
|
||||
#include "dxvk_color_space.glsl"
|
||||
|
||||
layout(constant_id = 0) const uint c_samples = 0u;
|
||||
layout(constant_id = 1) const bool c_gamma = false;
|
||||
|
||||
layout(constant_id = 2) const uint c_src_color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
layout(constant_id = 3) const bool c_src_is_srgb = true;
|
||||
layout(constant_id = 4) const uint c_dst_color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
layout(constant_id = 5) const bool c_dst_is_srgb = true;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D s_image;
|
||||
layout(set = 0, binding = 0) uniform sampler2DMS s_image_ms;
|
||||
layout(set = 0, binding = 1) uniform sampler1D s_gamma;
|
||||
|
||||
layout(push_constant)
|
||||
uniform present_info_t {
|
||||
ivec2 src_offset;
|
||||
ivec2 src_extent;
|
||||
ivec2 dst_offset;
|
||||
};
|
||||
|
||||
vec4 input_to_sc_rgb(vec4 color) {
|
||||
switch (c_src_color_space) {
|
||||
default:
|
||||
case VK_COLOR_SPACE_PASS_THROUGH_EXT:
|
||||
return color;
|
||||
|
||||
case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: {
|
||||
if (!c_src_is_srgb)
|
||||
color.rgb = srgb_to_linear(color.rgb);
|
||||
|
||||
color.rgb = nits_to_sc_rgb(color.rgb * SDR_NITS);
|
||||
return color;
|
||||
}
|
||||
|
||||
case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
|
||||
return color;
|
||||
|
||||
case VK_COLOR_SPACE_HDR10_ST2084_EXT:
|
||||
color.rgb = nits_to_sc_rgb(pq_to_nits(color.rgb));
|
||||
color.rgb = rec2020_to_rec709 * color.rgb;
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vec4 sc_rgb_to_output(vec4 color) {
|
||||
if (c_gamma) {
|
||||
// If we need to apply a gamma curve, convert to sRGB, perform
|
||||
// the lookup, and then convert back to scRGB as necessary
|
||||
if (c_src_color_space != VK_COLOR_SPACE_PASS_THROUGH_EXT) {
|
||||
color.rgb = sc_rgb_to_nits(color.rgb) / SDR_NITS;
|
||||
color.rgb = linear_to_srgb(color.rgb);
|
||||
} else if (c_src_is_srgb) {
|
||||
color.rgb = linear_to_srgb(color.rgb);
|
||||
}
|
||||
|
||||
color.rgb = vec3(
|
||||
texture(s_gamma, color.r).r,
|
||||
texture(s_gamma, color.g).g,
|
||||
texture(s_gamma, color.b).b);
|
||||
|
||||
if (c_dst_color_space != VK_COLOR_SPACE_PASS_THROUGH_EXT) {
|
||||
color.rgb = srgb_to_linear(color.rgb);
|
||||
color.rgb = nits_to_sc_rgb(color.rgb * SDR_NITS);
|
||||
} else if (c_dst_is_srgb) {
|
||||
color.rgb = srgb_to_linear(color.rgb);
|
||||
}
|
||||
}
|
||||
|
||||
switch (c_dst_color_space) {
|
||||
default:
|
||||
case VK_COLOR_SPACE_PASS_THROUGH_EXT:
|
||||
// If we applied a gamma curve, the output is already correct
|
||||
if (!c_gamma && c_src_is_srgb != c_dst_is_srgb) {
|
||||
color.rgb = c_src_is_srgb
|
||||
? linear_to_srgb(color.rgb)
|
||||
: srgb_to_linear(color.rgb);
|
||||
}
|
||||
|
||||
return color;
|
||||
|
||||
case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: {
|
||||
color.rgb = sc_rgb_to_nits(color.rgb) / SDR_NITS;
|
||||
|
||||
if (!c_dst_is_srgb)
|
||||
color.rgb = linear_to_srgb(color.rgb);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
|
||||
return color;
|
||||
|
||||
case VK_COLOR_SPACE_HDR10_ST2084_EXT:
|
||||
color.rgb = rec709_to_rec2020 * color.rgb;
|
||||
color.rgb = nits_to_pq(sc_rgb_to_nits(color.rgb));
|
||||
return color;
|
||||
}
|
||||
}
|
@ -1,27 +1,14 @@
|
||||
#version 450
|
||||
|
||||
layout(constant_id = 1) const bool s_gamma_bound = false;
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
layout(binding = 0) uniform sampler2D s_image;
|
||||
layout(binding = 1) uniform sampler1D s_gamma;
|
||||
#include "dxvk_present_common.glsl"
|
||||
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
layout(push_constant)
|
||||
uniform present_info_t {
|
||||
ivec2 src_offset;
|
||||
ivec2 dst_offset;
|
||||
};
|
||||
|
||||
void main() {
|
||||
ivec2 coord = ivec2(gl_FragCoord.xy) + src_offset - dst_offset;
|
||||
o_color = texelFetch(s_image, coord, 0);
|
||||
|
||||
if (s_gamma_bound) {
|
||||
o_color = vec4(
|
||||
texture(s_gamma, o_color.r).r,
|
||||
texture(s_gamma, o_color.g).g,
|
||||
texture(s_gamma, o_color.b).b,
|
||||
o_color.a);
|
||||
}
|
||||
}
|
||||
|
||||
o_color = input_to_sc_rgb(texelFetch(s_image, coord, 0));
|
||||
o_color = sc_rgb_to_output(o_color);
|
||||
}
|
||||
|
@ -1,28 +1,14 @@
|
||||
#version 450
|
||||
|
||||
layout(constant_id = 1) const bool s_gamma_bound = false;
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
layout(binding = 0) uniform sampler2D s_image;
|
||||
layout(binding = 1) uniform sampler1D s_gamma;
|
||||
#include "dxvk_present_common.glsl"
|
||||
|
||||
layout(location = 0) in vec2 i_coord;
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
layout(push_constant)
|
||||
uniform present_info_t {
|
||||
ivec2 src_offset;
|
||||
uvec2 src_extent;
|
||||
};
|
||||
|
||||
void main() {
|
||||
vec2 coord = vec2(src_offset) + vec2(src_extent) * i_coord;
|
||||
o_color = textureLod(s_image, coord, 0.0f);
|
||||
|
||||
if (s_gamma_bound) {
|
||||
o_color = vec4(
|
||||
texture(s_gamma, o_color.r).r,
|
||||
texture(s_gamma, o_color.g).g,
|
||||
texture(s_gamma, o_color.b).b,
|
||||
o_color.a);
|
||||
}
|
||||
}
|
||||
o_color = input_to_sc_rgb(textureLod(s_image, coord, 0.0f));
|
||||
o_color = sc_rgb_to_output(o_color);
|
||||
}
|
||||
|
@ -1,33 +1,17 @@
|
||||
#version 450
|
||||
|
||||
layout(constant_id = 0) const uint c_samples = 0;
|
||||
layout(constant_id = 1) const bool s_gamma_bound = false;
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
layout(binding = 0) uniform sampler2DMS s_image;
|
||||
layout(binding = 1) uniform sampler1D s_gamma;
|
||||
#include "dxvk_present_common.glsl"
|
||||
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
layout(push_constant)
|
||||
uniform present_info_t {
|
||||
ivec2 src_offset;
|
||||
ivec2 dst_offset;
|
||||
};
|
||||
|
||||
void main() {
|
||||
ivec2 coord = ivec2(gl_FragCoord.xy) + src_offset - dst_offset;
|
||||
o_color = texelFetch(s_image, coord, 0);
|
||||
o_color = input_to_sc_rgb(texelFetch(s_image_ms, coord, 0));
|
||||
|
||||
for (uint i = 1; i < c_samples; i++)
|
||||
o_color += texelFetch(s_image, coord, int(i));
|
||||
o_color += input_to_sc_rgb(texelFetch(s_image_ms, coord, int(i)));
|
||||
|
||||
o_color /= float(c_samples);
|
||||
|
||||
if (s_gamma_bound) {
|
||||
o_color = vec4(
|
||||
texture(s_gamma, o_color.r).r,
|
||||
texture(s_gamma, o_color.g).g,
|
||||
texture(s_gamma, o_color.b).b,
|
||||
o_color.a);
|
||||
}
|
||||
}
|
||||
o_color = sc_rgb_to_output(o_color / float(c_samples));
|
||||
}
|
||||
|
@ -1,26 +1,17 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_AMD_shader_fragment_mask: enable
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
#extension GL_AMD_shader_fragment_mask : enable
|
||||
|
||||
layout(constant_id = 0) const uint c_samples = 0;
|
||||
layout(constant_id = 1) const bool s_gamma_bound = false;
|
||||
|
||||
layout(binding = 0) uniform sampler2DMS s_image;
|
||||
layout(binding = 1) uniform sampler1D s_gamma;
|
||||
#include "dxvk_present_common.glsl"
|
||||
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
layout(push_constant)
|
||||
uniform present_info_t {
|
||||
ivec2 src_offset;
|
||||
ivec2 dst_offset;
|
||||
};
|
||||
|
||||
void main() {
|
||||
ivec2 coord = ivec2(gl_FragCoord.xy) + src_offset - dst_offset;
|
||||
|
||||
// check dxvk_resolve_frag_f_amd.frag for documentation
|
||||
uint fragMask = fragmentMaskFetchAMD(s_image, coord);
|
||||
uint fragMask = fragmentMaskFetchAMD(s_image_ms, coord);
|
||||
uint fragCount = 0u;
|
||||
|
||||
for (int i = 0; i < 4 * c_samples; i += 4) {
|
||||
@ -34,19 +25,11 @@ void main() {
|
||||
int fragIndex = findLSB(fragCount) >> 2;
|
||||
int fragShift = fragIndex << 2;
|
||||
|
||||
o_color += fragmentFetchAMD(s_image, coord, fragIndex)
|
||||
o_color += input_to_sc_rgb(fragmentFetchAMD(s_image_ms, coord, fragIndex))
|
||||
* float(bitfieldExtract(fragCount, fragShift, 4));
|
||||
|
||||
fragCount = bitfieldInsert(fragCount, 0, fragShift, 4);
|
||||
}
|
||||
|
||||
o_color /= float(c_samples);
|
||||
|
||||
if (s_gamma_bound) {
|
||||
o_color = vec4(
|
||||
texture(s_gamma, o_color.r).r,
|
||||
texture(s_gamma, o_color.g).g,
|
||||
texture(s_gamma, o_color.b).b,
|
||||
o_color.a);
|
||||
}
|
||||
}
|
||||
o_color = sc_rgb_to_output(o_color / float(c_samples));
|
||||
}
|
||||
|
65
src/dxvk/shaders/dxvk_present_frag_ms_blit.frag
Normal file
65
src/dxvk/shaders/dxvk_present_frag_ms_blit.frag
Normal file
@ -0,0 +1,65 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
#include "dxvk_present_common.glsl"
|
||||
|
||||
layout(location = 0) in vec2 i_coord;
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
const vec2 sample_positions[] = {
|
||||
/* 2 samples */
|
||||
vec2( 0.25f, 0.25f),
|
||||
vec2(-0.25f,-0.25f),
|
||||
/* 4 samples */
|
||||
vec2(-0.125f,-0.375f),
|
||||
vec2( 0.375f,-0.125f),
|
||||
vec2(-0.375f, 0.125f),
|
||||
vec2( 0.125f, 0.375f),
|
||||
/* 8 samples */
|
||||
vec2( 0.0625f,-0.1875f),
|
||||
vec2(-0.0625f, 0.1875f),
|
||||
vec2( 0.3125f, 0.0625f),
|
||||
vec2(-0.1875f,-0.3125f),
|
||||
vec2(-0.3125f, 0.3125f),
|
||||
vec2(-0.4375f,-0.0625f),
|
||||
vec2( 0.1875f, 0.4375f),
|
||||
vec2( 0.4375f,-0.4375f),
|
||||
/* 16 samples */
|
||||
vec2( 0.0625f, 0.0625f),
|
||||
vec2(-0.0625f,-0.1875f),
|
||||
vec2(-0.1875f, 0.1250f),
|
||||
vec2( 0.2500f,-0.0625f),
|
||||
vec2(-0.3125f,-0.1250f),
|
||||
vec2( 0.1250f, 0.3125f),
|
||||
vec2( 0.3125f, 0.1875f),
|
||||
vec2( 0.1875f,-0.3125f),
|
||||
vec2(-0.1250f, 0.3750f),
|
||||
vec2( 0.0000f,-0.4375f),
|
||||
vec2(-0.2500f,-0.3750f),
|
||||
vec2(-0.3750f, 0.2500f),
|
||||
vec2(-0.5000f, 0.0000f),
|
||||
vec2( 0.4375f,-0.2500f),
|
||||
vec2( 0.3750f, 0.4375f),
|
||||
vec2(-0.4375f,-0.5000f),
|
||||
};
|
||||
|
||||
void main() {
|
||||
vec2 coord = vec2(src_offset) + vec2(src_extent) * i_coord;
|
||||
|
||||
ivec2 cint = ivec2(coord);
|
||||
vec2 cfrac = fract(coord) - 0.5f;
|
||||
|
||||
uint pos_index = c_samples - 2u;
|
||||
|
||||
o_color = vec4(0.0f);
|
||||
|
||||
for (uint i = 0; i < c_samples; i++) {
|
||||
vec2 sample_pos = sample_positions[pos_index + i];
|
||||
|
||||
ivec2 coffset = ivec2(greaterThan(cfrac - sample_pos, vec2(0.5f)));
|
||||
o_color += input_to_sc_rgb(texelFetch(s_image_ms, cint + coffset, int(i)));
|
||||
}
|
||||
|
||||
o_color = sc_rgb_to_output(o_color / float(c_samples));
|
||||
}
|
Loading…
Reference in New Issue
Block a user