mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-04 07:24:15 +01:00
[dxvk] Add support for drawing a software cursor
This commit is contained in:
parent
4420c39b62
commit
329d9a0bb2
@ -443,7 +443,7 @@ namespace dxvk {
|
||||
cHud->render(contextObjects, cBackBuffer, cColorSpace);
|
||||
}
|
||||
|
||||
cBlitter->endPresent(contextObjects, cBackBuffer);
|
||||
cBlitter->endPresent(contextObjects, cBackBuffer, cColorSpace);
|
||||
|
||||
// Submit current command list and present
|
||||
ctx->synchronizeWsi(cSync);
|
||||
|
@ -880,7 +880,7 @@ namespace dxvk {
|
||||
cHud->render(contextObjects, cDstView, cColorSpace);
|
||||
}
|
||||
|
||||
cBlitter->endPresent(contextObjects, cDstView);
|
||||
cBlitter->endPresent(contextObjects, cDstView, cColorSpace);
|
||||
|
||||
// Submit command list and present
|
||||
ctx->synchronizeWsi(cSync);
|
||||
|
@ -63,6 +63,9 @@ namespace dxvk {
|
||||
if (m_gammaBuffer)
|
||||
uploadGammaImage(ctx);
|
||||
|
||||
if (m_cursorBuffer)
|
||||
uploadCursorImage(ctx);
|
||||
|
||||
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;
|
||||
@ -99,85 +102,29 @@ namespace dxvk {
|
||||
|
||||
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(DxvkCmdBuffer::ExecBuffer,
|
||||
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;
|
||||
}
|
||||
|
||||
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(DxvkCmdBuffer::ExecBuffer,
|
||||
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(DxvkCmdBuffer::ExecBuffer,
|
||||
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);
|
||||
performDraw(ctx,
|
||||
dstView, dstColorSpace, dstRect,
|
||||
srcView, srcColorSpace, srcRect,
|
||||
VK_FALSE);
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::endPresent(
|
||||
const DxvkContextObjects& ctx,
|
||||
const Rc<DxvkImageView>& dstView) {
|
||||
const Rc<DxvkImageView>& dstView,
|
||||
VkColorSpaceKHR dstColorSpace) {
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
||||
if (m_cursorView) {
|
||||
VkRect2D cursorArea = { };
|
||||
cursorArea.extent.width = m_cursorImage->info().extent.width;
|
||||
cursorArea.extent.height = m_cursorImage->info().extent.height;
|
||||
|
||||
performDraw(ctx, dstView, dstColorSpace, m_cursorRect,
|
||||
m_cursorView, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, cursorArea,
|
||||
VK_TRUE);
|
||||
}
|
||||
|
||||
ctx.cmd->cmdEndRendering();
|
||||
|
||||
VkImageMemoryBarrier2 barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
|
||||
@ -228,6 +175,182 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::setCursorTexture(
|
||||
VkExtent2D extent,
|
||||
VkFormat format,
|
||||
const void* data) {
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
||||
if (extent.width && extent.height && format && data) {
|
||||
auto formatInfo = lookupFormatInfo(format);
|
||||
|
||||
DxvkBufferCreateInfo bufferInfo = { };
|
||||
bufferInfo.size = extent.width * extent.height * formatInfo->elementSize;
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufferInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
bufferInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
|
||||
m_cursorBuffer = m_device->createBuffer(bufferInfo,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
std::memcpy(m_cursorBuffer->mapPtr(0), data, bufferInfo.size);
|
||||
|
||||
DxvkImageCreateInfo imageInfo = { };
|
||||
imageInfo.type = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.format = format;
|
||||
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.extent = { extent.width, extent.height, 1u };
|
||||
imageInfo.numLayers = 1u;
|
||||
imageInfo.mipLevels = 1u;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
imageInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT
|
||||
| VK_ACCESS_TRANSFER_READ_BIT
|
||||
| VK_ACCESS_SHADER_READ_BIT;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
m_cursorImage = m_device->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
DxvkImageViewKey viewInfo = { };
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
viewInfo.format = format;
|
||||
viewInfo.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.mipIndex = 0u;
|
||||
viewInfo.mipCount = 1u;
|
||||
viewInfo.layerIndex = 0u;
|
||||
viewInfo.layerCount = 1u;
|
||||
|
||||
m_cursorView = m_cursorImage->createView(viewInfo);
|
||||
} else {
|
||||
// Destroy cursor image
|
||||
m_cursorBuffer = nullptr;
|
||||
m_cursorImage = nullptr;
|
||||
m_cursorView = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::setCursorPos(
|
||||
VkRect2D rect) {
|
||||
std::unique_lock lock(m_mutex);
|
||||
m_cursorRect = rect;
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::performDraw(
|
||||
const DxvkContextObjects& ctx,
|
||||
const Rc<DxvkImageView>& dstView,
|
||||
VkColorSpaceKHR dstColorSpace,
|
||||
VkRect2D dstRect,
|
||||
const Rc<DxvkImageView>& srcView,
|
||||
VkColorSpaceKHR srcColorSpace,
|
||||
VkRect2D srcRect,
|
||||
VkBool32 enableBlending) {
|
||||
VkExtent3D dstExtent = dstView->mipLevelExtent(0);
|
||||
|
||||
VkOffset2D coordA = dstRect.offset;
|
||||
VkOffset2D coordB = {
|
||||
coordA.x + int32_t(dstRect.extent.width),
|
||||
coordA.y + int32_t(dstRect.extent.height)
|
||||
};
|
||||
|
||||
coordA.x = std::max(coordA.x, 0);
|
||||
coordA.y = std::max(coordA.y, 0);
|
||||
coordB.x = std::min(coordB.x, int32_t(dstExtent.width));
|
||||
coordB.y = std::min(coordB.y, int32_t(dstExtent.height));
|
||||
|
||||
if (coordA.x >= coordB.x || coordA.y >= coordB.y)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
VkRect2D scissor = { };
|
||||
scissor.offset = coordA;
|
||||
scissor.extent.width = uint32_t(coordB.x - coordA.x);
|
||||
scissor.extent.height = uint32_t(coordB.y - coordA.y);
|
||||
|
||||
ctx.cmd->cmdSetScissor(1, &scissor);
|
||||
|
||||
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;
|
||||
key.needsBlending = enableBlending;
|
||||
|
||||
VkPipeline pipeline = getPipeline(key);
|
||||
|
||||
ctx.cmd->cmdBindPipeline(DxvkCmdBuffer::ExecBuffer,
|
||||
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;
|
||||
}
|
||||
|
||||
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(DxvkCmdBuffer::ExecBuffer,
|
||||
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(DxvkCmdBuffer::ExecBuffer,
|
||||
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::uploadGammaImage(
|
||||
const DxvkContextObjects& ctx) {
|
||||
if (!m_gammaImage || m_gammaImage->info().extent.width != m_gammaCpCount) {
|
||||
@ -266,6 +389,13 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::uploadCursorImage(
|
||||
const DxvkContextObjects& ctx) {
|
||||
uploadTexture(ctx, m_cursorImage, m_cursorBuffer);
|
||||
m_cursorBuffer = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchainBlitter::uploadTexture(
|
||||
const DxvkContextObjects& ctx,
|
||||
const Rc<DxvkImage>& image,
|
||||
|
@ -114,10 +114,12 @@ namespace dxvk {
|
||||
* Finishes rendering and prepares the image for presentation.
|
||||
* \param [in] ctx Context objects
|
||||
* \param [in] dstView Swap chain image view
|
||||
* \param [in] dstColorSpace Swap chain color space
|
||||
*/
|
||||
void endPresent(
|
||||
const DxvkContextObjects& ctx,
|
||||
const Rc<DxvkImageView>& dstView);
|
||||
const Rc<DxvkImageView>& dstView,
|
||||
VkColorSpaceKHR dstColorSpace);
|
||||
|
||||
/**
|
||||
* \brief Sets gamma ramp
|
||||
@ -132,6 +134,30 @@ namespace dxvk {
|
||||
uint32_t cpCount,
|
||||
const DxvkGammaCp* cpData);
|
||||
|
||||
/**
|
||||
* \brief Sets software cursor texture
|
||||
*
|
||||
* The cursor image is assumed to be in sRGB color space.
|
||||
* \param [in] extent Texture size, in pixels
|
||||
* \param [in] format Texture format
|
||||
* \param [in] data Texture data. Assumed to be
|
||||
* tightly packed according to the format.
|
||||
*/
|
||||
void setCursorTexture(
|
||||
VkExtent2D extent,
|
||||
VkFormat format,
|
||||
const void* data);
|
||||
|
||||
/**
|
||||
* \brief Sets cursor position
|
||||
*
|
||||
* If the size does not match the texture size, the
|
||||
* cursor will be rendered with a linear filter.
|
||||
* \param [in] rect Cursor rectangle, in pixels
|
||||
*/
|
||||
void setCursorPos(
|
||||
VkRect2D rect);
|
||||
|
||||
private:
|
||||
|
||||
struct SpecConstants {
|
||||
@ -168,6 +194,11 @@ namespace dxvk {
|
||||
Rc<DxvkImageView> m_gammaView;
|
||||
uint32_t m_gammaCpCount = 0;
|
||||
|
||||
Rc<DxvkBuffer> m_cursorBuffer;
|
||||
Rc<DxvkImage> m_cursorImage;
|
||||
Rc<DxvkImageView> m_cursorView;
|
||||
VkRect2D m_cursorRect = { };
|
||||
|
||||
Rc<DxvkSampler> m_samplerPresent;
|
||||
Rc<DxvkSampler> m_samplerGamma;
|
||||
|
||||
@ -177,6 +208,16 @@ namespace dxvk {
|
||||
std::unordered_map<DxvkSwapchainPipelineKey,
|
||||
VkPipeline, DxvkHash, DxvkEq> m_pipelines;
|
||||
|
||||
void performDraw(
|
||||
const DxvkContextObjects& ctx,
|
||||
const Rc<DxvkImageView>& dstView,
|
||||
VkColorSpaceKHR dstColorSpace,
|
||||
VkRect2D dstRect,
|
||||
const Rc<DxvkImageView>& srcView,
|
||||
VkColorSpaceKHR srcColorSpace,
|
||||
VkRect2D srcRect,
|
||||
VkBool32 enableBlending);
|
||||
|
||||
void uploadGammaImage(
|
||||
const DxvkContextObjects& ctx);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user