1
0
mirror of https://github.com/EduApps-CDG/OpenDX synced 2024-12-30 09:45:37 +01:00
OpenDX/src/dxvk/dxvk_context.cpp

589 lines
16 KiB
C++
Raw Normal View History

2017-10-14 23:52:47 +02:00
#include "dxvk_device.h"
2017-10-10 23:32:13 +02:00
#include "dxvk_context.h"
#include "dxvk_main.h"
namespace dxvk {
DxvkContext::DxvkContext(const Rc<DxvkDevice>& device)
: m_device(device) {
2017-11-26 14:01:41 +01:00
2017-10-11 00:27:33 +02:00
}
2017-10-10 23:32:13 +02:00
DxvkContext::~DxvkContext() {
2017-11-26 14:01:41 +01:00
2017-10-10 23:32:13 +02:00
}
void DxvkContext::beginRecording(const Rc<DxvkCommandList>& cmdList) {
m_cmd = cmdList;
m_cmd->beginRecording();
// The current state of the internal command buffer is
// undefined, so we have to bind and set up everything
// before any draw or dispatch command is recorded.
m_flags.clr(
DxvkContextFlag::GpRenderPassBound);
m_flags.set(
DxvkContextFlag::GpDirtyPipeline,
DxvkContextFlag::GpDirtyDynamicState,
DxvkContextFlag::GpDirtyResources,
DxvkContextFlag::GpDirtyIndexBuffer,
DxvkContextFlag::GpDirtyVertexBuffers,
DxvkContextFlag::CpDirtyPipeline,
DxvkContextFlag::CpDirtyResources);
2017-10-10 23:32:13 +02:00
}
Rc<DxvkCommandList> DxvkContext::endRecording() {
this->renderPassEnd();
m_cmd->endRecording();
return std::exchange(m_cmd, nullptr);
2017-10-10 23:32:13 +02:00
}
void DxvkContext::bindFramebuffer(
const Rc<DxvkFramebuffer>& fb) {
if (m_state.om.framebuffer != fb) {
m_state.om.framebuffer = fb;
this->renderPassEnd();
}
}
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) {
m_state.vi.indexBuffer = buffer;
m_flags.set(DxvkContextFlag::GpDirtyIndexBuffer);
}
}
void DxvkContext::bindResourceBuffer(
VkPipelineBindPoint pipe,
uint32_t slot,
const DxvkBufferBinding& buffer) {
auto rc = this->getShaderResourceSlots(pipe);
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::bindResourceTexelBuffer(
VkPipelineBindPoint pipe,
uint32_t slot,
const Rc<DxvkBufferView>& bufferView) {
auto rc = this->getShaderResourceSlots(pipe);
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);
}
}
void DxvkContext::bindVertexBuffer(
uint32_t binding,
const DxvkBufferBinding& buffer) {
if (m_state.vi.vertexBuffers.at(binding) != buffer) {
m_state.vi.vertexBuffers.at(binding) = buffer;
m_flags.set(DxvkContextFlag::GpDirtyVertexBuffers);
}
}
void DxvkContext::clearColorImage(
const Rc<DxvkImage>& image,
const VkClearColorValue& value,
const VkImageSubresourceRange& subresources) {
this->renderPassEnd();
m_cmd->cmdClearColorImage(
image->handle(),
VK_IMAGE_LAYOUT_GENERAL,
&value, 1, &subresources);
// TODO memory barrier
m_cmd->trackResource(image);
}
void DxvkContext::clearRenderTarget(
const VkClearAttachment& attachment,
const VkClearRect& clearArea) {
// We only need the framebuffer to be bound. Flushing the
// entire pipeline state is not required and might actually
// cause problems if the current pipeline state is invalid.
this->renderPassBegin();
2017-10-10 23:32:13 +02:00
m_cmd->cmdClearAttachments(
1, &attachment, 1, &clearArea);
}
void DxvkContext::copyBuffer(
const Rc<DxvkBuffer>& dstBuffer,
VkDeviceSize dstOffset,
const Rc<DxvkBuffer>& srcBuffer,
VkDeviceSize srcOffset,
VkDeviceSize numBytes) {
if (numBytes != 0) {
VkBufferCopy bufferRegion;
bufferRegion.srcOffset = srcOffset;
bufferRegion.dstOffset = dstOffset;
bufferRegion.size = numBytes;
m_cmd->cmdCopyBuffer(
srcBuffer->handle(),
dstBuffer->handle(),
1, &bufferRegion);
m_barriers.accessBuffer(
srcBuffer, srcOffset, numBytes,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT);
m_barriers.accessBuffer(
dstBuffer, dstOffset, numBytes,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
2017-12-01 10:51:58 +01:00
m_barriers.recordCommands(m_cmd);
m_cmd->trackResource(dstBuffer);
m_cmd->trackResource(srcBuffer);
}
}
2017-11-23 14:24:00 +01:00
void DxvkContext::dispatch(
uint32_t x,
uint32_t y,
uint32_t z) {
2017-11-26 14:01:41 +01:00
this->commitComputeState();
2017-11-23 14:24:00 +01:00
m_cmd->cmdDispatch(x, y, z);
this->commitComputeBarriers();
2017-11-23 14:24:00 +01:00
}
void DxvkContext::draw(
uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,
uint32_t firstInstance) {
this->commitGraphicsState();
m_cmd->cmdDraw(
vertexCount, instanceCount,
firstVertex, firstInstance);
}
void DxvkContext::drawIndexed(
uint32_t indexCount,
uint32_t instanceCount,
uint32_t firstIndex,
uint32_t vertexOffset,
uint32_t firstInstance) {
this->commitGraphicsState();
m_cmd->cmdDrawIndexed(
indexCount, instanceCount,
firstIndex, vertexOffset,
firstInstance);
}
void DxvkContext::initBuffer(
const Rc<DxvkBuffer>& buffer,
const Rc<DxvkDataBuffer>& data) {
// TODO implement
}
void DxvkContext::initImage(
const Rc<DxvkImage>& image,
const Rc<DxvkDataBuffer>& data) {
const DxvkImageCreateInfo& info = image->info();
VkImageSubresourceRange sr;
sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
sr.baseMipLevel = 0;
sr.levelCount = info.mipLevels;
sr.baseArrayLayer = 0;
sr.layerCount = info.numLayers;
m_barriers.initImage(image, sr,
VK_IMAGE_LAYOUT_GENERAL,
info.stages,
info.access);
m_barriers.recordCommands(m_cmd);
// TODO implement data upload
}
void DxvkContext::setViewports(
uint32_t viewportCount,
const VkViewport* viewports,
const VkRect2D* scissorRects) {
if (m_state.vp.viewportCount != viewportCount) {
m_state.vp.viewportCount = viewportCount;
m_flags.set(DxvkContextFlag::GpDirtyPipeline);
}
for (uint32_t i = 0; i < viewportCount; i++) {
m_state.vp.viewports.at(i) = viewports[i];
m_state.vp.scissorRects.at(i) = scissorRects[i];
}
2017-11-21 19:50:57 +01:00
this->updateViewports();
}
2017-10-10 23:32:13 +02:00
void DxvkContext::setInputAssemblyState(
const Rc<DxvkInputAssemblyState>& state) {
if (m_state.co.inputAssemblyState != state) {
m_state.co.inputAssemblyState = state;
m_flags.set(DxvkContextFlag::GpDirtyPipeline);
}
}
void DxvkContext::setInputLayout(
const Rc<DxvkInputLayout>& state) {
if (m_state.co.inputLayout != state) {
m_state.co.inputLayout = state;
m_flags.set(DxvkContextFlag::GpDirtyPipeline);
}
}
void DxvkContext::setRasterizerState(
const Rc<DxvkRasterizerState>& state) {
if (m_state.co.rasterizerState != state) {
m_state.co.rasterizerState = state;
m_flags.set(DxvkContextFlag::GpDirtyPipeline);
}
}
void DxvkContext::setMultisampleState(
const Rc<DxvkMultisampleState>& state) {
if (m_state.co.multisampleState != state) {
m_state.co.multisampleState = state;
m_flags.set(DxvkContextFlag::GpDirtyPipeline);
}
}
void DxvkContext::setDepthStencilState(
const Rc<DxvkDepthStencilState>& state) {
if (m_state.co.depthStencilState != state) {
m_state.co.depthStencilState = state;
m_flags.set(DxvkContextFlag::GpDirtyPipeline);
}
}
void DxvkContext::setBlendState(
const Rc<DxvkBlendState>& state) {
if (m_state.co.blendState != state) {
m_state.co.blendState = state;
m_flags.set(DxvkContextFlag::GpDirtyPipeline);
}
}
void DxvkContext::renderPassBegin() {
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)
&& (m_state.om.framebuffer != nullptr)) {
m_flags.set(DxvkContextFlag::GpRenderPassBound);
const DxvkFramebufferSize fbSize
= m_state.om.framebuffer->size();
VkRect2D renderArea;
renderArea.offset = VkOffset2D { 0, 0 };
renderArea.extent = VkExtent2D { fbSize.width, fbSize.height };
VkRenderPassBeginInfo info;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.pNext = nullptr;
info.renderPass = m_state.om.framebuffer->renderPass();
info.framebuffer = m_state.om.framebuffer->handle();
info.renderArea = renderArea;
info.clearValueCount = 0;
info.pClearValues = nullptr;
m_cmd->cmdBeginRenderPass(&info,
VK_SUBPASS_CONTENTS_INLINE);
m_cmd->trackResource(
m_state.om.framebuffer);
}
}
void DxvkContext::renderPassEnd() {
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
m_cmd->cmdEndRenderPass();
}
}
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);
}
2017-11-23 14:24:00 +01:00
}
void DxvkContext::updateGraphicsPipeline() {
if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) {
m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
DxvkGraphicsPipelineStateInfo gpState;
gpState.inputAssemblyState = m_state.co.inputAssemblyState;
gpState.inputLayout = m_state.co.inputLayout;
gpState.rasterizerState = m_state.co.rasterizerState;
gpState.multisampleState = m_state.co.multisampleState;
gpState.depthStencilState = m_state.co.depthStencilState;
gpState.blendState = m_state.co.blendState;
gpState.renderPass = m_state.om.framebuffer->renderPass();
gpState.viewportCount = m_state.vp.viewportCount;
m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS,
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());
}
}
2017-11-21 19:50:57 +01:00
void DxvkContext::updateDynamicState() {
if (m_flags.test(DxvkContextFlag::GpDirtyDynamicState)) {
m_flags.clr(DxvkContextFlag::GpDirtyDynamicState);
2017-11-21 19:50:57 +01:00
this->updateViewports();
}
}
2017-11-21 19:50:57 +01:00
void DxvkContext::updateViewports() {
m_cmd->cmdSetViewport(0, m_state.vp.viewportCount, m_state.vp.viewports.data());
m_cmd->cmdSetScissor (0, m_state.vp.viewportCount, m_state.vp.scissorRects.data());
}
void DxvkContext::updateIndexBufferBinding() {
if (m_flags.test(DxvkContextFlag::GpDirtyIndexBuffer)) {
m_flags.clr(DxvkContextFlag::GpDirtyIndexBuffer);
if (m_state.vi.indexBuffer.bufferHandle() != VK_NULL_HANDLE) {
m_cmd->cmdBindIndexBuffer(
m_state.vi.indexBuffer.bufferHandle(),
m_state.vi.indexBuffer.bufferOffset(),
VK_INDEX_TYPE_UINT32);
m_cmd->trackResource(
m_state.vi.indexBuffer.resource());
}
}
}
2017-11-21 19:50:57 +01:00
void DxvkContext::updateVertexBufferBindings() {
if (m_flags.test(DxvkContextFlag::GpDirtyVertexBuffers)) {
m_flags.clr(DxvkContextFlag::GpDirtyVertexBuffers);
2017-11-21 19:50:57 +01:00
for (uint32_t i = 0; i < m_state.vi.vertexBuffers.size(); i++) {
const DxvkBufferBinding vbo = m_state.vi.vertexBuffers.at(i);
VkBuffer handle = vbo.bufferHandle();
VkDeviceSize offset = vbo.bufferOffset();
if (handle != VK_NULL_HANDLE) {
m_cmd->cmdBindVertexBuffers(i, 1, &handle, &offset);
m_cmd->trackResource(vbo.resource());
}
}
}
}
2017-11-23 14:24:00 +01:00
void DxvkContext::commitComputeState() {
this->renderPassEnd();
this->updateComputePipeline();
this->updateComputeShaderResources();
2017-11-23 14:24:00 +01:00
}
void DxvkContext::commitGraphicsState() {
this->renderPassBegin();
this->updateGraphicsPipeline();
2017-11-21 19:50:57 +01:00
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;
}
}
2017-10-10 23:32:13 +02:00
}