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 {
|
|
|
|
|
2017-10-15 17:56:06 +02:00
|
|
|
DxvkContext::DxvkContext(
|
|
|
|
const Rc<DxvkDevice>& device,
|
|
|
|
const Rc<DxvkPipelineManager>& pipeMgr)
|
|
|
|
: m_device (device),
|
|
|
|
m_pipeMgr (pipeMgr) {
|
2017-10-14 23:52:47 +02:00
|
|
|
TRACE(this, device);
|
2017-10-11 00:27:33 +02:00
|
|
|
}
|
2017-10-10 23:32:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
DxvkContext::~DxvkContext() {
|
2017-10-11 00:27:33 +02:00
|
|
|
TRACE(this);
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxvkContext::beginRecording(
|
2017-10-14 14:28:31 +02:00
|
|
|
const Rc<DxvkRecorder>& recorder) {
|
|
|
|
TRACE(this, recorder);
|
2017-11-17 19:49:44 +01:00
|
|
|
|
2017-10-14 14:28:31 +02:00
|
|
|
m_cmd = recorder;
|
|
|
|
m_cmd->beginRecording();
|
2017-10-13 03:19:23 +02:00
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
// 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_state.flags.clr(
|
|
|
|
DxvkContextFlag::GpRenderPassBound);
|
2017-10-13 03:19:23 +02:00
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
m_state.flags.set(
|
|
|
|
DxvkContextFlag::GpDirtyPipeline,
|
|
|
|
DxvkContextFlag::GpDirtyPipelineState,
|
2017-11-20 13:21:27 +01:00
|
|
|
DxvkContextFlag::GpDirtyDynamicState,
|
2017-11-17 19:49:44 +01:00
|
|
|
DxvkContextFlag::GpDirtyResources,
|
2017-11-18 10:42:27 +01:00
|
|
|
DxvkContextFlag::GpDirtyIndexBuffer,
|
2017-11-17 19:49:44 +01:00
|
|
|
DxvkContextFlag::GpDirtyVertexBuffers,
|
|
|
|
DxvkContextFlag::CpDirtyPipeline,
|
|
|
|
DxvkContextFlag::CpDirtyResources);
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
void DxvkContext::endRecording() {
|
2017-10-11 00:27:33 +02:00
|
|
|
TRACE(this);
|
2017-10-11 23:29:05 +02:00
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
this->renderPassEnd();
|
2017-10-11 23:29:05 +02:00
|
|
|
|
2017-10-14 14:28:31 +02:00
|
|
|
m_cmd->endRecording();
|
|
|
|
m_cmd = nullptr;
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
2017-10-11 23:29:05 +02:00
|
|
|
|
|
|
|
|
2017-10-15 17:56:06 +02:00
|
|
|
void DxvkContext::bindFramebuffer(
|
|
|
|
const Rc<DxvkFramebuffer>& fb) {
|
|
|
|
TRACE(this, fb);
|
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
if (m_state.om.framebuffer != fb) {
|
|
|
|
m_state.om.framebuffer = fb;
|
|
|
|
this->renderPassEnd();
|
2017-10-15 17:56:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-20 13:21:27 +01:00
|
|
|
void DxvkContext::bindIndexBuffer(
|
|
|
|
const DxvkBufferBinding& buffer) {
|
|
|
|
if (m_state.vi.indexBuffer != buffer) {
|
|
|
|
m_state.vi.indexBuffer = buffer;
|
|
|
|
m_state.flags.set(DxvkContextFlag::GpDirtyIndexBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-15 17:56:06 +02:00
|
|
|
void DxvkContext::bindShader(
|
|
|
|
VkShaderStageFlagBits stage,
|
|
|
|
const Rc<DxvkShader>& shader) {
|
|
|
|
TRACE(this, stage, shader);
|
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
DxvkShaderStageState* stageState = this->getShaderStage(stage);
|
2017-10-15 17:56:06 +02:00
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
if (stageState->shader != shader) {
|
|
|
|
stageState->shader = shader;
|
|
|
|
|
|
|
|
if (stage == VK_SHADER_STAGE_COMPUTE_BIT) {
|
|
|
|
m_state.flags.set(
|
|
|
|
DxvkContextFlag::CpDirtyPipeline,
|
|
|
|
DxvkContextFlag::CpDirtyResources);
|
|
|
|
} else {
|
|
|
|
m_state.flags.set(
|
|
|
|
DxvkContextFlag::GpDirtyPipeline,
|
|
|
|
DxvkContextFlag::GpDirtyPipelineState,
|
|
|
|
DxvkContextFlag::GpDirtyResources,
|
|
|
|
DxvkContextFlag::GpDirtyVertexBuffers,
|
2017-11-18 10:42:27 +01:00
|
|
|
DxvkContextFlag::GpDirtyIndexBuffer);
|
2017-11-17 19:49:44 +01:00
|
|
|
}
|
2017-10-15 17:56:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-20 13:21:27 +01:00
|
|
|
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_state.flags.set(DxvkContextFlag::GpDirtyVertexBuffers);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-11 23:29:05 +02:00
|
|
|
void DxvkContext::clearRenderTarget(
|
|
|
|
const VkClearAttachment& attachment,
|
|
|
|
const VkClearRect& clearArea) {
|
2017-11-17 19:49:44 +01:00
|
|
|
TRACE(this);
|
|
|
|
|
|
|
|
// 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
|
|
|
|
2017-10-14 14:28:31 +02:00
|
|
|
m_cmd->cmdClearAttachments(
|
|
|
|
1, &attachment, 1, &clearArea);
|
2017-10-11 23:29:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxvkContext::draw(
|
|
|
|
uint32_t vertexCount,
|
|
|
|
uint32_t instanceCount,
|
|
|
|
uint32_t firstVertex,
|
|
|
|
uint32_t firstInstance) {
|
2017-10-15 17:56:06 +02:00
|
|
|
TRACE(this, vertexCount, instanceCount,
|
|
|
|
firstVertex, firstInstance);
|
2017-11-20 14:11:09 +01:00
|
|
|
|
|
|
|
this->commitGraphicsState();
|
2017-10-11 23:29:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxvkContext::drawIndexed(
|
|
|
|
uint32_t indexCount,
|
|
|
|
uint32_t instanceCount,
|
|
|
|
uint32_t firstIndex,
|
|
|
|
uint32_t vertexOffset,
|
|
|
|
uint32_t firstInstance) {
|
2017-10-15 17:56:06 +02:00
|
|
|
TRACE(this, indexCount, instanceCount,
|
|
|
|
firstIndex, vertexOffset, firstInstance);
|
2017-11-20 14:11:09 +01:00
|
|
|
|
|
|
|
this->commitGraphicsState();
|
2017-10-11 23:29:05 +02:00
|
|
|
}
|
|
|
|
|
2017-10-10 23:32:13 +02:00
|
|
|
|
2017-11-20 13:38:24 +01:00
|
|
|
void DxvkContext::setInputAssemblyState(
|
|
|
|
const Rc<DxvkInputAssemblyState>& state) {
|
|
|
|
if (m_state.co.inputAssemblyState != state) {
|
|
|
|
m_state.co.inputAssemblyState = state;
|
|
|
|
m_state.flags.set(DxvkContextFlag::GpDirtyPipelineState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxvkContext::setInputLayout(
|
|
|
|
const Rc<DxvkInputLayout>& state) {
|
|
|
|
if (m_state.co.inputLayout != state) {
|
|
|
|
m_state.co.inputLayout = state;
|
|
|
|
m_state.flags.set(DxvkContextFlag::GpDirtyPipelineState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxvkContext::setRasterizerState(
|
|
|
|
const Rc<DxvkRasterizerState>& state) {
|
|
|
|
if (m_state.co.rasterizerState != state) {
|
|
|
|
m_state.co.rasterizerState = state;
|
|
|
|
m_state.flags.set(DxvkContextFlag::GpDirtyPipelineState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxvkContext::setMultisampleState(
|
|
|
|
const Rc<DxvkMultisampleState>& state) {
|
|
|
|
if (m_state.co.multisampleState != state) {
|
|
|
|
m_state.co.multisampleState = state;
|
|
|
|
m_state.flags.set(DxvkContextFlag::GpDirtyPipelineState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxvkContext::setDepthStencilState(
|
|
|
|
const Rc<DxvkDepthStencilState>& state) {
|
|
|
|
if (m_state.co.depthStencilState != state) {
|
|
|
|
m_state.co.depthStencilState = state;
|
|
|
|
m_state.flags.set(DxvkContextFlag::GpDirtyPipelineState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxvkContext::setBlendState(
|
|
|
|
const Rc<DxvkBlendState>& state) {
|
|
|
|
if (m_state.co.blendState != state) {
|
|
|
|
m_state.co.blendState = state;
|
|
|
|
m_state.flags.set(DxvkContextFlag::GpDirtyPipelineState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
void DxvkContext::renderPassBegin() {
|
|
|
|
if (!m_state.flags.test(DxvkContextFlag::GpRenderPassBound)
|
|
|
|
&& (m_state.om.framebuffer != nullptr)) {
|
|
|
|
m_state.flags.set(DxvkContextFlag::GpRenderPassBound);
|
2017-10-13 03:19:23 +02:00
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
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;
|
2017-10-15 19:23:10 +02:00
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
m_cmd->cmdBeginRenderPass(&info,
|
|
|
|
VK_SUBPASS_CONTENTS_INLINE);
|
2017-10-15 19:23:10 +02:00
|
|
|
}
|
2017-10-11 23:29:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
void DxvkContext::renderPassEnd() {
|
|
|
|
if (m_state.flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
|
|
|
m_state.flags.clr(DxvkContextFlag::GpRenderPassBound);
|
|
|
|
m_cmd->cmdEndRenderPass();
|
|
|
|
}
|
2017-10-11 23:29:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
void DxvkContext::bindGraphicsPipeline() {
|
|
|
|
if (m_state.flags.test(DxvkContextFlag::GpDirtyPipeline)) {
|
|
|
|
m_state.flags.clr(DxvkContextFlag::GpDirtyPipeline);
|
2017-10-11 23:29:05 +02:00
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
m_state.activeGraphicsPipeline = m_pipeMgr->getGraphicsPipeline(
|
|
|
|
m_state.vs.shader, m_state.tcs.shader, m_state.tes.shader,
|
|
|
|
m_state.gs.shader, m_state.fs.shader);
|
|
|
|
}
|
2017-10-11 23:29:05 +02:00
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
if (m_state.flags.test(DxvkContextFlag::GpDirtyPipelineState)
|
|
|
|
&& m_state.activeGraphicsPipeline != nullptr) {
|
|
|
|
m_state.flags.clr(DxvkContextFlag::GpDirtyPipelineState);
|
|
|
|
|
|
|
|
DxvkGraphicsPipelineStateInfo gpState;
|
2017-11-20 13:38:24 +01:00
|
|
|
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;
|
2017-11-17 19:49:44 +01:00
|
|
|
|
|
|
|
m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
|
|
m_state.activeGraphicsPipeline->getPipelineHandle(gpState));
|
2017-11-20 14:11:09 +01:00
|
|
|
m_cmd->trackResource(m_state.activeGraphicsPipeline);
|
2017-10-15 17:56:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-20 13:21:27 +01:00
|
|
|
void DxvkContext::bindDynamicState() {
|
|
|
|
if (m_state.flags.test(DxvkContextFlag::GpDirtyDynamicState)) {
|
|
|
|
m_state.flags.clr(DxvkContextFlag::GpDirtyDynamicState);
|
|
|
|
|
|
|
|
// TODO implement
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxvkContext::bindIndexBuffer() {
|
|
|
|
if (m_state.flags.test(DxvkContextFlag::GpDirtyIndexBuffer)) {
|
|
|
|
m_state.flags.clr(DxvkContextFlag::GpDirtyIndexBuffer);
|
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxvkContext::bindVertexBuffers() {
|
|
|
|
if (m_state.flags.test(DxvkContextFlag::GpDirtyVertexBuffers)) {
|
|
|
|
m_state.flags.clr(DxvkContextFlag::GpDirtyVertexBuffers);
|
|
|
|
|
|
|
|
// TODO implement
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-20 14:11:09 +01:00
|
|
|
void DxvkContext::commitGraphicsState() {
|
2017-11-17 19:49:44 +01:00
|
|
|
this->renderPassBegin();
|
|
|
|
this->bindGraphicsPipeline();
|
2017-11-20 13:21:27 +01:00
|
|
|
this->bindDynamicState();
|
|
|
|
this->bindIndexBuffer();
|
|
|
|
this->bindVertexBuffers();
|
2017-10-15 17:56:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-17 19:49:44 +01:00
|
|
|
DxvkShaderStageState* DxvkContext::getShaderStage(VkShaderStageFlagBits stage) {
|
2017-10-13 03:19:23 +02:00
|
|
|
switch (stage) {
|
2017-11-17 19:49:44 +01:00
|
|
|
case VK_SHADER_STAGE_VERTEX_BIT: return &m_state.vs;
|
|
|
|
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return &m_state.tcs;
|
|
|
|
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return &m_state.tes;
|
|
|
|
case VK_SHADER_STAGE_GEOMETRY_BIT: return &m_state.gs;
|
|
|
|
case VK_SHADER_STAGE_FRAGMENT_BIT: return &m_state.fs;
|
|
|
|
case VK_SHADER_STAGE_COMPUTE_BIT: return &m_state.cs;
|
2017-10-13 03:19:23 +02:00
|
|
|
|
|
|
|
default:
|
2017-11-17 19:49:44 +01:00
|
|
|
throw DxvkError(str::format(
|
|
|
|
"DxvkContext::getShaderStage: Invalid stage bit: ",
|
|
|
|
static_cast<uint32_t>(stage)));
|
2017-10-13 03:19:23 +02:00
|
|
|
}
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|