mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-11-29 01:24:11 +01:00
[dxvk] DxvkContext now supports clears and actual state tracking
This commit is contained in:
parent
20048db69d
commit
94af8140d2
@ -24,56 +24,128 @@ namespace dxvk {
|
||||
|
||||
bool DxvkContext::endRecording() {
|
||||
TRACE(this);
|
||||
|
||||
if (m_state.fb.flags.test(DxvkFbStateFlags::InsideRenderPass))
|
||||
this->endRenderPass();
|
||||
|
||||
// Finalize the command list
|
||||
m_commandList->endRecording();
|
||||
m_commandList = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::clearRenderTarget(
|
||||
const VkClearAttachment& attachment,
|
||||
const VkClearRect& clearArea) {
|
||||
if (!m_state.fb.flags.test(DxvkFbStateFlags::InsideRenderPass))
|
||||
this->beginRenderPass();
|
||||
|
||||
m_vkd->vkCmdClearAttachments(
|
||||
m_commandList->handle(),
|
||||
1, &attachment,
|
||||
1, &clearArea);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::draw(
|
||||
uint32_t vertexCount,
|
||||
uint32_t instanceCount,
|
||||
uint32_t firstVertex,
|
||||
uint32_t firstInstance) {
|
||||
this->prepareDraw();
|
||||
m_vkd->vkCmdDraw(
|
||||
m_commandList->handle(),
|
||||
vertexCount,
|
||||
instanceCount,
|
||||
firstVertex,
|
||||
firstInstance);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::drawIndexed(
|
||||
uint32_t indexCount,
|
||||
uint32_t instanceCount,
|
||||
uint32_t firstIndex,
|
||||
uint32_t vertexOffset,
|
||||
uint32_t firstInstance) {
|
||||
this->prepareDraw();
|
||||
m_vkd->vkCmdDrawIndexed(
|
||||
m_commandList->handle(),
|
||||
indexCount,
|
||||
instanceCount,
|
||||
firstIndex,
|
||||
vertexOffset,
|
||||
firstInstance);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::setFramebuffer(
|
||||
const Rc<DxvkFramebuffer>& fb) {
|
||||
TRACE(this, fb);
|
||||
|
||||
const DxvkFramebufferSize fbSize = fb->size();
|
||||
// TODO implement properly
|
||||
VkRect2D renderArea;
|
||||
renderArea.offset.x = 0;
|
||||
renderArea.offset.y = 0;
|
||||
renderArea.extent.width = fbSize.width;
|
||||
renderArea.extent.height = fbSize.height;
|
||||
// When changing the framebuffer binding, we end the
|
||||
// current render pass, but beginning the new render
|
||||
// pass is deferred until a draw command is called.
|
||||
if (m_state.fb.framebuffer != fb) {
|
||||
if (m_state.fb.flags.test(DxvkFbStateFlags::InsideRenderPass))
|
||||
this->endRenderPass();
|
||||
|
||||
m_state.fb.framebuffer = fb;
|
||||
m_commandList->trackResource(fb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::setShader(
|
||||
VkShaderStageFlagBits stage,
|
||||
const Rc<DxvkShader>& shader) {
|
||||
TRACE(this, stage, shader);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::flushGraphicsState() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::prepareDraw() {
|
||||
this->flushGraphicsState();
|
||||
|
||||
if (!m_state.fb.flags.test(DxvkFbStateFlags::InsideRenderPass))
|
||||
this->beginRenderPass();
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::beginRenderPass() {
|
||||
TRACE(this);
|
||||
|
||||
const DxvkFramebufferSize fbsize
|
||||
= m_state.fb.framebuffer->size();
|
||||
|
||||
VkRenderPassBeginInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.renderPass = fb->renderPass();
|
||||
info.framebuffer = fb->handle();
|
||||
info.renderArea = renderArea;
|
||||
info.renderPass = m_state.fb.framebuffer->renderPass();
|
||||
info.framebuffer = m_state.fb.framebuffer->handle();
|
||||
info.renderArea = VkRect2D { { 0, 0 }, { fbsize.width, fbsize.height } };
|
||||
info.clearValueCount = 0;
|
||||
info.pClearValues = nullptr;
|
||||
|
||||
// This is for testing purposes only.
|
||||
VkClearAttachment attachment;
|
||||
attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
attachment.colorAttachment = 0;
|
||||
attachment.clearValue.color.float32[0] = 1.0f;
|
||||
attachment.clearValue.color.float32[1] = 1.0f;
|
||||
attachment.clearValue.color.float32[2] = 1.0f;
|
||||
attachment.clearValue.color.float32[3] = 1.0f;
|
||||
|
||||
VkClearRect clearRect;
|
||||
clearRect.rect = renderArea;
|
||||
clearRect.baseArrayLayer = 0;
|
||||
clearRect.layerCount = fbSize.layers;
|
||||
|
||||
m_vkd->vkCmdBeginRenderPass(
|
||||
m_commandList->handle(), &info,
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
m_vkd->vkCmdClearAttachments(
|
||||
m_commandList->handle(),
|
||||
1, &attachment,
|
||||
1, &clearRect);
|
||||
m_vkd->vkCmdEndRenderPass(
|
||||
m_commandList->handle());
|
||||
&info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
m_state.fb.flags.set(DxvkFbStateFlags::InsideRenderPass);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::endRenderPass() {
|
||||
TRACE(this);
|
||||
|
||||
m_vkd->vkCmdEndRenderPass(m_commandList->handle());
|
||||
m_state.fb.flags.clr(DxvkFbStateFlags::InsideRenderPass);
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#define DXVK_ERROR_CHECKING 1
|
||||
|
||||
#include "dxvk_cmdlist.h"
|
||||
#include "dxvk_framebuffer.h"
|
||||
#include "dxvk_context_state.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
@ -49,6 +51,46 @@ namespace dxvk {
|
||||
*/
|
||||
bool endRecording();
|
||||
|
||||
/**
|
||||
* \brief Clears an active render target
|
||||
*
|
||||
* \param [in] attachment Attachment to clear
|
||||
* \param [in] clearArea Rectangular area to clear
|
||||
*/
|
||||
void clearRenderTarget(
|
||||
const VkClearAttachment& attachment,
|
||||
const VkClearRect& clearArea);
|
||||
|
||||
/**
|
||||
* \brief Draws primitive without using an index buffer
|
||||
*
|
||||
* \param [in] vertexCount Number of vertices to draw
|
||||
* \param [in] instanceCount Number of instances to render
|
||||
* \param [in] firstVertex First vertex in vertex buffer
|
||||
* \param [in] firstInstance First instance ID
|
||||
*/
|
||||
void draw(
|
||||
uint32_t vertexCount,
|
||||
uint32_t instanceCount,
|
||||
uint32_t firstVertex,
|
||||
uint32_t firstInstance);
|
||||
|
||||
/**
|
||||
* \brief Draws primitives using an index buffer
|
||||
*
|
||||
* \param [in] indexCount Number of indices to draw
|
||||
* \param [in] instanceCount Number of instances to render
|
||||
* \param [in] firstIndex First index within the index buffer
|
||||
* \param [in] vertexOffset Vertex ID that corresponds to index 0
|
||||
* \param [in] firstInstance First instance ID
|
||||
*/
|
||||
void drawIndexed(
|
||||
uint32_t indexCount,
|
||||
uint32_t instanceCount,
|
||||
uint32_t firstIndex,
|
||||
uint32_t vertexOffset,
|
||||
uint32_t firstInstance);
|
||||
|
||||
/**
|
||||
* \brief Sets framebuffer
|
||||
* \param [in] fb Framebuffer
|
||||
@ -56,10 +98,39 @@ namespace dxvk {
|
||||
void setFramebuffer(
|
||||
const Rc<DxvkFramebuffer>& fb);
|
||||
|
||||
/**
|
||||
* \brief Sets shader for a given shader stage
|
||||
*
|
||||
* Binds a shader to a given stage, while unbinding the
|
||||
* existing one. If \c nullptr is passed as the shader
|
||||
* to bind, the given shader stage will be disabled.
|
||||
* When drawing, at least a vertex shader must be bound.
|
||||
* \param [in] stage The shader stage
|
||||
* \param [in] shader The shader to set
|
||||
*/
|
||||
void setShader(
|
||||
VkShaderStageFlagBits stage,
|
||||
const Rc<DxvkShader>& shader);
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
Rc<DxvkCommandList> m_commandList;
|
||||
DxvkContextState m_state;
|
||||
|
||||
/**
|
||||
* \brief Forces a graphics pipeline state flush
|
||||
*
|
||||
* Applies current shader bindings, resource bindings
|
||||
* etc. to the command buffer so that draw calls can
|
||||
* be executed. Called whenever the need arises.
|
||||
*/
|
||||
void flushGraphicsState();
|
||||
|
||||
void prepareDraw();
|
||||
|
||||
void beginRenderPass();
|
||||
void endRenderPass();
|
||||
|
||||
};
|
||||
|
||||
|
@ -1,9 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_cmdlist.h"
|
||||
#include "dxvk_framebuffer.h"
|
||||
#include "dxvk_shader.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
enum class DxvkFbStateFlags : uint32_t {
|
||||
InsideRenderPass = 0,
|
||||
};
|
||||
|
||||
struct DxvkFramebufferState {
|
||||
Rc<DxvkFramebuffer> framebuffer;
|
||||
Flags<DxvkFbStateFlags> flags;
|
||||
};
|
||||
|
||||
struct DxvkContextState {
|
||||
DxvkFramebufferState fb; ///< Framebuffer and render pass
|
||||
};
|
||||
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
#include "dxvk_framebuffer.h"
|
||||
#include "dxvk_memory.h"
|
||||
#include "dxvk_renderpass.h"
|
||||
#include "dxvk_shader.h"
|
||||
#include "dxvk_swapchain.h"
|
||||
#include "dxvk_sync.h"
|
||||
|
||||
@ -111,6 +112,15 @@ namespace dxvk {
|
||||
*/
|
||||
Rc<DxvkSemaphore> createSemaphore();
|
||||
|
||||
/**
|
||||
* \brief Creates a shader module
|
||||
*
|
||||
* \param [in] code SPIR-V code
|
||||
* \returns Shader module
|
||||
*/
|
||||
Rc<DxvkShader> createShader(
|
||||
const SpirvCodeBuffer& code);
|
||||
|
||||
/**
|
||||
* \brief Creates a swap chain
|
||||
*
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "../util/log/log_debug.h"
|
||||
|
||||
#include "../util/util_error.h"
|
||||
#include "../util/util_flags.h"
|
||||
#include "../util/util_string.h"
|
||||
|
||||
#include "../util/rc/util_rc.h"
|
||||
|
@ -2,7 +2,6 @@ dxvk_src = files([
|
||||
'dxvk_adapter.cpp',
|
||||
'dxvk_cmdlist.cpp',
|
||||
'dxvk_context.cpp',
|
||||
'dxvk_context_state.cpp',
|
||||
'dxvk_device.cpp',
|
||||
'dxvk_framebuffer.cpp',
|
||||
'dxvk_image.cpp',
|
||||
@ -12,10 +11,13 @@ dxvk_src = files([
|
||||
'dxvk_memory.cpp',
|
||||
'dxvk_renderpass.cpp',
|
||||
'dxvk_resource.cpp',
|
||||
'dxvk_shader.cpp',
|
||||
'dxvk_surface.cpp',
|
||||
'dxvk_swapchain.cpp',
|
||||
'dxvk_sync.cpp',
|
||||
|
||||
'spirv/dxvk_spirv_code_buffer.cpp',
|
||||
|
||||
'vulkan/dxvk_vulkan_extensions.cpp',
|
||||
'vulkan/dxvk_vulkan_loader.cpp',
|
||||
'vulkan/dxvk_vulkan_names.cpp',
|
||||
|
107
src/dxvk/spirv/dxvk_spirv_code_buffer.cpp
Normal file
107
src/dxvk/spirv/dxvk_spirv_code_buffer.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#include "dxvk_spirv_code_buffer.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
SpirvCodeBuffer:: SpirvCodeBuffer() { }
|
||||
SpirvCodeBuffer::~SpirvCodeBuffer() { }
|
||||
|
||||
|
||||
SpirvCodeBuffer::SpirvCodeBuffer(
|
||||
std::basic_istream<uint32_t>& stream)
|
||||
: m_code(
|
||||
std::istreambuf_iterator<uint32_t>(stream),
|
||||
std::istreambuf_iterator<uint32_t>()) { }
|
||||
|
||||
|
||||
void SpirvCodeBuffer::append(const SpirvCodeBuffer& other) {
|
||||
const size_t size = m_code.size();
|
||||
m_code.resize(size + other.m_code.size());
|
||||
|
||||
uint32_t* dst = this->m_code.data();
|
||||
const uint32_t* src = other.m_code.data();
|
||||
|
||||
std::memcpy(dst + size, src, sizeof(uint32_t) * size);
|
||||
}
|
||||
|
||||
|
||||
void SpirvCodeBuffer::putWord(uint32_t word) {
|
||||
m_code.push_back(word);
|
||||
}
|
||||
|
||||
|
||||
void SpirvCodeBuffer::putIns(spv::Op opCode, uint16_t wordCount) {
|
||||
this->putWord(
|
||||
(static_cast<uint32_t>(opCode) << 0)
|
||||
| (static_cast<uint32_t>(wordCount) << 16));
|
||||
}
|
||||
|
||||
|
||||
void SpirvCodeBuffer::putInt32(uint32_t word) {
|
||||
this->putWord(word);
|
||||
}
|
||||
|
||||
|
||||
void SpirvCodeBuffer::putInt64(uint64_t value) {
|
||||
this->putWord(value >> 0);
|
||||
this->putWord(value >> 32);
|
||||
}
|
||||
|
||||
|
||||
void SpirvCodeBuffer::putFloat32(float value) {
|
||||
uint32_t tmp;
|
||||
static_assert(sizeof(tmp) == sizeof(value));
|
||||
std::memcpy(&tmp, &value, sizeof(value));
|
||||
this->putInt32(tmp);
|
||||
}
|
||||
|
||||
|
||||
void SpirvCodeBuffer::putFloat64(double value) {
|
||||
uint64_t tmp;
|
||||
static_assert(sizeof(tmp) == sizeof(value));
|
||||
std::memcpy(&tmp, &value, sizeof(value));
|
||||
this->putInt64(tmp);
|
||||
}
|
||||
|
||||
|
||||
void SpirvCodeBuffer::putStr(const char* str) {
|
||||
uint32_t word = 0;
|
||||
uint32_t nbit = 0;
|
||||
|
||||
for (uint32_t i = 0; str[i] != '\0'; str++) {
|
||||
word |= (static_cast<uint32_t>(str[i]) & 0xFF) << nbit;
|
||||
|
||||
if ((nbit += 8) == 32) {
|
||||
this->putWord(word);
|
||||
word = 0;
|
||||
nbit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Commit current word
|
||||
this->putWord(word);
|
||||
}
|
||||
|
||||
|
||||
void SpirvCodeBuffer::putHeader(uint32_t boundIds) {
|
||||
this->putWord(spv::MagicNumber);
|
||||
this->putWord(spv::Version);
|
||||
this->putWord(0); // Generator
|
||||
this->putWord(boundIds);
|
||||
this->putWord(0); // Schema
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvCodeBuffer::strLen(const char* str) {
|
||||
// Null-termination plus padding
|
||||
return (std::strlen(str) + 4) / 4;
|
||||
}
|
||||
|
||||
|
||||
void SpirvCodeBuffer::store(std::basic_ostream<uint32_t>& stream) const {
|
||||
stream.write(m_code.data(), m_code.size());
|
||||
}
|
||||
|
||||
}
|
131
src/dxvk/spirv/dxvk_spirv_code_buffer.h
Normal file
131
src/dxvk/spirv/dxvk_spirv_code_buffer.h
Normal file
@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
#include <spirv/spirv.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "../dxvk_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief SPIR-V code buffer
|
||||
*
|
||||
* Helper class for generating SPIR-V shaders.
|
||||
* Stores arbitrary SPIR-V instructions in a
|
||||
* format that can be read by Vulkan drivers.
|
||||
*/
|
||||
class SpirvCodeBuffer {
|
||||
|
||||
public:
|
||||
|
||||
SpirvCodeBuffer();
|
||||
SpirvCodeBuffer(
|
||||
std::basic_istream<uint32_t>& stream);
|
||||
~SpirvCodeBuffer();
|
||||
|
||||
/**
|
||||
* \brief Code
|
||||
* \returns Code
|
||||
*/
|
||||
const uint32_t* code() const {
|
||||
return m_code.data();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Code size, in bytes
|
||||
* \returns Code size, in bytes
|
||||
*/
|
||||
size_t size() const {
|
||||
return m_code.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Merges two code buffers
|
||||
*
|
||||
* This is useful to generate declarations or
|
||||
* the SPIR-V header at the same time as the
|
||||
* code when doing so in advance is impossible.
|
||||
* \param [in] other Code buffer to append
|
||||
*/
|
||||
void append(const SpirvCodeBuffer& other);
|
||||
|
||||
/**
|
||||
* \brief Appends an 32-bit word to the buffer
|
||||
* \param [in] word The word to append
|
||||
*/
|
||||
void putWord(uint32_t word);
|
||||
|
||||
/**
|
||||
* \brief Appends an instruction word to the buffer
|
||||
*
|
||||
* Adds a single word containing both the word count
|
||||
* and the op code number for a single instruction.
|
||||
* \param [in] opCode Operand code
|
||||
* \param [in] wordCount Number of words
|
||||
*/
|
||||
void putIns(spv::Op opCode, uint16_t wordCount);
|
||||
|
||||
/**
|
||||
* \brief Appends a 32-bit integer to the buffer
|
||||
* \param [in] value The number to add
|
||||
*/
|
||||
void putInt32(uint32_t word);
|
||||
|
||||
/**
|
||||
* \brief Appends a 64-bit integer to the buffer
|
||||
*
|
||||
* A 64-bit integer will take up two 32-bit words.
|
||||
* \param [in] value 64-bit value to add
|
||||
*/
|
||||
void putInt64(uint64_t value);
|
||||
|
||||
/**
|
||||
* \brief Appends a 32-bit float to the buffer
|
||||
* \param [in] value The number to add
|
||||
*/
|
||||
void putFloat32(float value);
|
||||
|
||||
/**
|
||||
* \brief Appends a 64-bit float to the buffer
|
||||
* \param [in] value The number to add
|
||||
*/
|
||||
void putFloat64(double value);
|
||||
|
||||
/**
|
||||
* \brief Appends a literal string to the buffer
|
||||
* \param [in] str String to append to the buffer
|
||||
*/
|
||||
void putStr(const char* str);
|
||||
|
||||
/**
|
||||
* \brief Adds the header to the buffer
|
||||
* \param [in] boundIds Number of bound IDs
|
||||
*/
|
||||
void putHeader(uint32_t boundIds);
|
||||
|
||||
/**
|
||||
* \brief Computes length of a literal string
|
||||
*
|
||||
* \param [in] str The string to check
|
||||
* \returns Number of words consumed by a string
|
||||
*/
|
||||
uint32_t strLen(const char* str);
|
||||
|
||||
/**
|
||||
* \brief Stores the SPIR-V module to a stream
|
||||
*
|
||||
* The ability to save modules to a file
|
||||
* exists mostly for debugging purposes.
|
||||
* \param [in] stream Output stream
|
||||
*/
|
||||
void store(std::basic_ostream<uint32_t>& stream) const;
|
||||
|
||||
private:
|
||||
|
||||
std::vector<uint32_t> m_code;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -36,9 +36,28 @@ public:
|
||||
auto sync1 = m_dxvkDevice->createSemaphore();
|
||||
auto sync2 = m_dxvkDevice->createSemaphore();
|
||||
|
||||
auto fb = m_dxvkSwapchain->getFramebuffer(sync1);
|
||||
auto fbSize = fb->size();
|
||||
|
||||
m_dxvkContext->beginRecording(m_dxvkCommandList);
|
||||
m_dxvkContext->setFramebuffer(
|
||||
m_dxvkSwapchain->getFramebuffer(sync1));
|
||||
m_dxvkContext->setFramebuffer(fb);
|
||||
|
||||
VkClearAttachment clearAttachment;
|
||||
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
clearAttachment.colorAttachment = 0;
|
||||
clearAttachment.clearValue.color.float32[0] = 1.0f;
|
||||
clearAttachment.clearValue.color.float32[1] = 1.0f;
|
||||
clearAttachment.clearValue.color.float32[2] = 1.0f;
|
||||
clearAttachment.clearValue.color.float32[3] = 1.0f;
|
||||
|
||||
VkClearRect clearArea;
|
||||
clearArea.rect = VkRect2D { { 0, 0 }, fbSize.width, fbSize.height };
|
||||
clearArea.baseArrayLayer = 0;
|
||||
clearArea.layerCount = fbSize.layers;
|
||||
|
||||
m_dxvkContext->clearRenderTarget(
|
||||
clearAttachment,
|
||||
clearArea);
|
||||
m_dxvkContext->endRecording();
|
||||
|
||||
auto fence = m_dxvkDevice->submitCommandList(
|
||||
@ -57,7 +76,8 @@ private:
|
||||
Rc<DxvkContext> m_dxvkContext;
|
||||
Rc<DxvkCommandList> m_dxvkCommandList;
|
||||
|
||||
Rc<DxvkBuffer> m_vertexBuffer;
|
||||
Rc<DxvkShader> m_vertShader;
|
||||
Rc<DxvkShader> m_fragShader;
|
||||
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user