[dxvk] Implemented shader resource binding

This commit is contained in:
Philip Rebohle 2017-12-03 20:23:26 +01:00
parent a6bf7659b0
commit b5d068366d
28 changed files with 778 additions and 140 deletions

View File

@ -33,6 +33,26 @@ namespace dxvk {
m_acquireSync = m_device->createSemaphore();
m_presentSync = m_device->createSemaphore();
// Sampler for presentation
DxvkSamplerCreateInfo samplerInfo;
samplerInfo.magFilter = VK_FILTER_NEAREST;
samplerInfo.minFilter = VK_FILTER_NEAREST;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
samplerInfo.mipmapLodBias = 0.0f;
samplerInfo.mipmapLodMin = 0.0f;
samplerInfo.mipmapLodMax = 0.0f;
samplerInfo.useAnisotropy = VK_FALSE;
samplerInfo.maxAnisotropy = 1.0f;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
samplerInfo.compareToDepth = VK_FALSE;
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
samplerInfo.usePixelCoord = VK_FALSE;
m_sampler = m_device->createSampler(samplerInfo);
// Set up context state. The shader bindings and the
// constant state objects will never be modified.
m_context->bindGraphicsPipeline(createPipeline());
@ -133,9 +153,12 @@ namespace dxvk {
m_context->setViewports(1, &viewport, &scissor);
// TODO bind back buffer as a shader resource
// m_context->bindSampler(0, m_sampler);
// m_context->bindSampledImage(1, view);
m_context->bindResourceSampler(
VK_PIPELINE_BIND_POINT_GRAPHICS,
BindingIds::Sampler, m_sampler);
m_context->bindResourceImage(
VK_PIPELINE_BIND_POINT_GRAPHICS,
BindingIds::Texture, view);
m_context->draw(4, 1, 0, 0);
m_device->submitCommandList(
@ -279,10 +302,26 @@ namespace dxvk {
uint32_t typeVec2 = module.defVectorType(typeF32, 2);
uint32_t typeVec4 = module.defVectorType(typeF32, 4);
uint32_t typeFn = module.defFunctionType(typeVoid, 0, nullptr);
uint32_t typeSampler = module.defSamplerType();
uint32_t typeTexture = module.defImageType(
typeF32, spv::Dim2D, 0, 0, 0, 1, spv::ImageFormatUnknown);
uint32_t typeSampledTex = module.defSampledImageType(typeTexture);
// Pointer type definitions
uint32_t ptrInputVec2 = module.defPointerType(typeVec2, spv::StorageClassInput);
uint32_t ptrOutputVec4 = module.defPointerType(typeVec4, spv::StorageClassOutput);
uint32_t ptrSampler = module.defPointerType(typeSampler, spv::StorageClassUniformConstant);
uint32_t ptrTexture = module.defPointerType(typeTexture, spv::StorageClassUniformConstant);
// Sampler
uint32_t rcSampler = module.newVar(ptrSampler, spv::StorageClassUniformConstant);
module.decorateDescriptorSet(rcSampler, 0);
module.decorateBinding(rcSampler, BindingIds::Sampler);
// Texture
uint32_t rcTexture = module.newVar(ptrTexture, spv::StorageClassUniformConstant);
module.decorateDescriptorSet(rcTexture, 0);
module.decorateBinding(rcTexture, BindingIds::Texture);
// Input variable: Texture coordinates
uint32_t inTexCoord = module.newVar(
@ -299,13 +338,14 @@ namespace dxvk {
module.opLabel(module.allocateId());
// Load texture coordinates
uint32_t tmpTexCoord = module.opLoad(typeVec2, inTexCoord);
// Compute final color
uint32_t swizzleIndices[4] = { 0, 1, 2, 3 };
uint32_t tmpColor = module.opVectorShuffle(
typeVec4, tmpTexCoord, tmpTexCoord, 4, swizzleIndices);
module.opStore(outColor, tmpColor);
module.opStore(outColor,
module.opImageSampleImplicitLod(
typeVec4,
module.opSampledImage(
typeSampledTex,
module.opLoad(typeTexture, rcTexture),
module.opLoad(typeSampler, rcSampler)),
module.opLoad(typeVec2, inTexCoord)));
module.opReturn();
module.functionEnd();
@ -325,12 +365,14 @@ namespace dxvk {
Rc<DxvkBindingLayout> DxgiPresenter::createBindingLayout() {
std::array<DxvkBindingInfo, 2> bindings;
bindings.at(0).type = VK_DESCRIPTOR_TYPE_SAMPLER;
bindings.at(0).stages = VK_SHADER_STAGE_FRAGMENT_BIT;
std::array<DxvkDescriptorSlot, 2> bindings;
bindings.at(BindingIds::Sampler).slot = BindingIds::Sampler;
bindings.at(BindingIds::Sampler).type = VK_DESCRIPTOR_TYPE_SAMPLER;
bindings.at(BindingIds::Sampler).stages = VK_SHADER_STAGE_FRAGMENT_BIT;
bindings.at(1).type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
bindings.at(1).stages = VK_SHADER_STAGE_FRAGMENT_BIT;
bindings.at(BindingIds::Texture).slot = BindingIds::Texture;
bindings.at(BindingIds::Texture).type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
bindings.at(BindingIds::Texture).stages = VK_SHADER_STAGE_FRAGMENT_BIT;
return m_device->createBindingLayout(
bindings.size(), bindings.data());

View File

@ -43,6 +43,11 @@ namespace dxvk {
private:
enum BindingIds : uint32_t {
Sampler = 0,
Texture = 1,
};
Rc<DxvkDevice> m_device;
Rc<DxvkContext> m_context;
@ -52,6 +57,8 @@ namespace dxvk {
Rc<DxvkSemaphore> m_acquireSync;
Rc<DxvkSemaphore> m_presentSync;
Rc<DxvkSampler> m_sampler;
Rc<DxvkShader> createVertexShader();
Rc<DxvkShader> createFragmentShader();

View File

@ -45,9 +45,6 @@ namespace dxvk {
}
// Set initial window mode and fullscreen state
if (FAILED(this->ResizeTarget(&pDesc->BufferDesc)))
throw DxvkError("DxgiSwapChain::DxgiSwapChain: Failed to set initial display mode");
if (FAILED(this->SetFullscreenState(!pDesc->Windowed, nullptr)))
throw DxvkError("DxgiSwapChain::DxgiSwapChain: Failed to set initial fullscreen state");
@ -319,7 +316,7 @@ namespace dxvk {
DxvkImageCreateInfo imageInfo;
imageInfo.type = VK_IMAGE_TYPE_2D;
imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
imageInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
imageInfo.extent.width = m_desc.BufferDesc.Width;
imageInfo.extent.height = m_desc.BufferDesc.Height;

61
src/dxvk/dxvk_binding.h Normal file
View File

@ -0,0 +1,61 @@
#pragma once
#include "dxvk_buffer.h"
#include "dxvk_descriptor.h"
#include "dxvk_image.h"
#include "dxvk_sampler.h"
namespace dxvk {
/**
* \brief Bound shader resource
*/
struct DxvkShaderResourceSlot {
Rc<DxvkSampler> sampler;
Rc<DxvkImageView> imageView;
Rc<DxvkBufferView> bufferView;
DxvkBufferBinding bufferSlice;
};
/**
* \brief Shader resource slots
*/
class DxvkShaderResourceSlots {
public:
DxvkShaderResourceSlots() { }
DxvkShaderResourceSlots(size_t n) {
m_resources .resize(n);
m_descriptors.resize(n);
}
uint32_t descriptorCount() const {
return m_descriptors.size();
}
const DxvkDescriptorInfo* descriptors() const {
return m_descriptors.data();
}
const DxvkShaderResourceSlot& getShaderResource(uint32_t slot) const {
return m_resources.at(slot);
}
void bindShaderResource(
uint32_t slot,
const DxvkShaderResourceSlot& resource,
const DxvkDescriptorInfo& descriptor) {
m_resources .at(slot) = resource;
m_descriptors .at(slot) = descriptor;
}
private:
std::vector<DxvkShaderResourceSlot> m_resources;
std::vector<DxvkDescriptorInfo> m_descriptors;
};
}

View File

@ -60,7 +60,8 @@ namespace dxvk {
DxvkBufferView::~DxvkBufferView() {
m_vkd->vkDestroyBufferView(
m_vkd->device(), m_view, nullptr);
}
}

View File

@ -12,7 +12,6 @@ namespace dxvk {
* passed to \ref DxvkDevice::createBuffer
*/
struct DxvkBufferCreateInfo {
/// Size of the buffer, in bytes
VkDeviceSize size;
@ -25,7 +24,6 @@ namespace dxvk {
/// Allowed access patterns
VkAccessFlags access;
};
@ -36,7 +34,6 @@ namespace dxvk {
* are to \ref DxvkDevice::createBufferView
*/
struct DxvkBufferViewCreateInfo {
/// Buffer data format, like image data
VkFormat format;

View File

@ -91,6 +91,51 @@ namespace dxvk {
}
void DxvkCommandList::bindResourceDescriptors(
VkPipelineBindPoint pipeline,
VkPipelineLayout pipelineLayout,
VkDescriptorSetLayout descriptorLayout,
uint32_t descriptorCount,
const DxvkDescriptorSlot* descriptorSlots,
const DxvkDescriptorInfo* descriptorInfos) {
// Allocate a new descriptor set
VkDescriptorSet dset = m_descAlloc.alloc(descriptorLayout);
// Write data to the descriptor set
// TODO recycle vector as a class member
std::vector<VkWriteDescriptorSet> descriptorWrites;
descriptorWrites.resize(descriptorCount);
for (uint32_t i = 0; i < descriptorCount; i++) {
auto& curr = descriptorWrites.at(i);
auto& binding = descriptorSlots[i];
curr.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
curr.pNext = nullptr;
curr.dstSet = dset;
curr.dstBinding = i;
curr.dstArrayElement = 0;
curr.descriptorCount = 1;
curr.descriptorType = binding.type;
curr.pImageInfo = &descriptorInfos[binding.slot].image;
curr.pBufferInfo = &descriptorInfos[binding.slot].buffer;
curr.pTexelBufferView = &descriptorInfos[binding.slot].texelBuffer;
}
m_vkd->vkUpdateDescriptorSets(
m_vkd->device(),
descriptorWrites.size(),
descriptorWrites.data(),
0, nullptr);
// Bind descriptor set to the pipeline
m_vkd->vkCmdBindDescriptorSets(m_buffer,
pipeline, pipelineLayout, 0, 1,
&dset, 0, nullptr);
}
void DxvkCommandList::cmdBeginRenderPass(
const VkRenderPassBeginInfo* pRenderPassBegin,
VkSubpassContents contents) {

View File

@ -4,6 +4,7 @@
#include "dxvk_descriptor.h"
#include "dxvk_lifetime.h"
#include "dxvk_pipeline.h"
namespace dxvk {
@ -76,6 +77,14 @@ namespace dxvk {
*/
void reset();
void bindResourceDescriptors(
VkPipelineBindPoint pipeline,
VkPipelineLayout pipelineLayout,
VkDescriptorSetLayout descriptorLayout,
uint32_t descriptorCount,
const DxvkDescriptorSlot* descriptorSlots,
const DxvkDescriptorInfo* descriptorInfos);
void cmdBeginRenderPass(
const VkRenderPassBeginInfo* pRenderPassBegin,
VkSubpassContents contents);

View File

@ -14,7 +14,7 @@ namespace dxvk {
info.pNext = nullptr;
info.flags = 0;
info.stage = cs->stageInfo();
info.layout = this->pipelineLayout();
info.layout = m_layout->pipelineLayout();
info.basePipelineHandle = VK_NULL_HANDLE;
info.basePipelineIndex = 0;

View File

@ -25,25 +25,15 @@ namespace dxvk {
~DxvkComputePipeline();
/**
* \brief Descriptor set layout
* \brief Pipeline layout
*
* The descriptor set layout for this pipeline.
* Use this to allocate new descriptor sets.
* \returns The descriptor set layout
* Stores the pipeline layout and the descriptor set
* layout, as well as information on the resource
* slots used by the pipeline.
* \returns Pipeline layout
*/
VkDescriptorSetLayout descriptorSetLayout() const {
return m_layout->descriptorSetLayout();
}
/**
* \brief Pipeline layout layout
*
* The pipeline layout for this pipeline.
* Use this to bind descriptor sets.
* \returns The descriptor set layout
*/
VkPipelineLayout pipelineLayout() const {
return m_layout->pipelineLayout();
Rc<DxvkBindingLayout> layout() const {
return m_layout;
}
/**

View File

@ -53,6 +53,32 @@ namespace dxvk {
}
void DxvkContext::bindComputePipeline(
const Rc<DxvkComputePipeline>& pipeline) {
if (m_state.cPipe != pipeline) {
m_state.cPipe = pipeline;
m_flags.set(
DxvkContextFlag::CpDirtyPipeline,
DxvkContextFlag::CpDirtyResources);
}
}
void DxvkContext::bindGraphicsPipeline(
const Rc<DxvkGraphicsPipeline>& pipeline) {
if (m_state.gPipe != pipeline) {
m_state.gPipe = pipeline;
m_flags.set(
DxvkContextFlag::GpDirtyPipeline,
DxvkContextFlag::GpDirtyResources,
DxvkContextFlag::GpDirtyVertexBuffers,
DxvkContextFlag::GpDirtyIndexBuffer);
}
}
void DxvkContext::bindIndexBuffer(
const DxvkBufferBinding& buffer) {
if (m_state.vi.indexBuffer != buffer) {
@ -62,25 +88,93 @@ namespace dxvk {
}
void DxvkContext::bindComputePipeline(
const Rc<DxvkComputePipeline>& pipeline) {
m_state.cp = pipeline;
void DxvkContext::bindResourceBuffer(
VkPipelineBindPoint pipe,
uint32_t slot,
const DxvkBufferBinding& buffer) {
auto rc = this->getShaderResourceSlots(pipe);
m_flags.set(
DxvkContextFlag::CpDirtyPipeline,
DxvkContextFlag::CpDirtyResources);
if (rc->getShaderResource(slot).bufferSlice != buffer) {
m_flags.set(this->getResourceDirtyFlag(pipe));
DxvkShaderResourceSlot resource;
resource.bufferSlice = buffer;
DxvkDescriptorInfo descriptor;
if (buffer.bufferHandle() != VK_NULL_HANDLE)
descriptor.buffer = buffer.descriptorInfo();
rc->bindShaderResource(slot, resource, descriptor);
}
}
void DxvkContext::bindGraphicsPipeline(
const Rc<DxvkGraphicsPipeline>& pipeline) {
m_state.gp = pipeline;
void DxvkContext::bindResourceTexelBuffer(
VkPipelineBindPoint pipe,
uint32_t slot,
const Rc<DxvkBufferView>& bufferView) {
auto rc = this->getShaderResourceSlots(pipe);
m_flags.set(
DxvkContextFlag::GpDirtyPipeline,
DxvkContextFlag::GpDirtyResources,
DxvkContextFlag::GpDirtyVertexBuffers,
DxvkContextFlag::GpDirtyIndexBuffer);
if (rc->getShaderResource(slot).bufferView != bufferView) {
m_flags.set(this->getResourceDirtyFlag(pipe));
DxvkShaderResourceSlot resource;
resource.bufferView = bufferView;
DxvkDescriptorInfo descriptor;
if (bufferView != nullptr)
descriptor.texelBuffer = bufferView->handle();
rc->bindShaderResource(slot, resource, descriptor);
}
}
void DxvkContext::bindResourceImage(
VkPipelineBindPoint pipe,
uint32_t slot,
const Rc<DxvkImageView>& image) {
auto rc = this->getShaderResourceSlots(pipe);
if (rc->getShaderResource(slot).imageView != image) {
m_flags.set(this->getResourceDirtyFlag(pipe));
DxvkShaderResourceSlot resource;
resource.imageView = image;
DxvkDescriptorInfo descriptor;
if (image != nullptr) {
descriptor.image.imageView = image->handle();
descriptor.image.imageLayout = image->imageLayout();
}
rc->bindShaderResource(slot, resource, descriptor);
}
}
void DxvkContext::bindResourceSampler(
VkPipelineBindPoint pipe,
uint32_t slot,
const Rc<DxvkSampler>& sampler) {
auto rc = this->getShaderResourceSlots(pipe);
if (rc->getShaderResource(slot).sampler != sampler) {
m_flags.set(this->getResourceDirtyFlag(pipe));
DxvkShaderResourceSlot resource;
resource.sampler = sampler;
DxvkDescriptorInfo descriptor;
if (sampler != nullptr)
descriptor.image.sampler = sampler->handle();
rc->bindShaderResource(slot, resource, descriptor);
}
}
@ -166,6 +260,8 @@ namespace dxvk {
this->commitComputeState();
m_cmd->cmdDispatch(x, y, z);
this->commitComputeBarriers();
}
@ -335,12 +431,18 @@ namespace dxvk {
}
void DxvkContext::bindComputePipeline() {
// TODO implement
void DxvkContext::updateComputePipeline() {
if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) {
m_flags.clr(DxvkContextFlag::CpDirtyPipeline);
m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE,
m_state.cPipe->getPipelineHandle());
m_cmd->trackResource(m_state.cPipe);
}
}
void DxvkContext::bindGraphicsPipeline() {
void DxvkContext::updateGraphicsPipeline() {
if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) {
m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
@ -355,8 +457,42 @@ namespace dxvk {
gpState.viewportCount = m_state.vp.viewportCount;
m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS,
m_state.gp->getPipelineHandle(gpState));
m_cmd->trackResource(m_state.gp);
m_state.gPipe->getPipelineHandle(gpState));
m_cmd->trackResource(m_state.gPipe);
}
}
void DxvkContext::updateComputeShaderResources() {
if (m_flags.test(DxvkContextFlag::CpDirtyResources)) {
m_flags.clr(DxvkContextFlag::CpDirtyResources);
auto layout = m_state.cPipe->layout();
m_cmd->bindResourceDescriptors(
VK_PIPELINE_BIND_POINT_COMPUTE,
layout->pipelineLayout(),
layout->descriptorSetLayout(),
layout->bindingCount(),
layout->bindings(),
m_cResources.descriptors());
}
}
void DxvkContext::updateGraphicsShaderResources() {
if (m_flags.test(DxvkContextFlag::GpDirtyResources)) {
m_flags.clr(DxvkContextFlag::GpDirtyResources);
auto layout = m_state.gPipe->layout();
m_cmd->bindResourceDescriptors(
VK_PIPELINE_BIND_POINT_GRAPHICS,
layout->pipelineLayout(),
layout->descriptorSetLayout(),
layout->bindingCount(),
layout->bindings(),
m_gResources.descriptors());
}
}
@ -413,16 +549,41 @@ namespace dxvk {
void DxvkContext::commitComputeState() {
this->renderPassEnd();
this->bindComputePipeline();
this->updateComputePipeline();
this->updateComputeShaderResources();
}
void DxvkContext::commitGraphicsState() {
this->renderPassBegin();
this->bindGraphicsPipeline();
this->updateGraphicsPipeline();
this->updateDynamicState();
this->updateIndexBufferBinding();
this->updateVertexBufferBindings();
this->updateGraphicsShaderResources();
}
void DxvkContext::commitComputeBarriers() {
// TODO implement
}
DxvkShaderResourceSlots* DxvkContext::getShaderResourceSlots(VkPipelineBindPoint pipe) {
switch (pipe) {
case VK_PIPELINE_BIND_POINT_GRAPHICS: return &m_gResources;
case VK_PIPELINE_BIND_POINT_COMPUTE : return &m_cResources;
default: return nullptr;
}
}
DxvkContextFlag DxvkContext::getResourceDirtyFlag(VkPipelineBindPoint pipe) const {
switch (pipe) {
default:
case VK_PIPELINE_BIND_POINT_GRAPHICS: return DxvkContextFlag::GpDirtyResources;
case VK_PIPELINE_BIND_POINT_COMPUTE : return DxvkContextFlag::CpDirtyResources;
}
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "dxvk_barrier.h"
#include "dxvk_binding.h"
#include "dxvk_cmdlist.h"
#include "dxvk_context_state.h"
#include "dxvk_data.h"
@ -53,19 +54,8 @@ namespace dxvk {
void bindFramebuffer(
const Rc<DxvkFramebuffer>& fb);
/**
* \brief Binds index buffer
* \param [in] buffer New index buffer
*/
void bindIndexBuffer(
const DxvkBufferBinding& buffer);
/**
* \brief Binds compute pipeline
*
* Note that binding a new pipeline implicitly
* invalidates all resource bindings that are
* used by the pipeline.
* \param [in] pipeline The pipeline to bind
*/
void bindComputePipeline(
@ -73,15 +63,76 @@ namespace dxvk {
/**
* \brief Binds graphics pipeline
*
* Note that binding a new pipeline implicitly
* invalidates all bindings that are used by
* the pipeline.
* \param [in] pipeline The pipeline to bind
*/
void bindGraphicsPipeline(
const Rc<DxvkGraphicsPipeline>& pipeline);
/**
* \brief Binds index buffer
*
* The index buffer will be used when
* issuing \c drawIndexed commands.
* \param [in] buffer New index buffer
*/
void bindIndexBuffer(
const DxvkBufferBinding& buffer);
/**
* \brief Binds buffer as a shader resource
*
* Can be used for uniform and storage buffers.
* \param [in] pipe Target pipeline
* \param [in] slot Resource binding slot
* \param [in] buffer Buffer to bind
*/
void bindResourceBuffer(
VkPipelineBindPoint pipe,
uint32_t slot,
const DxvkBufferBinding& buffer);
/**
* \brief Binds texel buffer view
*
* Can be used for both uniform texel
* buffers and storage texel buffers.
* \param [in] pipe Target pipeline
* \param [in] slot Resource binding slot
* \param [in] bufferView Buffer view to bind
*/
void bindResourceTexelBuffer(
VkPipelineBindPoint pipe,
uint32_t slot,
const Rc<DxvkBufferView>& bufferView);
/**
* \brief Binds image view
*
* Can be used for sampled images with a
* dedicated sampler and storage images.
* \param [in] pipe Target pipeline
* \param [in] slot Resource binding slot
* \param [in] imageView Image view to bind
*/
void bindResourceImage(
VkPipelineBindPoint pipe,
uint32_t slot,
const Rc<DxvkImageView>& image);
/**
* \brief Binds image sampler
*
* Binds a sampler that can be used together with
* an image in order to read from a texture.
* \param [in] pipe Target pipeline
* \param [in] slot Resource binding slot
* \param [in] sampler Sampler view to bind
*/
void bindResourceSampler(
VkPipelineBindPoint pipe,
uint32_t slot,
const Rc<DxvkSampler>& sampler);
/**
* \brief Binds vertex buffer
*
@ -262,13 +313,17 @@ namespace dxvk {
DxvkContextState m_state;
DxvkBarrierSet m_barriers;
std::vector<VkWriteDescriptorSet> m_descriptorSetWrites;
DxvkShaderResourceSlots m_cResources = { 1024 };
DxvkShaderResourceSlots m_gResources = { 4096 };
void renderPassBegin();
void renderPassEnd();
void bindComputePipeline();
void bindGraphicsPipeline();
void updateComputePipeline();
void updateGraphicsPipeline();
void updateComputeShaderResources();
void updateGraphicsShaderResources();
void updateDynamicState();
void updateViewports();
@ -278,6 +333,15 @@ namespace dxvk {
void commitComputeState();
void commitGraphicsState();
void commitComputeBarriers();
DxvkShaderResourceSlots* getShaderResourceSlots(
VkPipelineBindPoint pipe);
DxvkContextFlag getResourceDirtyFlag(
VkPipelineBindPoint pipe) const;
};
}

View File

@ -7,6 +7,8 @@
#include "dxvk_graphics.h"
#include "dxvk_image.h"
#include "dxvk_limits.h"
#include "dxvk_pipeline.h"
#include "dxvk_sampler.h"
#include "dxvk_shader.h"
namespace dxvk {
@ -64,8 +66,8 @@ namespace dxvk {
DxvkOutputMergerState om;
DxvkConstantStateObjects co;
Rc<DxvkGraphicsPipeline> gp;
Rc<DxvkComputePipeline> cp;
Rc<DxvkGraphicsPipeline> gPipe;
Rc<DxvkComputePipeline> cPipe;
};
}

View File

@ -4,6 +4,19 @@
namespace dxvk {
/**
* \brief Descriptor info
*
* Stores information that is required to
* update a single resource descriptor.
*/
struct DxvkDescriptorInfo {
VkDescriptorImageInfo image = { VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED };
VkDescriptorBufferInfo buffer = { VK_NULL_HANDLE, 0, 0 };
VkBufferView texelBuffer = VK_NULL_HANDLE;
};
/**
* \brief Descriptor set allocator
*

View File

@ -79,6 +79,12 @@ namespace dxvk {
}
Rc<DxvkSampler> DxvkDevice::createSampler(
const DxvkSamplerCreateInfo& createInfo) {
return new DxvkSampler(m_vkd, createInfo);
}
Rc<DxvkSemaphore> DxvkDevice::createSemaphore() {
return new DxvkSemaphore(m_vkd);
}
@ -92,8 +98,8 @@ namespace dxvk {
Rc<DxvkBindingLayout> DxvkDevice::createBindingLayout(
uint32_t bindingCount,
const DxvkBindingInfo* bindingInfos) {
uint32_t bindingCount,
const DxvkDescriptorSlot* bindingInfos) {
return new DxvkBindingLayout(m_vkd, bindingCount, bindingInfos);
}

View File

@ -9,6 +9,7 @@
#include "dxvk_image.h"
#include "dxvk_memory.h"
#include "dxvk_renderpass.h"
#include "dxvk_sampler.h"
#include "dxvk_shader.h"
#include "dxvk_swapchain.h"
#include "dxvk_sync.h"
@ -141,6 +142,15 @@ namespace dxvk {
const Rc<DxvkImage>& image,
const DxvkImageViewCreateInfo& createInfo);
/**
* \brief Creates a sampler object
*
* \param [in] createInfo Sampler parameters
* \returns Newly created sampler object
*/
Rc<DxvkSampler> createSampler(
const DxvkSamplerCreateInfo& createInfo);
/**
* \brief Creates a semaphore object
* \returns Newly created semaphore
@ -166,8 +176,8 @@ namespace dxvk {
* \returns New binding layout
*/
Rc<DxvkBindingLayout> createBindingLayout(
uint32_t bindingCount,
const DxvkBindingInfo* bindingInfos);
uint32_t bindingCount,
const DxvkDescriptorSlot* bindingInfos);
/**
* \brief Creates a compute pipeline

View File

@ -119,7 +119,7 @@ namespace dxvk {
info.pDepthStencilState = &state.depthStencilState->info();
info.pColorBlendState = &state.blendState->info();
info.pDynamicState = &dsInfo;
info.layout = this->pipelineLayout();
info.layout = m_layout->pipelineLayout();
info.renderPass = state.renderPass;
info.subpass = 0;
info.basePipelineHandle = VK_NULL_HANDLE;

View File

@ -58,26 +58,16 @@ namespace dxvk {
const Rc<DxvkShader>& fs);
~DxvkGraphicsPipeline();
/**
* \brief Descriptor set layout
*
* The descriptor set layout for this pipeline.
* Use this to allocate new descriptor sets.
* \returns The descriptor set layout
*/
VkDescriptorSetLayout descriptorSetLayout() const {
return m_layout->descriptorSetLayout();
}
/**
* \brief Pipeline layout
*
* The pipeline layout for this pipeline.
* Use this to bind descriptor sets.
* \returns The descriptor set layout
* Stores the pipeline layout and the descriptor set
* layout, as well as information on the resource
* slots used by the pipeline.
* \returns Pipeline layout
*/
VkPipelineLayout pipelineLayout() const {
return m_layout->pipelineLayout();
Rc<DxvkBindingLayout> layout() const {
return m_layout;
}
/**

View File

@ -178,6 +178,14 @@ namespace dxvk {
return m_image;
}
/**
* \brief Image layout
* \returns Image layout
*/
VkImageLayout imageLayout() const {
return m_image->info().layout;
}
/**
* \brief Subresource range
* \returns Subresource range

View File

@ -5,11 +5,12 @@
namespace dxvk {
enum DxvkLimits : size_t {
MaxNumRenderTargets = 8,
MaxNumVertexAttributes = 32,
MaxNumVertexBindings = 32,
MaxNumOutputStreams = 4,
MaxNumViewports = 16,
MaxNumRenderTargets = 8,
MaxNumVertexAttributes = 32,
MaxNumVertexBindings = 32,
MaxNumOutputStreams = 4,
MaxNumViewports = 16,
MaxNumResourceSlots = 4096,
};
}

View File

@ -1,29 +1,37 @@
#include <cstring>
#include "dxvk_pipeline.h"
namespace dxvk {
DxvkBindingLayout::DxvkBindingLayout(
const Rc<vk::DeviceFn>& vkd,
uint32_t bindingCount,
const DxvkBindingInfo* bindingInfos)
const Rc<vk::DeviceFn>& vkd,
uint32_t bindingCount,
const DxvkDescriptorSlot* bindingInfos)
: m_vkd(vkd) {
m_bindingSlots.resize(bindingCount);
std::memcpy(m_bindingSlots.data(), bindingInfos,
bindingCount * sizeof(DxvkDescriptorSlot));
std::vector<VkDescriptorSetLayoutBinding> bindings;
for (uint32_t i = 0; i < bindingCount; i++) {
VkDescriptorSetLayoutBinding binding;
binding.binding = i;
binding.descriptorType = bindingInfos[i].type;
binding.descriptorCount = bindingInfos[i].stages == 0 ? 0 : 1;
binding.descriptorCount = 1;
binding.stageFlags = bindingInfos[i].stages;
binding.pImmutableSamplers = nullptr;
m_bindings.push_back(binding);
bindings.push_back(binding);
}
VkDescriptorSetLayoutCreateInfo dsetInfo;
dsetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
dsetInfo.pNext = nullptr;
dsetInfo.flags = 0;
dsetInfo.bindingCount = m_bindings.size();
dsetInfo.pBindings = m_bindings.data();
dsetInfo.bindingCount = bindings.size();
dsetInfo.pBindings = bindings.data();
if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(),
&dsetInfo, nullptr, &m_descriptorSetLayout) != VK_SUCCESS)
@ -59,14 +67,4 @@ namespace dxvk {
}
}
DxvkBindingInfo DxvkBindingLayout::binding(uint32_t id) const {
const VkDescriptorSetLayoutBinding& bindingInfo = m_bindings.at(id);
DxvkBindingInfo result;
result.type = bindingInfo.descriptorType;
result.stages = bindingInfo.stageFlags;
return result;
}
}

View File

@ -11,9 +11,10 @@ namespace dxvk {
* Vulkan. DXVK does not use descriptor arrays.
* Instead, each binding stores one descriptor.
*/
struct DxvkBindingInfo {
VkDescriptorType type;
VkShaderStageFlags stages;
struct DxvkDescriptorSlot {
uint32_t slot; ///< Resource slot index for the context
VkDescriptorType type; ///< Descriptor type (aka resource type)
VkShaderStageFlags stages; ///< Stages that can use the resource
};
@ -28,9 +29,9 @@ namespace dxvk {
public:
DxvkBindingLayout(
const Rc<vk::DeviceFn>& vkd,
uint32_t bindingCount,
const DxvkBindingInfo* bindingInfos);
const Rc<vk::DeviceFn>& vkd,
uint32_t bindingCount,
const DxvkDescriptorSlot* bindingInfos);
~DxvkBindingLayout();
@ -38,17 +39,17 @@ namespace dxvk {
* \brief Number of resource bindings
* \returns Resource binding count
*/
uint32_t numBindings() const {
return m_bindings.size();
uint32_t bindingCount() const {
return m_bindingSlots.size();
}
/**
* \brief Retrieves binding info
*
* \param [in] binding ID
* \returns Binding info
* \brief Resource binding info
* \returns Resource binding info
*/
DxvkBindingInfo binding(uint32_t id) const;
const DxvkDescriptorSlot* bindings() const {
return m_bindingSlots.data();
}
/**
* \brief Descriptor set layout handle
@ -73,7 +74,7 @@ namespace dxvk {
VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
std::vector<VkDescriptorSetLayoutBinding> m_bindings;
std::vector<DxvkDescriptorSlot> m_bindingSlots;
};

View File

@ -0,0 +1,40 @@
#include "dxvk_sampler.h"
namespace dxvk {
DxvkSampler::DxvkSampler(
const Rc<vk::DeviceFn>& vkd,
const DxvkSamplerCreateInfo& info)
: m_vkd(vkd), m_info(info) {
VkSamplerCreateInfo samplerInfo;
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.pNext = nullptr;
samplerInfo.flags = 0;
samplerInfo.magFilter = info.magFilter;
samplerInfo.minFilter = info.minFilter;
samplerInfo.mipmapMode = info.mipmapMode;
samplerInfo.addressModeU = info.addressModeU;
samplerInfo.addressModeV = info.addressModeV;
samplerInfo.addressModeW = info.addressModeW;
samplerInfo.mipLodBias = info.mipmapLodBias;
samplerInfo.anisotropyEnable = info.useAnisotropy;
samplerInfo.maxAnisotropy = info.maxAnisotropy;
samplerInfo.compareEnable = info.compareToDepth;
samplerInfo.compareOp = info.compareOp;
samplerInfo.minLod = info.mipmapLodMin;
samplerInfo.maxLod = info.mipmapLodMax;
samplerInfo.borderColor = info.borderColor;
samplerInfo.unnormalizedCoordinates = info.usePixelCoord;
if (m_vkd->vkCreateSampler(m_vkd->device(),
&samplerInfo, nullptr, &m_sampler) != VK_SUCCESS)
throw DxvkError("DxvkSampler::DxvkSampler: Failed to create sampler");
}
DxvkSampler::~DxvkSampler() {
m_vkd->vkDestroySampler(
m_vkd->device(), m_sampler, nullptr);
}
}

View File

@ -0,0 +1,82 @@
#pragma once
#include "dxvk_resource.h"
namespace dxvk {
/**
* \brief Sampler properties
*/
struct DxvkSamplerCreateInfo {
/// Texture filter propertoes
VkFilter magFilter;
VkFilter minFilter;
/// Mipmapping properties
VkSamplerMipmapMode mipmapMode;
float mipmapLodBias;
float mipmapLodMin;
float mipmapLodMax;
/// Anisotropic filtering
VkBool32 useAnisotropy;
float maxAnisotropy;
/// Address modes
VkSamplerAddressMode addressModeU;
VkSamplerAddressMode addressModeV;
VkSamplerAddressMode addressModeW;
/// Compare op for shadow textures
VkBool32 compareToDepth;
VkCompareOp compareOp;
/// Texture border color
VkBorderColor borderColor;
/// Enables unnormalized coordinates
VkBool32 usePixelCoord;
};
/**
* \brief Sampler
*
* Manages a sampler object that can be bound to
* a pipeline. Sampler objects provide parameters
* for texture lookups within a shader.
*/
class DxvkSampler : public DxvkResource {
public:
DxvkSampler(
const Rc<vk::DeviceFn>& vkd,
const DxvkSamplerCreateInfo& info);
~DxvkSampler();
/**
* \brief Sampler handle
* \returns Sampler handle
*/
VkSampler handle() const {
return m_sampler;
}
/**
* \brief Sampler parameters
* \returns Sampler parameters
*/
const DxvkSamplerCreateInfo& info() const {
return m_info;
}
private:
Rc<vk::DeviceFn> m_vkd;
DxvkSamplerCreateInfo m_info;
VkSampler m_sampler = VK_NULL_HANDLE;
};
}

View File

@ -19,6 +19,7 @@ dxvk_src = files([
'dxvk_pipeline.cpp',
'dxvk_renderpass.cpp',
'dxvk_resource.cpp',
'dxvk_sampler.cpp',
'dxvk_shader.cpp',
'dxvk_surface.cpp',
'dxvk_swapchain.cpp',

View File

@ -221,6 +221,16 @@ namespace dxvk {
}
void SpirvModule::decorateBinding(
uint32_t object,
uint32_t binding) {
m_annotations.putIns (spv::OpDecorate, 4);
m_annotations.putWord (object);
m_annotations.putWord (spv::DecorationBinding);
m_annotations.putInt32(binding);
}
void SpirvModule::decorateBlock(uint32_t object) {
m_annotations.putIns (spv::OpDecorate, 3);
m_annotations.putWord (object);
@ -248,6 +258,16 @@ namespace dxvk {
}
void SpirvModule::decorateDescriptorSet(
uint32_t object,
uint32_t set) {
m_annotations.putIns (spv::OpDecorate, 4);
m_annotations.putWord (object);
m_annotations.putWord (spv::DecorationDescriptorSet);
m_annotations.putInt32(set);
}
void SpirvModule::decorateLocation(
uint32_t object,
uint32_t location) {
@ -378,6 +398,36 @@ namespace dxvk {
}
uint32_t SpirvModule::defSamplerType() {
return this->defType(spv::OpTypeSampler, 0, nullptr);
}
uint32_t SpirvModule::defImageType(
uint32_t sampledType,
spv::Dim dimensionality,
uint32_t depth,
uint32_t arrayed,
uint32_t multisample,
uint32_t sampled,
spv::ImageFormat format) {
std::array<uint32_t, 7> args = {
sampledType, dimensionality,
depth, arrayed, multisample,
sampled, format
};
return this->defType(spv::OpTypeImage,
args.size(), args.data());
}
uint32_t SpirvModule::defSampledImageType(
uint32_t imageType) {
return this->defType(spv::OpTypeSampledImage, 1, &imageType);
}
uint32_t SpirvModule::newVar(
uint32_t pointerType,
spv::StorageClass storageClass) {
@ -675,6 +725,36 @@ namespace dxvk {
}
uint32_t SpirvModule::opSampledImage(
uint32_t resultType,
uint32_t image,
uint32_t sampler) {
uint32_t resultId = this->allocateId();
m_code.putIns (spv::OpSampledImage, 5);
m_code.putWord(resultType);
m_code.putWord(resultId);
m_code.putWord(image);
m_code.putWord(sampler);
return resultId;
}
uint32_t SpirvModule::opImageSampleImplicitLod(
uint32_t resultType,
uint32_t sampledImage,
uint32_t coordinates) {
uint32_t resultId = this->allocateId();
m_code.putIns (spv::OpImageSampleImplicitLod, 5);
m_code.putWord(resultType);
m_code.putWord(resultId);
m_code.putWord(sampledImage);
m_code.putWord(coordinates);
return resultId;
}
void SpirvModule::opReturn() {
m_code.putIns (spv::OpReturn, 1);
}

View File

@ -81,6 +81,10 @@ namespace dxvk {
uint32_t constCount,
const uint32_t* constIds);
void decorateBinding(
uint32_t object,
uint32_t binding);
void decorateBlock(
uint32_t object);
@ -92,6 +96,10 @@ namespace dxvk {
uint32_t object,
uint32_t location);
void decorateDescriptorSet(
uint32_t object,
uint32_t set);
void decorateLocation(
uint32_t object,
uint32_t location);
@ -140,6 +148,20 @@ namespace dxvk {
uint32_t variableType,
spv::StorageClass storageClass);
uint32_t defSamplerType();
uint32_t defImageType(
uint32_t sampledType,
spv::Dim dimensionality,
uint32_t depth,
uint32_t arrayed,
uint32_t multisample,
uint32_t sampled,
spv::ImageFormat format);
uint32_t defSampledImageType(
uint32_t imageType);
uint32_t newVar(
uint32_t pointerType,
spv::StorageClass storageClass);
@ -239,6 +261,16 @@ namespace dxvk {
uint32_t pointerId,
uint32_t valueId);
uint32_t opSampledImage(
uint32_t resultType,
uint32_t image,
uint32_t sampler);
uint32_t opImageSampleImplicitLod(
uint32_t resultType,
uint32_t sampledImage,
uint32_t coordinates);
void opReturn();
private:

View File

@ -63,7 +63,7 @@ public:
void run() {
FLOAT color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
FLOAT color[4] = { 0.8f, 0.2f, 0.2f, 1.0f };
m_context->OMSetRenderTargets(1, &m_bufferView, nullptr);
m_context->ClearRenderTargetView(m_bufferView.ptr(), color);