Swap chains, part 2 (#94)
This commit is contained in:
parent
3818e18c5c
commit
c16a67ae52
|
@ -23,9 +23,10 @@
|
|||
|
||||
nxt::Device device;
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
float RandomFloat(float min, float max) {
|
||||
float zeroOne = rand() / float(RAND_MAX);
|
||||
|
@ -47,6 +48,8 @@ void init() {
|
|||
device = CreateCppNXTDevice();
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
swapchain = GetSwapChain(device);
|
||||
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||
|
||||
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
|
@ -105,7 +108,9 @@ void init() {
|
|||
})"
|
||||
);
|
||||
|
||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
|
@ -124,6 +129,10 @@ void init() {
|
|||
}
|
||||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
|
||||
static int f = 0;
|
||||
f++;
|
||||
|
||||
|
@ -152,7 +161,9 @@ void frame() {
|
|||
}
|
||||
|
||||
queue.Submit(50, commands.data());
|
||||
DoSwapBuffers();
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
DoFlush();
|
||||
fprintf(stderr, "frame %i\n", f);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
nxtDevice device;
|
||||
nxtQueue queue;
|
||||
nxtSwapChain swapchain;
|
||||
nxtRenderPipeline pipeline;
|
||||
nxtRenderPass renderpass;
|
||||
nxtFramebuffer framebuffer;
|
||||
|
||||
void init() {
|
||||
device = CreateCppNXTDevice().Release();
|
||||
|
@ -32,6 +32,15 @@ void init() {
|
|||
nxtQueueBuilderRelease(builder);
|
||||
}
|
||||
|
||||
{
|
||||
nxtSwapChainBuilder builder = nxtDeviceCreateSwapChainBuilder(device);
|
||||
uint64_t swapchainImpl = GetSwapChainImplementation();
|
||||
nxtSwapChainBuilderSetImplementation(builder, swapchainImpl);
|
||||
swapchain = nxtSwapChainBuilderGetResult(builder);
|
||||
nxtSwapChainBuilderRelease(builder);
|
||||
}
|
||||
nxtSwapChainConfigure(swapchain, NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM, 640, 480);
|
||||
|
||||
const char* vs =
|
||||
"#version 450\n"
|
||||
"const vec2 pos[3] = vec2[3](vec2(0.0f, 0.5f), vec2(-0.5f, -0.5f), vec2(0.5f, -0.5f));\n"
|
||||
|
@ -57,13 +66,6 @@ void init() {
|
|||
renderpass = nxtRenderPassBuilderGetResult(builder);
|
||||
nxtRenderPassBuilderRelease(builder);
|
||||
}
|
||||
{
|
||||
nxtFramebufferBuilder builder = nxtDeviceCreateFramebufferBuilder(device);
|
||||
nxtFramebufferBuilderSetRenderPass(builder, renderpass);
|
||||
nxtFramebufferBuilderSetDimensions(builder, 640, 480);
|
||||
framebuffer = nxtFramebufferBuilderGetResult(builder);
|
||||
nxtFramebufferBuilderRelease(builder);
|
||||
}
|
||||
{
|
||||
nxtRenderPipelineBuilder builder = nxtDeviceCreateRenderPipelineBuilder(device);
|
||||
nxtRenderPipelineBuilderSetSubpass(builder, renderpass, 0);
|
||||
|
@ -78,6 +80,22 @@ void init() {
|
|||
}
|
||||
|
||||
void frame() {
|
||||
nxtTexture backbuffer = nxtSwapChainGetNextTexture(swapchain);
|
||||
nxtTextureView backbufferView;
|
||||
{
|
||||
nxtTextureViewBuilder builder = nxtTextureCreateTextureViewBuilder(backbuffer);
|
||||
backbufferView = nxtTextureViewBuilderGetResult(builder);
|
||||
nxtTextureViewBuilderRelease(builder);
|
||||
}
|
||||
nxtFramebuffer framebuffer;
|
||||
{
|
||||
nxtFramebufferBuilder builder = nxtDeviceCreateFramebufferBuilder(device);
|
||||
nxtFramebufferBuilderSetRenderPass(builder, renderpass);
|
||||
nxtFramebufferBuilderSetDimensions(builder, 640, 480);
|
||||
nxtFramebufferBuilderSetAttachment(builder, 0, backbufferView);
|
||||
framebuffer = nxtFramebufferBuilderGetResult(builder);
|
||||
nxtFramebufferBuilderRelease(builder);
|
||||
}
|
||||
nxtCommandBuffer commands;
|
||||
{
|
||||
nxtCommandBufferBuilder builder = nxtDeviceCreateCommandBufferBuilder(device);
|
||||
|
@ -93,8 +111,12 @@ void frame() {
|
|||
|
||||
nxtQueueSubmit(queue, 1, &commands);
|
||||
nxtCommandBufferRelease(commands);
|
||||
nxtTextureTransitionUsage(backbuffer, NXT_TEXTURE_USAGE_BIT_PRESENT);
|
||||
nxtSwapChainPresent(swapchain, backbuffer);
|
||||
nxtFramebufferRelease(framebuffer);
|
||||
nxtTextureViewRelease(backbufferView);
|
||||
|
||||
DoSwapBuffers();
|
||||
DoFlush();
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
|
|
@ -25,20 +25,19 @@
|
|||
|
||||
nxt::Device device;
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
|
||||
nxt::Buffer modelBuffer;
|
||||
std::array<nxt::Buffer, 2> particleBuffers;
|
||||
|
||||
nxt::RenderPipeline renderPipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
nxt::Buffer updateParams;
|
||||
nxt::ComputePipeline updatePipeline;
|
||||
std::array<nxt::BindGroup, 2> updateBGs;
|
||||
|
||||
std::array<nxt::CommandBuffer, 2> commandBuffers;
|
||||
|
||||
size_t pingpong = 0;
|
||||
|
||||
static const uint32_t kNumParticles = 1000;
|
||||
|
@ -124,7 +123,9 @@ void initRender() {
|
|||
.SetInput(1, sizeof(glm::vec2), nxt::InputStepMode::Vertex)
|
||||
.GetResult();
|
||||
|
||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
renderPipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
|
@ -259,12 +260,11 @@ void initSim() {
|
|||
}
|
||||
}
|
||||
|
||||
void initCommandBuffers() {
|
||||
nxt::CommandBuffer createCommandBuffer(const nxt::Framebuffer& framebuffer, size_t i) {
|
||||
static const uint32_t zeroOffsets[1] = {0};
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
auto& bufferSrc = particleBuffers[i];
|
||||
auto& bufferDst = particleBuffers[(i + 1) % 2];
|
||||
commandBuffers[i] = device.CreateCommandBufferBuilder()
|
||||
return device.CreateCommandBufferBuilder()
|
||||
.BeginComputePass()
|
||||
.SetComputePipeline(updatePipeline)
|
||||
.TransitionBufferUsage(bufferSrc, nxt::BufferUsageBit::Storage)
|
||||
|
@ -285,22 +285,29 @@ void initCommandBuffers() {
|
|||
|
||||
.GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
void init() {
|
||||
device = CreateCppNXTDevice();
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
swapchain = GetSwapChain(device);
|
||||
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||
|
||||
initBuffers();
|
||||
initRender();
|
||||
initSim();
|
||||
initCommandBuffers();
|
||||
}
|
||||
|
||||
void frame() {
|
||||
queue.Submit(1, &commandBuffers[pingpong]);
|
||||
DoSwapBuffers();
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
|
||||
nxt::CommandBuffer commandBuffer = createCommandBuffer(framebuffer, pingpong);
|
||||
queue.Submit(1, &commandBuffer);
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
DoFlush();
|
||||
|
||||
pingpong = (pingpong + 1) % 2;
|
||||
}
|
||||
|
|
|
@ -21,11 +21,12 @@
|
|||
|
||||
nxt::Device device;
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::Buffer buffer;
|
||||
nxt::RenderPipeline renderPipeline;
|
||||
nxt::BindGroup renderBindGroup;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::ComputePipeline computePipeline;
|
||||
nxt::BindGroup computeBindGroup;
|
||||
|
||||
|
@ -33,6 +34,8 @@ void init() {
|
|||
device = CreateCppNXTDevice();
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
swapchain = GetSwapChain(device);
|
||||
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||
|
||||
struct {uint32_t a; float b;} s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
|
@ -109,7 +112,9 @@ void init() {
|
|||
.SetBindGroupLayout(0, bgl)
|
||||
.GetResult();
|
||||
|
||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
renderPipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetLayout(pl)
|
||||
|
@ -126,6 +131,10 @@ void init() {
|
|||
}
|
||||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginComputePass()
|
||||
.SetComputePipeline(computePipeline)
|
||||
|
@ -146,7 +155,9 @@ void frame() {
|
|||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
DoSwapBuffers();
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
DoFlush();
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
|
|
@ -35,11 +35,12 @@ nxt::BindGroup bindGroup[2];
|
|||
nxt::BindGroup cubeTransformBindGroup[2];
|
||||
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPipeline planePipeline;
|
||||
nxt::RenderPipeline reflectionPipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
void initBuffers() {
|
||||
static const uint32_t indexData[6*6] = {
|
||||
|
@ -114,6 +115,8 @@ void init() {
|
|||
device = CreateCppNXTDevice();
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
swapchain = GetSwapChain(device);
|
||||
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||
|
||||
initBuffers();
|
||||
|
||||
|
@ -206,7 +209,8 @@ void init() {
|
|||
.SetBufferViews(1, 1, &transformBufferView[1])
|
||||
.GetResult();
|
||||
|
||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
auto depthStencilState = device.CreateDepthStencilStateBuilder()
|
||||
.SetDepthCompareFunction(nxt::CompareFunction::Less)
|
||||
|
@ -271,6 +275,10 @@ void frame() {
|
|||
cameraBuffer.TransitionUsage(nxt::BufferUsageBit::TransferDst);
|
||||
cameraBuffer.SetSubData(0, sizeof(CameraData) / sizeof(uint32_t), reinterpret_cast<uint32_t*>(&cameraData));
|
||||
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
|
@ -296,7 +304,9 @@ void frame() {
|
|||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
DoSwapBuffers();
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
DoFlush();
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
|
|
@ -25,9 +25,10 @@ nxt::Buffer indexBuffer;
|
|||
nxt::Buffer vertexBuffer;
|
||||
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
void initBuffers() {
|
||||
static const uint32_t indexData[3] = {
|
||||
|
@ -47,6 +48,8 @@ void init() {
|
|||
device = CreateCppNXTDevice();
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
swapchain = GetSwapChain(device);
|
||||
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||
|
||||
initBuffers();
|
||||
|
||||
|
@ -71,7 +74,9 @@ void init() {
|
|||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||
.GetResult();
|
||||
|
||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
|
@ -81,6 +86,10 @@ void init() {
|
|||
}
|
||||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
|
@ -94,7 +103,9 @@ void frame() {
|
|||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
DoSwapBuffers();
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
DoFlush();
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
|
|
@ -25,9 +25,10 @@ nxt::Buffer vertexBuffer;
|
|||
nxt::Buffer instanceBuffer;
|
||||
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
void initBuffers() {
|
||||
static const float vertexData[12] = {
|
||||
|
@ -50,6 +51,8 @@ void init() {
|
|||
device = CreateCppNXTDevice();
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
swapchain = GetSwapChain(device);
|
||||
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||
|
||||
initBuffers();
|
||||
|
||||
|
@ -77,7 +80,9 @@ void init() {
|
|||
.SetInput(1, 2 * sizeof(float), nxt::InputStepMode::Instance)
|
||||
.GetResult();
|
||||
|
||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
|
@ -87,6 +92,10 @@ void init() {
|
|||
}
|
||||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
|
@ -100,7 +109,9 @@ void frame() {
|
|||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
DoSwapBuffers();
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
DoFlush();
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
|
|
@ -28,9 +28,10 @@ nxt::Texture texture;
|
|||
nxt::Sampler sampler;
|
||||
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::BindGroup bindGroup;
|
||||
|
||||
void initBuffers() {
|
||||
|
@ -81,6 +82,8 @@ void init() {
|
|||
device = CreateCppNXTDevice();
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
swapchain = GetSwapChain(device);
|
||||
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||
|
||||
initBuffers();
|
||||
initTextures();
|
||||
|
@ -118,7 +121,9 @@ void init() {
|
|||
.SetBindGroupLayout(0, bgl)
|
||||
.GetResult();
|
||||
|
||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetLayout(pl)
|
||||
|
@ -142,6 +147,11 @@ void frame() {
|
|||
s.a = (s.a + 1) % 256;
|
||||
s.b += 0.02f;
|
||||
if (s.b >= 1.0f) {s.b = 0.0f;}
|
||||
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
|
@ -156,7 +166,9 @@ void frame() {
|
|||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
DoSwapBuffers();
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
DoFlush();
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
|
||||
nxt::Device device;
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::Buffer buffer;
|
||||
nxt::BindGroup bindGroup;
|
||||
|
||||
|
@ -31,6 +32,8 @@ void init() {
|
|||
device = CreateCppNXTDevice();
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
swapchain = GetSwapChain(device);
|
||||
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||
|
||||
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
|
@ -60,7 +63,9 @@ void init() {
|
|||
.SetBindGroupLayout(0, bgl)
|
||||
.GetResult();
|
||||
|
||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetLayout(pl)
|
||||
|
@ -93,6 +98,10 @@ void frame() {
|
|||
buffer.TransitionUsage(nxt::BufferUsageBit::TransferDst);
|
||||
buffer.SetSubData(0, sizeof(s) / sizeof(uint32_t), reinterpret_cast<uint32_t*>(&s));
|
||||
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
|
@ -105,7 +114,9 @@ void frame() {
|
|||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
DoSwapBuffers();
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
DoFlush();
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
|
|
@ -24,9 +24,10 @@ nxt::Device device;
|
|||
nxt::Buffer vertexBuffer;
|
||||
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
void initBuffers() {
|
||||
static const float vertexData[12] = {
|
||||
|
@ -41,6 +42,8 @@ void init() {
|
|||
device = CreateCppNXTDevice();
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
swapchain = GetSwapChain(device);
|
||||
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||
|
||||
initBuffers();
|
||||
|
||||
|
@ -65,7 +68,9 @@ void init() {
|
|||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||
.GetResult();
|
||||
|
||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
|
@ -75,6 +80,10 @@ void init() {
|
|||
}
|
||||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
|
@ -87,7 +96,9 @@ void frame() {
|
|||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
DoSwapBuffers();
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
DoFlush();
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
|
|
@ -29,11 +29,11 @@ nxt::TextureView renderTargetView;
|
|||
nxt::Sampler samplerPost;
|
||||
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPipeline pipelinePost;
|
||||
nxt::BindGroup bindGroup;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
|
||||
void initBuffers() {
|
||||
static const float vertexData[12] = {
|
||||
|
@ -81,14 +81,6 @@ void initRenderPass() {
|
|||
// subpass 1
|
||||
.SubpassSetColorAttachment(1, 0, 1) // -> back buffer
|
||||
.GetResult();
|
||||
framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
// attachment 0 -> render target
|
||||
.SetAttachment(0, renderTargetView)
|
||||
// attachment 1 -> back buffer
|
||||
// (implicit) // TODO(kainino@chromium.org): use the texture provided by WSI
|
||||
.SetDimensions(640, 480)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
void initPipeline() {
|
||||
|
@ -174,6 +166,8 @@ void init() {
|
|||
device = CreateCppNXTDevice();
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
swapchain = GetSwapChain(device);
|
||||
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||
|
||||
initBuffers();
|
||||
initTextures();
|
||||
|
@ -183,6 +177,15 @@ void init() {
|
|||
}
|
||||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer = swapchain.GetNextTexture();
|
||||
auto backbufferView = backbuffer.CreateTextureViewBuilder().GetResult();
|
||||
auto framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(640, 480)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
.SetAttachment(1, backbufferView)
|
||||
.GetResult();
|
||||
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
|
@ -204,7 +207,9 @@ void frame() {
|
|||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
DoSwapBuffers();
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
DoFlush();
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <nxt/nxt.h>
|
||||
#include <nxt/nxtcpp.h>
|
||||
#include <nxt/nxt_wsi.h>
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
#include <cstring>
|
||||
|
@ -39,9 +40,9 @@ enum class CmdBufType {
|
|||
static utils::BackendType backendType = utils::BackendType::D3D12;
|
||||
#elif defined(NXT_ENABLE_BACKEND_METAL)
|
||||
static utils::BackendType backendType = utils::BackendType::Metal;
|
||||
#elif defined(NXT_ENABLE_BACKEND_VULKAN)
|
||||
static utils::BackendType backendType = utils::BackendType::OpenGL;
|
||||
#elif defined(NXT_ENABLE_BACKEND_OPENGL)
|
||||
static utils::BackendType backendType = utils::BackendType::OpenGL;
|
||||
#elif defined(NXT_ENABLE_BACKEND_VULKAN)
|
||||
static utils::BackendType backendType = utils::BackendType::Vulkan;
|
||||
#else
|
||||
#error
|
||||
|
@ -111,6 +112,56 @@ nxt::Device CreateCppNXTDevice() {
|
|||
return nxt::Device::Acquire(cDevice);
|
||||
}
|
||||
|
||||
uint64_t GetSwapChainImplementation() {
|
||||
return binding->GetSwapChainImplementation();
|
||||
}
|
||||
|
||||
nxt::SwapChain GetSwapChain(const nxt::Device &device) {
|
||||
return device.CreateSwapChainBuilder()
|
||||
.SetImplementation(GetSwapChainImplementation())
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
nxt::RenderPass CreateDefaultRenderPass(const nxt::Device& device) {
|
||||
return device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(2)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetFormat(1, nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.SubpassSetDepthStencilAttachment(0, 1)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
nxt::TextureView CreateDefaultDepthStencilView(const nxt::Device& device) {
|
||||
auto depthStencilTexture = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(640, 480, 1)
|
||||
.SetFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
depthStencilTexture.FreezeUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
return depthStencilTexture.CreateTextureViewBuilder()
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
void GetNextFramebuffer(const nxt::Device& device,
|
||||
const nxt::RenderPass& renderpass,
|
||||
const nxt::SwapChain& swapchain,
|
||||
const nxt::TextureView& depthStencilView,
|
||||
nxt::Texture* backbuffer,
|
||||
nxt::Framebuffer* framebuffer) {
|
||||
*backbuffer = swapchain.GetNextTexture();
|
||||
auto backbufferView = backbuffer->CreateTextureViewBuilder().GetResult();
|
||||
*framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(640, 480)
|
||||
.SetAttachment(0, backbufferView)
|
||||
.SetAttachment(1, depthStencilView)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
bool InitSample(int argc, const char** argv) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) {
|
||||
|
@ -138,7 +189,7 @@ bool InitSample(int argc, const char** argv) {
|
|||
fprintf(stderr, "--backend expects a backend name (opengl, metal, d3d12, null, vulkan)\n");
|
||||
return false;
|
||||
}
|
||||
if (std::string("-c") == argv[i] || std::string("--comand-buffer") == argv[i]) {
|
||||
if (std::string("-c") == argv[i] || std::string("--command-buffer") == argv[i]) {
|
||||
i++;
|
||||
if (i < argc && std::string("none") == argv[i]) {
|
||||
cmdBufType = CmdBufType::None;
|
||||
|
@ -161,13 +212,12 @@ bool InitSample(int argc, const char** argv) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void DoSwapBuffers() {
|
||||
void DoFlush() {
|
||||
if (cmdBufType == CmdBufType::Terrible) {
|
||||
c2sBuf->Flush();
|
||||
s2cBuf->Flush();
|
||||
}
|
||||
glfwPollEvents();
|
||||
binding->SwapBuffers();
|
||||
}
|
||||
|
||||
bool ShouldQuit() {
|
||||
|
|
|
@ -13,12 +13,23 @@
|
|||
// limitations under the License.
|
||||
|
||||
#include <nxt/nxtcpp.h>
|
||||
#include <nxt/nxt_wsi.h>
|
||||
|
||||
bool InitSample(int argc, const char** argv);
|
||||
void DoSwapBuffers();
|
||||
void DoFlush();
|
||||
bool ShouldQuit();
|
||||
|
||||
struct GLFWwindow;
|
||||
struct GLFWwindow* GetGLFWWindow();
|
||||
|
||||
nxt::Device CreateCppNXTDevice();
|
||||
uint64_t GetSwapChainImplementation();
|
||||
nxt::SwapChain GetSwapChain(const nxt::Device& device);
|
||||
nxt::RenderPass CreateDefaultRenderPass(const nxt::Device& device);
|
||||
nxt::TextureView CreateDefaultDepthStencilView(const nxt::Device& device);
|
||||
void GetNextFramebuffer(const nxt::Device& device,
|
||||
const nxt::RenderPass& renderPass,
|
||||
const nxt::SwapChain& swapchain,
|
||||
const nxt::TextureView& depthStencilView,
|
||||
nxt::Texture* backbuffer,
|
||||
nxt::Framebuffer* framebuffer);
|
||||
|
|
|
@ -77,8 +77,10 @@ struct u_transform_block {
|
|||
|
||||
nxt::Device device;
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::Framebuffer lastFramebuffer;
|
||||
|
||||
nxt::Buffer defaultBuffer;
|
||||
std::map<std::string, nxt::Buffer> buffers;
|
||||
|
@ -467,7 +469,11 @@ namespace {
|
|||
device = CreateCppNXTDevice();
|
||||
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
swapchain = GetSwapChain(device);
|
||||
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
initBuffers();
|
||||
initSamplers();
|
||||
|
@ -506,7 +512,7 @@ namespace {
|
|||
material.uniformBuffer.SetSubData(0,
|
||||
sizeof(u_transform_block) / sizeof(uint32_t),
|
||||
reinterpret_cast<const uint32_t*>(&transforms));
|
||||
cmd.BeginRenderPass(renderpass, framebuffer);
|
||||
cmd.BeginRenderPass(renderpass, lastFramebuffer);
|
||||
cmd.BeginRenderSubpass();
|
||||
cmd.SetRenderPipeline(material.pipeline);
|
||||
cmd.TransitionBufferUsage(material.uniformBuffer, nxt::BufferUsageBit::Uniform);
|
||||
|
@ -586,12 +592,17 @@ namespace {
|
|||
}
|
||||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &lastFramebuffer);
|
||||
|
||||
const auto& defaultSceneNodes = scene.scenes.at(scene.defaultScene);
|
||||
for (const auto& n : defaultSceneNodes) {
|
||||
const auto& node = scene.nodes.at(n);
|
||||
drawNode(node);
|
||||
}
|
||||
DoSwapBuffers();
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
DoFlush();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -521,6 +521,10 @@
|
|||
"name": "create shader module builder",
|
||||
"returns": "shader module builder"
|
||||
},
|
||||
{
|
||||
"name": "create swap chain builder",
|
||||
"returns": "swap chain builder"
|
||||
},
|
||||
{
|
||||
"name": "create texture builder",
|
||||
"returns": "texture builder"
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "backend/RenderPipeline.h"
|
||||
#include "backend/Sampler.h"
|
||||
#include "backend/ShaderModule.h"
|
||||
#include "backend/SwapChain.h"
|
||||
#include "backend/Texture.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
@ -130,6 +131,9 @@ namespace backend {
|
|||
ShaderModuleBuilder* DeviceBase::CreateShaderModuleBuilder() {
|
||||
return new ShaderModuleBuilder(this);
|
||||
}
|
||||
SwapChainBuilder* DeviceBase::CreateSwapChainBuilder() {
|
||||
return new SwapChainBuilder(this);
|
||||
}
|
||||
TextureBuilder* DeviceBase::CreateTextureBuilder() {
|
||||
return new TextureBuilder(this);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ namespace backend {
|
|||
}
|
||||
|
||||
SwapChainBase::~SwapChainBase() {
|
||||
const auto& im = GetImplementation();
|
||||
im.Destroy(im.userData);
|
||||
}
|
||||
|
||||
DeviceBase* SwapChainBase::GetDevice() {
|
||||
|
@ -41,6 +43,8 @@ namespace backend {
|
|||
this->format = format;
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
implementation.Configure(implementation.userData,
|
||||
static_cast<nxtTextureFormat>(format), width, height);
|
||||
}
|
||||
|
||||
TextureBase* SwapChainBase::GetNextTexture() {
|
||||
|
@ -102,7 +106,7 @@ namespace backend {
|
|||
|
||||
nxtSwapChainImplementation& impl = *reinterpret_cast<nxtSwapChainImplementation*>(implementation);
|
||||
|
||||
if (!impl.Init || impl.Destroy || !impl.Configure ||
|
||||
if (!impl.Init || !impl.Destroy || !impl.Configure ||
|
||||
!impl.GetNextTexture || !impl.Present) {
|
||||
HandleError("Implementation is incomplete");
|
||||
return;
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace d3d12 {
|
|||
{
|
||||
auto* view = ToBackend(GetBindingAsTextureView(binding));
|
||||
auto& srv = view->GetSRVDescriptor();
|
||||
d3d12Device->CreateShaderResourceView(ToBackend(view->GetTexture())->GetD3D12Resource().Get(), &srv, cbvUavSrvHeapStart.GetCPUHandle(*cbvUavSrvHeapOffset + bindingOffsets[binding]));
|
||||
d3d12Device->CreateShaderResourceView(ToBackend(view->GetTexture())->GetD3D12Resource(), &srv, cbvUavSrvHeapStart.GetCPUHandle(*cbvUavSrvHeapOffset + bindingOffsets[binding]));
|
||||
}
|
||||
break;
|
||||
case nxt::BindingType::Sampler:
|
||||
|
|
|
@ -309,7 +309,7 @@ namespace d3d12 {
|
|||
);
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION textureLocation;
|
||||
textureLocation.pResource = texture->GetD3D12Resource().Get();
|
||||
textureLocation.pResource = texture->GetD3D12Resource();
|
||||
textureLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
textureLocation.SubresourceIndex = copy->destination.level;
|
||||
|
||||
|
@ -358,7 +358,7 @@ namespace d3d12 {
|
|||
);
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION textureLocation;
|
||||
textureLocation.pResource = texture->GetD3D12Resource().Get();
|
||||
textureLocation.pResource = texture->GetD3D12Resource();
|
||||
textureLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
textureLocation.SubresourceIndex = copy->source.level;
|
||||
|
||||
|
|
|
@ -51,11 +51,6 @@ namespace d3d12 {
|
|||
return backendDevice->GetCommandQueue();
|
||||
}
|
||||
|
||||
void SetNextTexture(nxtDevice device, ComPtr<ID3D12Resource> resource) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
backendDevice->SetNextTexture(resource);
|
||||
}
|
||||
|
||||
uint64_t GetSerial(const nxtDevice device) {
|
||||
const Device* backendDevice = reinterpret_cast<const Device*>(device);
|
||||
return backendDevice->GetSerial();
|
||||
|
@ -101,6 +96,8 @@ namespace d3d12 {
|
|||
ASSERT_SUCCESS(d3d12Device->CreateFence(serial, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)));
|
||||
fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
ASSERT(fenceEvent != nullptr);
|
||||
|
||||
NextSerial();
|
||||
}
|
||||
|
||||
Device::~Device() {
|
||||
|
@ -163,15 +160,6 @@ namespace d3d12 {
|
|||
return pendingCommands.commandList;
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> Device::GetCurrentTexture() {
|
||||
return nextTexture;
|
||||
}
|
||||
|
||||
void Device::SetNextTexture(ComPtr<ID3D12Resource> resource) {
|
||||
nextTexture = resource;
|
||||
}
|
||||
|
||||
|
||||
void Device::TickImpl() {
|
||||
// Perform cleanup operations to free unused objects
|
||||
const uint64_t lastCompletedSerial = fence->GetCompletedValue();
|
||||
|
|
|
@ -120,9 +120,6 @@ namespace d3d12 {
|
|||
void OpenCommandList(ComPtr<ID3D12GraphicsCommandList>* commandList);
|
||||
ComPtr<ID3D12GraphicsCommandList> GetPendingCommandList();
|
||||
|
||||
ComPtr<ID3D12Resource> GetCurrentTexture();
|
||||
void SetNextTexture(ComPtr<ID3D12Resource> resource);
|
||||
|
||||
uint64_t GetSerial() const;
|
||||
void NextSerial();
|
||||
void WaitForSerial(uint64_t serial);
|
||||
|
@ -147,8 +144,6 @@ namespace d3d12 {
|
|||
ComPtr<ID3D12GraphicsCommandList> commandList;
|
||||
bool open = false;
|
||||
} pendingCommands;
|
||||
|
||||
ComPtr<ID3D12Resource> nextTexture;
|
||||
};
|
||||
|
||||
class DepthStencilState : public DepthStencilStateBase {
|
||||
|
|
|
@ -78,20 +78,7 @@ namespace d3d12 {
|
|||
|
||||
for (uint32_t index : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
||||
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.colorAttachments[index]];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(heapIndex);
|
||||
|
||||
uint32_t attachment = subpassInfo.colorAttachments[index];
|
||||
if (!GetTextureView(attachment)) {
|
||||
// TODO(kainino@chromium.org): null=backbuffer hack
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
|
||||
rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||
rtvDesc.Texture2D.MipSlice = 0;
|
||||
rtvDesc.Texture2D.PlaneSlice = 0;
|
||||
device->GetD3D12Device()->CreateRenderTargetView(device->GetCurrentTexture().Get(), &rtvDesc, rtvHandle);
|
||||
}
|
||||
|
||||
args.RTVs[args.numRTVs++] = rtvHandle;
|
||||
args.RTVs[args.numRTVs++] = rtvHeap.GetCPUHandle(heapIndex);
|
||||
}
|
||||
if (subpassInfo.depthStencilAttachmentSet) {
|
||||
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.depthStencilAttachment];
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "backend/d3d12/SwapChainD3D12.h"
|
||||
|
||||
#include "backend/d3d12/D3D12Backend.h"
|
||||
#include "backend/d3d12/TextureD3D12.h"
|
||||
|
||||
#include <nxt/nxt_wsi.h>
|
||||
|
@ -25,19 +26,23 @@ namespace d3d12 {
|
|||
: SwapChainBase(builder) {
|
||||
const auto& im = GetImplementation();
|
||||
nxtWSIContextD3D12 wsiContext = {};
|
||||
// TODO(kainino@chromium.org): set up wsiContext
|
||||
wsiContext.device = reinterpret_cast<nxtDevice>(GetDevice());
|
||||
im.Init(im.userData, &wsiContext);
|
||||
|
||||
// TODO(kainino@chromium.org): set up D3D12 swapchain
|
||||
}
|
||||
|
||||
SwapChain::~SwapChain() {
|
||||
// TODO(kainino@chromium.org): clean up D3D12 swapchain
|
||||
}
|
||||
|
||||
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
|
||||
ComPtr<ID3D12Resource> nativeTexture = nullptr;
|
||||
// TODO(kainino@chromium.org): obtain native texture from D3D12 swapchain
|
||||
const auto& im = GetImplementation();
|
||||
nxtSwapChainNextTexture next = {};
|
||||
nxtSwapChainError error = im.GetNextTexture(im.userData, &next);
|
||||
if (error) {
|
||||
GetDevice()->HandleError(error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D12Resource* nativeTexture = reinterpret_cast<ID3D12Resource*>(next.texture);
|
||||
return new Texture(builder, nativeTexture);
|
||||
}
|
||||
|
||||
|
|
|
@ -105,23 +105,28 @@ namespace d3d12 {
|
|||
resourceDescriptor.Flags = D3D12ResourceFlags(GetAllowedUsage(), GetFormat());
|
||||
|
||||
resource = device->GetResourceAllocator()->Allocate(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, D3D12TextureUsage(GetUsage(), GetFormat()));
|
||||
resourcePtr = resource.Get();
|
||||
}
|
||||
|
||||
Texture::Texture(TextureBuilder* builder, ComPtr<ID3D12Resource> nativeTexture)
|
||||
: TextureBase(builder), device(ToBackend(builder->GetDevice())), resource(nativeTexture) {
|
||||
// With this constructor, the lifetime of the ID3D12Resource is externally managed.
|
||||
Texture::Texture(TextureBuilder* builder, ID3D12Resource* nativeTexture)
|
||||
: TextureBase(builder), device(ToBackend(builder->GetDevice())),
|
||||
resourcePtr(nativeTexture) {
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
// TODO(kainino@chromium.org): Maybe don't release when using the native texture constructor?
|
||||
if (resource) {
|
||||
// If we own the resource, release it.
|
||||
device->GetResourceAllocator()->Release(resource);
|
||||
}
|
||||
}
|
||||
|
||||
DXGI_FORMAT Texture::GetD3D12Format() const {
|
||||
return D3D12TextureFormat(GetFormat());
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> Texture::GetD3D12Resource() {
|
||||
return resource;
|
||||
ID3D12Resource* Texture::GetD3D12Resource() {
|
||||
return resourcePtr;
|
||||
}
|
||||
|
||||
bool Texture::GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier) {
|
||||
|
@ -134,7 +139,7 @@ namespace d3d12 {
|
|||
|
||||
barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier->Transition.pResource = resource.Get();
|
||||
barrier->Transition.pResource = resourcePtr;
|
||||
barrier->Transition.StateBefore = stateBefore;
|
||||
barrier->Transition.StateAfter = stateAfter;
|
||||
barrier->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
|
|
@ -29,16 +29,17 @@ namespace d3d12 {
|
|||
class Texture : public TextureBase {
|
||||
public:
|
||||
Texture(TextureBuilder* builder);
|
||||
Texture(TextureBuilder* builder, ComPtr<ID3D12Resource> nativeTexture);
|
||||
Texture(TextureBuilder* builder, ID3D12Resource* nativeTexture);
|
||||
~Texture();
|
||||
|
||||
DXGI_FORMAT GetD3D12Format() const;
|
||||
ComPtr<ID3D12Resource> GetD3D12Resource();
|
||||
ID3D12Resource* GetD3D12Resource();
|
||||
bool GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier);
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
ComPtr<ID3D12Resource> resource;
|
||||
ComPtr<ID3D12Resource> resource = {};
|
||||
ID3D12Resource* resourcePtr = nullptr;
|
||||
|
||||
// NXT API
|
||||
void TransitionUsageImpl(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage) override;
|
||||
|
|
|
@ -90,15 +90,8 @@ namespace metal {
|
|||
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
|
||||
uint32_t attachment = info.colorAttachments[index];
|
||||
|
||||
// TODO(kainino@chromium.org): currently a 'null' texture view
|
||||
// falls back to the 'back buffer' but this should go away
|
||||
// when we have WSI.
|
||||
id<MTLTexture> texture = nil;
|
||||
if (auto textureView = currentFramebuffer->GetTextureView(attachment)) {
|
||||
texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
|
||||
} else {
|
||||
texture = device->GetCurrentTexture();
|
||||
}
|
||||
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
||||
auto texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
|
||||
descriptor.colorAttachments[index].texture = texture;
|
||||
descriptor.colorAttachments[index].loadAction = MTLLoadActionLoad;
|
||||
descriptor.colorAttachments[index].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
|
||||
|
|
|
@ -109,11 +109,7 @@ namespace metal {
|
|||
|
||||
void TickImpl() override;
|
||||
|
||||
void SetNextDrawable(id<CAMetalDrawable> drawable);
|
||||
void Present();
|
||||
|
||||
id<MTLDevice> GetMTLDevice();
|
||||
id<MTLTexture> GetCurrentTexture();
|
||||
|
||||
id<MTLCommandBuffer> GetPendingCommandBuffer();
|
||||
void SubmitPendingCommandBuffer();
|
||||
|
@ -130,9 +126,6 @@ namespace metal {
|
|||
MapReadRequestTracker* mapReadTracker;
|
||||
ResourceUploader* resourceUploader;
|
||||
|
||||
id<CAMetalDrawable> currentDrawable = nil;
|
||||
id<MTLTexture> currentTexture = nil;
|
||||
|
||||
Serial finishedCommandSerial = 0;
|
||||
Serial pendingCommandSerial = 1;
|
||||
id<MTLCommandBuffer> pendingCommands = nil;
|
||||
|
|
|
@ -41,16 +41,6 @@ namespace metal {
|
|||
*device = reinterpret_cast<nxtDevice>(new Device(metalDevice));
|
||||
}
|
||||
|
||||
void SetNextDrawable(nxtDevice device, id<CAMetalDrawable> drawable) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
backendDevice->SetNextDrawable(drawable);
|
||||
}
|
||||
|
||||
void Present(nxtDevice device) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
backendDevice->Present();
|
||||
}
|
||||
|
||||
// Device
|
||||
|
||||
Device::Device(id<MTLDevice> mtlDevice)
|
||||
|
@ -86,9 +76,6 @@ namespace metal {
|
|||
|
||||
[commandQueue release];
|
||||
commandQueue = nil;
|
||||
|
||||
[currentTexture release];
|
||||
currentTexture = nil;
|
||||
}
|
||||
|
||||
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
|
||||
|
@ -155,43 +142,10 @@ namespace metal {
|
|||
SubmitPendingCommandBuffer();
|
||||
}
|
||||
|
||||
void Device::SetNextDrawable(id<CAMetalDrawable> drawable) {
|
||||
[currentDrawable release];
|
||||
currentDrawable = drawable;
|
||||
[currentDrawable retain];
|
||||
|
||||
[currentTexture release];
|
||||
currentTexture = drawable.texture;
|
||||
[currentTexture retain];
|
||||
|
||||
MTLRenderPassDescriptor* passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
passDescriptor.colorAttachments[0].texture = currentTexture;
|
||||
passDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
passDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
passDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
|
||||
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
|
||||
id<MTLRenderCommandEncoder> commandEncoder = [commandBuffer
|
||||
renderCommandEncoderWithDescriptor:passDescriptor];
|
||||
[commandEncoder endEncoding];
|
||||
[commandBuffer commit];
|
||||
}
|
||||
|
||||
void Device::Present() {
|
||||
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
|
||||
[commandBuffer presentDrawable: currentDrawable];
|
||||
[commandBuffer commit];
|
||||
}
|
||||
|
||||
id<MTLDevice> Device::GetMTLDevice() {
|
||||
return mtlDevice;
|
||||
}
|
||||
|
||||
id<MTLTexture> Device::GetCurrentTexture() {
|
||||
return currentTexture;
|
||||
}
|
||||
|
||||
id<MTLCommandBuffer> Device::GetPendingCommandBuffer() {
|
||||
if (pendingCommands == nil) {
|
||||
pendingCommands = [commandQueue commandBuffer];
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "backend/metal/SwapChainMTL.h"
|
||||
|
||||
#include "backend/metal/MetalBackend.h"
|
||||
#include "backend/metal/TextureMTL.h"
|
||||
|
||||
#include <nxt/nxt_wsi.h>
|
||||
|
@ -25,19 +26,23 @@ namespace metal {
|
|||
: SwapChainBase(builder) {
|
||||
const auto& im = GetImplementation();
|
||||
nxtWSIContextMetal wsiContext = {};
|
||||
// TODO(kainino@chromium.org): set up wsiContext
|
||||
wsiContext.device = ToBackend(GetDevice())->GetMTLDevice();
|
||||
im.Init(im.userData, &wsiContext);
|
||||
|
||||
// TODO(kainino@chromium.org): set up Metal swapchain
|
||||
}
|
||||
|
||||
SwapChain::~SwapChain() {
|
||||
// TODO(kainino@chromium.org): clean up Metal swapchain
|
||||
}
|
||||
|
||||
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
|
||||
id<MTLTexture> nativeTexture = nil;
|
||||
// TODO(kainino@chromium.org): obtain MTLTexture from Metal swapchain
|
||||
const auto& im = GetImplementation();
|
||||
nxtSwapChainNextTexture next = {};
|
||||
nxtSwapChainError error = im.GetNextTexture(im.userData, &next);
|
||||
if (error) {
|
||||
GetDevice()->HandleError(error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
id<MTLTexture> nativeTexture = reinterpret_cast<id<MTLTexture>>(next.texture);
|
||||
return new Texture(builder, nativeTexture);
|
||||
}
|
||||
|
||||
|
|
|
@ -104,21 +104,13 @@ namespace opengl {
|
|||
glGenFramebuffers(1, ¤tFBO);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
|
||||
|
||||
auto* device = ToBackend(GetDevice());
|
||||
const auto& info = currentRenderPass->GetSubpassInfo(currentSubpass);
|
||||
|
||||
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
|
||||
uint32_t attachment = info.colorAttachments[index];
|
||||
|
||||
// TODO(kainino@chromium.org): currently a 'null' texture view
|
||||
// falls back to the 'back buffer' but this should go away
|
||||
// when we have WSI.
|
||||
GLuint texture = 0;
|
||||
if (auto textureView = currentFramebuffer->GetTextureView(attachment)) {
|
||||
texture = ToBackend(textureView->GetTexture())->GetHandle();
|
||||
} else {
|
||||
texture = device->GetCurrentTexture();
|
||||
}
|
||||
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
||||
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0 + index,
|
||||
GL_TEXTURE_2D, texture, 0);
|
||||
|
@ -131,6 +123,7 @@ namespace opengl {
|
|||
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
|
||||
|
||||
GLenum glAttachment = 0;
|
||||
// TODO(kainino@chromium.org): it may be valid to just always use GL_DEPTH_STENCIL_ATTACHMENT here.
|
||||
if (TextureFormatHasDepth(format)) {
|
||||
if (TextureFormatHasStencil(format)) {
|
||||
glAttachment = GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
|
|
|
@ -30,11 +30,6 @@ namespace opengl {
|
|||
nxtProcTable GetNonValidatingProcs();
|
||||
nxtProcTable GetValidatingProcs();
|
||||
|
||||
void HACKCLEAR(nxtDevice device) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
backendDevice->HACKCLEAR();
|
||||
}
|
||||
|
||||
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device) {
|
||||
*device = nullptr;
|
||||
|
||||
|
@ -44,17 +39,6 @@ namespace opengl {
|
|||
*device = reinterpret_cast<nxtDevice>(new Device);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
HACKCLEAR(*device);
|
||||
}
|
||||
|
||||
void InitBackbuffer(nxtDevice device) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
backendDevice->InitBackbuffer();
|
||||
}
|
||||
|
||||
void CommitBackbuffer(nxtDevice device) {
|
||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
||||
backendDevice->CommitBackbuffer();
|
||||
}
|
||||
|
||||
// Device
|
||||
|
@ -117,36 +101,6 @@ namespace opengl {
|
|||
void Device::TickImpl() {
|
||||
}
|
||||
|
||||
void Device::HACKCLEAR() {
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backFBO);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void Device::InitBackbuffer() {
|
||||
glGenTextures(1, &backTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, backTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 640, 480, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
glGenFramebuffers(1, &backFBO);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, backTexture, 0);
|
||||
|
||||
HACKCLEAR();
|
||||
}
|
||||
|
||||
void Device::CommitBackbuffer() {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glBlitFramebuffer(0, 0, 640, 480, 0, 0, 640, 480,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
|
||||
GLuint Device::GetCurrentTexture() {
|
||||
return backTexture;
|
||||
}
|
||||
|
||||
// Bind Group
|
||||
|
||||
BindGroup::BindGroup(BindGroupBuilder* builder)
|
||||
|
|
|
@ -104,15 +104,6 @@ namespace opengl {
|
|||
TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
|
||||
|
||||
void TickImpl() override;
|
||||
|
||||
void HACKCLEAR();
|
||||
void InitBackbuffer();
|
||||
void CommitBackbuffer();
|
||||
GLuint GetCurrentTexture();
|
||||
|
||||
private:
|
||||
GLuint backFBO = 0;
|
||||
GLuint backTexture = 0;
|
||||
};
|
||||
|
||||
class BindGroup : public BindGroupBase {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "backend/opengl/SwapChainGL.h"
|
||||
|
||||
#include "backend/Device.h"
|
||||
#include "backend/opengl/TextureGL.h"
|
||||
|
||||
#include <nxt/nxt_wsi.h>
|
||||
|
@ -24,18 +25,21 @@ namespace opengl {
|
|||
SwapChain::SwapChain(SwapChainBuilder* builder)
|
||||
: SwapChainBase(builder) {
|
||||
const auto& im = GetImplementation();
|
||||
nxtWSIContextGL wsiContext = {};
|
||||
// TODO(kainino@chromium.org): set up wsiContext
|
||||
im.Init(im.userData, &wsiContext);
|
||||
|
||||
// TODO(kainino@chromium.org): set up FBO
|
||||
im.Init(im.userData, nullptr);
|
||||
}
|
||||
|
||||
SwapChain::~SwapChain() {
|
||||
// TODO(kainino@chromium.org): clean up FBO
|
||||
}
|
||||
|
||||
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
|
||||
const auto& im = GetImplementation();
|
||||
nxtSwapChainNextTexture next = {};
|
||||
nxtSwapChainError error = im.GetNextTexture(im.userData, &next);
|
||||
if (error) {
|
||||
GetDevice()->HandleError(error);
|
||||
return nullptr;
|
||||
}
|
||||
GLuint nativeTexture = static_cast<GLuint>(reinterpret_cast<uintptr_t>(next.texture));
|
||||
return new Texture(builder, nativeTexture);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,9 +31,6 @@ namespace opengl {
|
|||
|
||||
protected:
|
||||
TextureBase* GetNextTextureImpl(TextureBuilder* builder) override;
|
||||
|
||||
private:
|
||||
GLuint nativeTexture = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
// Error message (or nullptr if there was no error)
|
||||
typedef const char* nxtSwapChainError;
|
||||
constexpr nxtSwapChainError NXT_SWAP_CHAIN_NO_ERROR = nullptr;
|
||||
|
||||
typedef struct {
|
||||
/// Backend-specific texture id/name/pointer
|
||||
|
@ -46,13 +47,17 @@ typedef struct {
|
|||
void* userData = nullptr;
|
||||
} nxtSwapChainImplementation;
|
||||
|
||||
#ifdef NXT_ENABLE_BACKEND_D3D12
|
||||
#if defined(NXT_ENABLE_BACKEND_D3D12) && defined(__cplusplus)
|
||||
typedef struct {
|
||||
nxtDevice device = nullptr;
|
||||
} nxtWSIContextD3D12;
|
||||
#endif
|
||||
|
||||
#ifdef NXT_ENABLE_BACKEND_METAL
|
||||
#if defined(NXT_ENABLE_BACKEND_METAL) && defined(__OBJC__)
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
typedef struct {
|
||||
id<MTLDevice> device = nil;
|
||||
} nxtWSIContextMetal;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -137,6 +137,10 @@ void NXTTest::SetUp() {
|
|||
device = nxt::Device::Acquire(backendDevice);
|
||||
queue = device.CreateQueueBuilder().GetResult();
|
||||
|
||||
swapchain = device.CreateSwapChainBuilder()
|
||||
.SetImplementation(binding->GetSwapChainImplementation())
|
||||
.GetResult();
|
||||
|
||||
device.SetErrorCallback(DeviceErrorCauseTestFailure, 0);
|
||||
}
|
||||
|
||||
|
@ -217,8 +221,11 @@ void NXTTest::WaitABit() {
|
|||
utils::USleep(100);
|
||||
}
|
||||
|
||||
void NXTTest::SwapBuffers() {
|
||||
binding->SwapBuffers();
|
||||
void NXTTest::SwapBuffersForCapture() {
|
||||
// Insert a frame boundary for API capture tools.
|
||||
nxt::Texture backBuffer = swapchain.GetNextTexture();
|
||||
backBuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backBuffer);
|
||||
}
|
||||
|
||||
NXTTest::ReadbackReservation NXTTest::ReserveReadback(uint32_t readbackSize) {
|
||||
|
|
|
@ -77,13 +77,15 @@ class NXTTest : public ::testing::TestWithParam<BackendType> {
|
|||
protected:
|
||||
nxt::Device device;
|
||||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
|
||||
// Helper methods to implement the EXPECT_ macros
|
||||
std::ostringstream& AddBufferExpectation(const char* file, int line, const nxt::Buffer& buffer, uint32_t offset, uint32_t size, detail::Expectation* expectation);
|
||||
std::ostringstream& AddTextureExpectation(const char* file, int line, const nxt::Texture& texture, uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t level, uint32_t pixelSize, detail::Expectation* expectation);
|
||||
|
||||
void WaitABit();
|
||||
void SwapBuffers();
|
||||
|
||||
void SwapBuffersForCapture();
|
||||
|
||||
private:
|
||||
// MapRead buffers used to get data for the expectations
|
||||
|
|
|
@ -21,7 +21,7 @@ class RenderPipelineValidationTest : public ValidationTest {
|
|||
void SetUp() override {
|
||||
ValidationTest::SetUp();
|
||||
|
||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
||||
CreateSimpleRenderPassAndFramebuffer(device, &renderpass, &framebuffer);
|
||||
|
||||
pipelineLayout = device.CreatePipelineLayoutBuilder().GetResult();
|
||||
|
||||
|
|
|
@ -69,6 +69,32 @@ bool ValidationTest::EndExpectDeviceError() {
|
|||
return error;
|
||||
}
|
||||
|
||||
void ValidationTest::CreateSimpleRenderPassAndFramebuffer(const nxt::Device& device, nxt::RenderPass* renderpass, nxt::Framebuffer* framebuffer) {
|
||||
auto colorBuffer = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(640, 480, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
colorBuffer.FreezeUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
auto colorView = colorBuffer.CreateTextureViewBuilder()
|
||||
.GetResult();
|
||||
|
||||
*renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
*framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(*renderpass)
|
||||
.SetDimensions(640, 480)
|
||||
.SetAttachment(0, colorView)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
void ValidationTest::OnDeviceError(const char* message, nxtCallbackUserdata userdata) {
|
||||
// Skip this one specific error that is raised when a builder is used after it got an error
|
||||
// this is important because we don't want to wrap all creation tests in ASSERT_DEVICE_ERROR.
|
||||
|
|
|
@ -48,6 +48,8 @@ class ValidationTest : public testing::Test {
|
|||
void StartExpectDeviceError();
|
||||
bool EndExpectDeviceError();
|
||||
|
||||
void CreateSimpleRenderPassAndFramebuffer(const nxt::Device& device, nxt::RenderPass* renderpass, nxt::Framebuffer* framebuffer);
|
||||
|
||||
// Helper functions to create objects to test validation.
|
||||
|
||||
struct DummyRenderPass {
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#ifndef UTILS_BACKENDBINDING_H_
|
||||
#define UTILS_BACKENDBINDING_H_
|
||||
|
||||
#include <nxt/nxt_wsi.h>
|
||||
|
||||
struct GLFWwindow;
|
||||
typedef struct nxtProcTable_s nxtProcTable;
|
||||
typedef struct nxtDeviceImpl* nxtDevice;
|
||||
|
@ -35,7 +37,7 @@ namespace utils {
|
|||
|
||||
virtual void SetupGLFWWindowHints() = 0;
|
||||
virtual void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) = 0;
|
||||
virtual void SwapBuffers() = 0;
|
||||
virtual uint64_t GetSwapChainImplementation() = 0;
|
||||
|
||||
void SetWindow(GLFWwindow* window);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ list(APPEND UTILS_SOURCES
|
|||
${UTILS_DIR}/BackendBinding.h
|
||||
${UTILS_DIR}/NXTHelpers.cpp
|
||||
${UTILS_DIR}/NXTHelpers.h
|
||||
${UTILS_DIR}/SwapChainImpl.h
|
||||
${UTILS_DIR}/SystemUtils.cpp
|
||||
${UTILS_DIR}/SystemUtils.h
|
||||
)
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "utils/BackendBinding.h"
|
||||
|
||||
#include "common/Assert.h"
|
||||
#include "nxt/nxt_wsi.h"
|
||||
#include "utils/SwapChainImpl.h"
|
||||
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#include "GLFW/glfw3.h"
|
||||
|
@ -34,7 +36,6 @@ namespace backend {
|
|||
namespace d3d12 {
|
||||
void Init(ComPtr<ID3D12Device> d3d12Device, nxtProcTable* procs, nxtDevice* device);
|
||||
ComPtr<ID3D12CommandQueue> GetCommandQueue(nxtDevice device);
|
||||
void SetNextTexture(nxtDevice device, ComPtr<ID3D12Resource> resource);
|
||||
uint64_t GetSerial(const nxtDevice device);
|
||||
void NextSerial(nxtDevice device);
|
||||
void ExecuteCommandLists(nxtDevice device, std::initializer_list<ID3D12CommandList*> commandLists);
|
||||
|
@ -44,14 +45,14 @@ namespace d3d12 {
|
|||
}
|
||||
|
||||
namespace utils {
|
||||
|
||||
class D3D12Binding : public BackendBinding {
|
||||
public:
|
||||
void SetupGLFWWindowHints() override {
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
namespace {
|
||||
void ASSERT_SUCCESS(HRESULT hr) {
|
||||
ASSERT(SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
ComPtr<IDXGIFactory4> CreateFactory() {
|
||||
ComPtr<IDXGIFactory4> factory;
|
||||
|
||||
uint32_t dxgiFactoryFlags = 0;
|
||||
#ifdef _DEBUG
|
||||
// Enable the debug layer (requires the Graphics Tools "optional feature").
|
||||
|
@ -73,19 +74,59 @@ namespace utils {
|
|||
#endif
|
||||
|
||||
ASSERT_SUCCESS(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)));
|
||||
ASSERT(GetHardwareAdapter(factory.Get(), &hardwareAdapter));
|
||||
ASSERT_SUCCESS(D3D12CreateDevice(
|
||||
hardwareAdapter.Get(),
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
IID_PPV_ARGS(&d3d12Device)
|
||||
));
|
||||
|
||||
backend::d3d12::Init(d3d12Device, procs, device);
|
||||
backendDevice = *device;
|
||||
return factory;
|
||||
}
|
||||
}
|
||||
|
||||
class SwapChainImplD3D12 : SwapChainImpl {
|
||||
public:
|
||||
static nxtSwapChainImplementation Create(HWND window, const nxtProcTable& procs) {
|
||||
auto impl = GenerateSwapChainImplementation<SwapChainImplD3D12, nxtWSIContextD3D12>();
|
||||
impl.userData = new SwapChainImplD3D12(window, procs);
|
||||
return impl;
|
||||
}
|
||||
|
||||
private:
|
||||
nxtDevice backendDevice = nullptr;
|
||||
nxtProcTable procs = {};
|
||||
|
||||
static constexpr unsigned int kFrameCount = 2;
|
||||
|
||||
HWND window = 0;
|
||||
ComPtr<IDXGIFactory4> factory = {};
|
||||
ComPtr<ID3D12CommandQueue> commandQueue = {};
|
||||
ComPtr<IDXGISwapChain3> swapChain = {};
|
||||
ComPtr<ID3D12Resource> renderTargetResources[kFrameCount] = {};
|
||||
|
||||
// Frame synchronization. Updated every frame
|
||||
uint32_t renderTargetIndex = 0;
|
||||
uint32_t previousRenderTargetIndex = 0;
|
||||
uint64_t lastSerialRenderTargetWasUsed[kFrameCount] = {};
|
||||
|
||||
SwapChainImplD3D12(HWND window, nxtProcTable procs)
|
||||
: window(window), procs(procs), factory(CreateFactory()) {
|
||||
}
|
||||
|
||||
~SwapChainImplD3D12() {
|
||||
}
|
||||
|
||||
// For GenerateSwapChainImplementation
|
||||
friend class SwapChainImpl;
|
||||
|
||||
void Init(nxtWSIContextD3D12* ctx) {
|
||||
backendDevice = ctx->device;
|
||||
commandQueue = backend::d3d12::GetCommandQueue(backendDevice);
|
||||
}
|
||||
|
||||
nxtSwapChainError Configure(nxtTextureFormat format,
|
||||
uint32_t width, uint32_t height) {
|
||||
if (format != NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM) {
|
||||
return "unsupported format";
|
||||
}
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
|
||||
int width, height;
|
||||
glfwGetWindowSize(window, &width, &height);
|
||||
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
|
||||
swapChainDesc.Width = width;
|
||||
swapChainDesc.Height = height;
|
||||
|
@ -96,11 +137,10 @@ namespace utils {
|
|||
swapChainDesc.SampleDesc.Count = 1;
|
||||
swapChainDesc.SampleDesc.Quality = 0;
|
||||
|
||||
HWND win32Window = glfwGetWin32Window(window);
|
||||
ComPtr<IDXGISwapChain1> swapChain1;
|
||||
ASSERT_SUCCESS(factory->CreateSwapChainForHwnd(
|
||||
commandQueue.Get(),
|
||||
win32Window,
|
||||
window,
|
||||
&swapChainDesc,
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
@ -122,48 +162,26 @@ namespace utils {
|
|||
lastSerialRenderTargetWasUsed[n] = initialSerial;
|
||||
}
|
||||
|
||||
// Transition the first frame to be a render target
|
||||
{
|
||||
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
||||
|
||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
||||
resourceBarrier.Transition.pResource = renderTargetResources[renderTargetIndex].Get();
|
||||
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
resourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
resourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
commandList->ResourceBarrier(1, &resourceBarrier);
|
||||
ASSERT_SUCCESS(commandList->Close());
|
||||
backend::d3d12::ExecuteCommandLists(backendDevice, { commandList.Get() });
|
||||
|
||||
backend::d3d12::NextSerial(backendDevice);
|
||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||
}
|
||||
|
||||
backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex]);
|
||||
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
|
||||
nextTexture->texture = renderTargetResources[renderTargetIndex].Get();
|
||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||
}
|
||||
|
||||
void SwapBuffers() override {
|
||||
// Transition current frame's render target for presenting
|
||||
{
|
||||
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
||||
resourceBarrier.Transition.pResource = renderTargetResources[renderTargetIndex].Get();
|
||||
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
resourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
resourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
commandList->ResourceBarrier(1, &resourceBarrier);
|
||||
ASSERT_SUCCESS(commandList->Close());
|
||||
backend::d3d12::ExecuteCommandLists(backendDevice, { commandList.Get() });
|
||||
}
|
||||
nxtSwapChainError Present() {
|
||||
// Current frame already transitioned to Present by the application, but
|
||||
// we need to flush the D3D12 backend's pending transitions.
|
||||
procs.deviceTick(backendDevice);
|
||||
|
||||
ASSERT_SUCCESS(swapChain->Present(1, 0));
|
||||
|
||||
// Transition last frame's render target back to being a render target
|
||||
{
|
||||
ComPtr<ID3D12GraphicsCommandList> commandList = {};
|
||||
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
||||
|
||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
||||
resourceBarrier.Transition.pResource = renderTargetResources[previousRenderTargetIndex].Get();
|
||||
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
|
@ -188,32 +206,47 @@ namespace utils {
|
|||
|
||||
lastSerialRenderTargetWasUsed[renderTargetIndex] = backend::d3d12::GetSerial(backendDevice);
|
||||
|
||||
// Tell the backend to render to the current render target
|
||||
backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex]);
|
||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
class D3D12Binding : public BackendBinding {
|
||||
public:
|
||||
void SetupGLFWWindowHints() override {
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
}
|
||||
|
||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
factory = CreateFactory();
|
||||
ASSERT(GetHardwareAdapter(factory.Get(), &hardwareAdapter));
|
||||
ASSERT_SUCCESS(D3D12CreateDevice(
|
||||
hardwareAdapter.Get(),
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
IID_PPV_ARGS(&d3d12Device)
|
||||
));
|
||||
|
||||
backend::d3d12::Init(d3d12Device, procs, device);
|
||||
backendDevice = *device;
|
||||
procTable = *procs;
|
||||
}
|
||||
|
||||
uint64_t GetSwapChainImplementation() override {
|
||||
if (swapchainImpl.userData == nullptr) {
|
||||
HWND win32Window = glfwGetWin32Window(window);
|
||||
swapchainImpl = SwapChainImplD3D12::Create(win32Window, procTable);
|
||||
}
|
||||
return reinterpret_cast<uint64_t>(&swapchainImpl);
|
||||
}
|
||||
|
||||
private:
|
||||
nxtDevice backendDevice = nullptr;
|
||||
|
||||
static constexpr unsigned int kFrameCount = 2;
|
||||
nxtSwapChainImplementation swapchainImpl = {};
|
||||
nxtProcTable procTable = {};
|
||||
|
||||
// Initialization
|
||||
ComPtr<IDXGIFactory4> factory;
|
||||
ComPtr<IDXGIAdapter1> hardwareAdapter;
|
||||
ComPtr<ID3D12Device> d3d12Device;
|
||||
ComPtr<ID3D12CommandQueue> commandQueue;
|
||||
ComPtr<IDXGISwapChain3> swapChain;
|
||||
ComPtr<ID3D12Resource> renderTargetResources[kFrameCount];
|
||||
|
||||
// Frame synchronization. Updated every frame
|
||||
uint32_t renderTargetIndex;
|
||||
uint32_t previousRenderTargetIndex;
|
||||
uint64_t lastSerialRenderTargetWasUsed[kFrameCount];
|
||||
ComPtr<ID3D12GraphicsCommandList> commandList;
|
||||
|
||||
static void ASSERT_SUCCESS(HRESULT hr) {
|
||||
ASSERT(SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
static bool GetHardwareAdapter(IDXGIFactory4* factory, IDXGIAdapter1** hardwareAdapter) {
|
||||
*hardwareAdapter = nullptr;
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
#include "utils/BackendBinding.h"
|
||||
|
||||
#include "common/Assert.h"
|
||||
#include "nxt/nxt_wsi.h"
|
||||
#include "utils/SwapChainImpl.h"
|
||||
|
||||
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "GLFW/glfw3native.h"
|
||||
|
@ -30,6 +34,103 @@ namespace metal {
|
|||
}
|
||||
|
||||
namespace utils {
|
||||
class SwapChainImplMTL : SwapChainImpl {
|
||||
public:
|
||||
static nxtSwapChainImplementation Create(id nswindow) {
|
||||
auto impl = GenerateSwapChainImplementation<SwapChainImplMTL, nxtWSIContextMetal>();
|
||||
impl.userData = new SwapChainImplMTL(nswindow);
|
||||
return impl;
|
||||
}
|
||||
|
||||
private:
|
||||
id nsWindow = nil;
|
||||
id<MTLDevice> mtlDevice = nil;
|
||||
id<MTLCommandQueue> commandQueue = nil;
|
||||
|
||||
CAMetalLayer* layer = nullptr;
|
||||
id<CAMetalDrawable> currentDrawable = nil;
|
||||
id<MTLTexture> currentTexture = nil;
|
||||
|
||||
SwapChainImplMTL(id nsWindow)
|
||||
: nsWindow(nsWindow) {
|
||||
}
|
||||
|
||||
~SwapChainImplMTL() {
|
||||
[currentTexture release];
|
||||
[currentDrawable release];
|
||||
}
|
||||
|
||||
// For GenerateSwapChainImplementation
|
||||
friend class SwapChainImpl;
|
||||
|
||||
void Init(nxtWSIContextMetal* ctx) {
|
||||
mtlDevice = ctx->device;
|
||||
commandQueue = [mtlDevice newCommandQueue];
|
||||
}
|
||||
|
||||
nxtSwapChainError Configure(nxtTextureFormat format,
|
||||
uint32_t width, uint32_t height) {
|
||||
if (format != NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM) {
|
||||
return "unsupported format";
|
||||
}
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
|
||||
NSView* contentView = [nsWindow contentView];
|
||||
[contentView setWantsLayer: YES];
|
||||
|
||||
CGSize size = {};
|
||||
size.width = width;
|
||||
size.height = height;
|
||||
|
||||
layer = [CAMetalLayer layer];
|
||||
[layer setDevice: mtlDevice];
|
||||
[layer setPixelFormat: MTLPixelFormatBGRA8Unorm];
|
||||
[layer setFramebufferOnly: YES];
|
||||
[layer setDrawableSize: size];
|
||||
|
||||
[contentView setLayer: layer];
|
||||
|
||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||
}
|
||||
|
||||
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
|
||||
[currentDrawable release];
|
||||
currentDrawable = [layer nextDrawable];
|
||||
[currentDrawable retain];
|
||||
|
||||
[currentTexture release];
|
||||
currentTexture = currentDrawable.texture;
|
||||
[currentTexture retain];
|
||||
|
||||
// Clear initial contents of the texture
|
||||
{
|
||||
MTLRenderPassDescriptor* passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
passDescriptor.colorAttachments[0].texture = currentTexture;
|
||||
passDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
passDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
passDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
|
||||
id<MTLRenderCommandEncoder> commandEncoder = [commandBuffer
|
||||
renderCommandEncoderWithDescriptor:passDescriptor];
|
||||
[commandEncoder endEncoding];
|
||||
[commandBuffer commit];
|
||||
}
|
||||
|
||||
nextTexture->texture = reinterpret_cast<void*>(currentTexture);
|
||||
|
||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||
}
|
||||
|
||||
nxtSwapChainError Present() {
|
||||
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
|
||||
[commandBuffer presentDrawable: currentDrawable];
|
||||
[commandBuffer commit];
|
||||
|
||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
class MetalBinding : public BackendBinding {
|
||||
public:
|
||||
|
@ -39,40 +140,21 @@ namespace utils {
|
|||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
metalDevice = MTLCreateSystemDefaultDevice();
|
||||
|
||||
id nsWindow = glfwGetCocoaWindow(window);
|
||||
NSView* contentView = [nsWindow contentView];
|
||||
[contentView setWantsLayer: YES];
|
||||
|
||||
layer = [CAMetalLayer layer];
|
||||
[layer setDevice: metalDevice];
|
||||
[layer setPixelFormat: MTLPixelFormatBGRA8Unorm];
|
||||
[layer setFramebufferOnly: YES];
|
||||
[layer setDrawableSize: [contentView bounds].size];
|
||||
|
||||
[contentView setLayer: layer];
|
||||
|
||||
backend::metal::Init(metalDevice, procs, device);
|
||||
backendDevice = *device;
|
||||
|
||||
backend::metal::SetNextDrawable(backendDevice, GetNextDrawable());
|
||||
}
|
||||
void SwapBuffers() override {
|
||||
backend::metal::Present(backendDevice);
|
||||
backend::metal::SetNextDrawable(backendDevice, GetNextDrawable());
|
||||
|
||||
uint64_t GetSwapChainImplementation() override {
|
||||
if (swapchainImpl.userData == nullptr) {
|
||||
swapchainImpl = SwapChainImplMTL::Create(glfwGetCocoaWindow(window));
|
||||
}
|
||||
return reinterpret_cast<uint64_t>(&swapchainImpl);
|
||||
}
|
||||
|
||||
private:
|
||||
id<CAMetalDrawable> GetNextDrawable() {
|
||||
lastDrawable = [layer nextDrawable];
|
||||
return lastDrawable;
|
||||
}
|
||||
|
||||
id<MTLDevice> metalDevice = nil;
|
||||
CAMetalLayer* layer = nullptr;
|
||||
|
||||
id<CAMetalDrawable> lastDrawable = nil;
|
||||
|
||||
nxtDevice backendDevice = nullptr;
|
||||
nxtSwapChainImplementation swapchainImpl = {};
|
||||
};
|
||||
|
||||
BackendBinding* CreateMetalBinding() {
|
||||
|
|
|
@ -92,34 +92,6 @@ namespace utils {
|
|||
return builder.GetResult();
|
||||
}
|
||||
|
||||
void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer) {
|
||||
auto depthStencilTexture = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(640, 480, 1)
|
||||
.SetFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
depthStencilTexture.FreezeUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
auto depthStencilView = depthStencilTexture.CreateTextureViewBuilder()
|
||||
.GetResult();
|
||||
|
||||
*renderPass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(2)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetFormat(1, nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.SubpassSetDepthStencilAttachment(0, 1)
|
||||
.GetResult();
|
||||
*framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(*renderPass)
|
||||
.SetDimensions(640, 480)
|
||||
// Attachment 0 is implicit until we add WSI
|
||||
.SetAttachment(1, depthStencilView)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device, const void* data, uint32_t size, nxt::BufferUsageBit usage) {
|
||||
nxt::Buffer buffer = device.CreateBufferBuilder()
|
||||
.SetAllowedUsage(nxt::BufferUsageBit::TransferDst | usage)
|
||||
|
|
|
@ -18,7 +18,6 @@ namespace utils {
|
|||
|
||||
void FillShaderModuleBuilder(const nxt::ShaderModuleBuilder& builder, nxt::ShaderStage stage, const char* source);
|
||||
nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage stage, const char* source);
|
||||
void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer);
|
||||
nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device, const void* data, uint32_t size, nxt::BufferUsageBit usage);
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ namespace utils {
|
|||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
backend::null::Init(procs, device);
|
||||
}
|
||||
void SwapBuffers() override {
|
||||
uint64_t GetSwapChainImplementation() override {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,20 +14,104 @@
|
|||
|
||||
#include "utils/BackendBinding.h"
|
||||
|
||||
#include "common/Assert.h"
|
||||
#include "common/Platform.h"
|
||||
#include "nxt/nxt_wsi.h"
|
||||
#include "utils/SwapChainImpl.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include "glad/glad.h"
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
|
||||
void HACKCLEAR(nxtDevice device);
|
||||
void InitBackbuffer(nxtDevice device);
|
||||
void CommitBackbuffer(nxtDevice device);
|
||||
}
|
||||
}
|
||||
|
||||
namespace utils {
|
||||
class SwapChainImplGL : SwapChainImpl {
|
||||
public:
|
||||
static nxtSwapChainImplementation Create(GLFWwindow* window) {
|
||||
auto impl = GenerateSwapChainImplementation<SwapChainImplGL, nxtWSIContextGL>();
|
||||
impl.userData = new SwapChainImplGL(window);
|
||||
return impl;
|
||||
}
|
||||
|
||||
private:
|
||||
GLFWwindow* window = nullptr;
|
||||
uint32_t cfgWidth = 0;
|
||||
uint32_t cfgHeight = 0;
|
||||
GLuint backFBO = 0;
|
||||
GLuint backTexture = 0;
|
||||
|
||||
SwapChainImplGL(GLFWwindow* window)
|
||||
: window(window) {
|
||||
}
|
||||
|
||||
~SwapChainImplGL() {
|
||||
glDeleteTextures(1, &backTexture);
|
||||
glDeleteFramebuffers(1, &backFBO);
|
||||
}
|
||||
|
||||
void HACKCLEAR() {
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backFBO);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// For GenerateSwapChainImplementation
|
||||
friend class SwapChainImpl;
|
||||
|
||||
void Init(nxtWSIContextGL*) {
|
||||
glGenTextures(1, &backTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, backTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
glGenFramebuffers(1, &backFBO);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, backTexture, 0);
|
||||
}
|
||||
|
||||
nxtSwapChainError Configure(nxtTextureFormat format,
|
||||
uint32_t width, uint32_t height) {
|
||||
if (format != NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM) {
|
||||
return "unsupported format";
|
||||
}
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
cfgWidth = width;
|
||||
cfgHeight = height;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, backTexture);
|
||||
// Reallocate the texture
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
// Clear the newly (re-)allocated texture
|
||||
HACKCLEAR();
|
||||
|
||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||
}
|
||||
|
||||
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
|
||||
nextTexture->texture = reinterpret_cast<void*>(static_cast<size_t>(backTexture));
|
||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||
}
|
||||
|
||||
nxtSwapChainError Present() {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glBlitFramebuffer(0, 0, cfgWidth, cfgHeight, 0, 0, cfgWidth, cfgHeight,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glfwSwapBuffers(window);
|
||||
HACKCLEAR();
|
||||
|
||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
class OpenGLBinding : public BackendBinding {
|
||||
public:
|
||||
void SetupGLFWWindowHints() override {
|
||||
|
@ -48,16 +132,18 @@ namespace utils {
|
|||
backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
|
||||
|
||||
backendDevice = *device;
|
||||
backend::opengl::InitBackbuffer(backendDevice);
|
||||
}
|
||||
void SwapBuffers() override {
|
||||
backend::opengl::CommitBackbuffer(backendDevice);
|
||||
glfwSwapBuffers(window);
|
||||
backend::opengl::HACKCLEAR(backendDevice);
|
||||
|
||||
uint64_t GetSwapChainImplementation() override {
|
||||
if (swapchainImpl.userData == nullptr) {
|
||||
swapchainImpl = SwapChainImplGL::Create(window);
|
||||
}
|
||||
return reinterpret_cast<uint64_t>(&swapchainImpl);
|
||||
}
|
||||
|
||||
private:
|
||||
nxtDevice backendDevice = nullptr;
|
||||
nxtSwapChainImplementation swapchainImpl = {};
|
||||
};
|
||||
|
||||
BackendBinding* CreateOpenGLBinding() {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef UTILS_SWAPCHAINIMPL_H_
|
||||
#define UTILS_SWAPCHAINIMPL_H_
|
||||
|
||||
namespace utils {
|
||||
class SwapChainImpl {
|
||||
protected:
|
||||
template<class TImpl, typename TWSIContext>
|
||||
static nxtSwapChainImplementation GenerateSwapChainImplementation() {
|
||||
nxtSwapChainImplementation impl = {};
|
||||
impl.Init = [](void* userData, void* wsiContext) {
|
||||
auto* ctx = reinterpret_cast<TWSIContext*>(wsiContext);
|
||||
reinterpret_cast<TImpl*>(userData)->Init(ctx);
|
||||
};
|
||||
impl.Destroy = [](void* userData) {
|
||||
delete reinterpret_cast<TImpl*>(userData);
|
||||
};
|
||||
impl.Configure = [](void* userData, nxtTextureFormat format, uint32_t width, uint32_t height) {
|
||||
return reinterpret_cast<TImpl*>(userData)->Configure(
|
||||
format, width, height);
|
||||
};
|
||||
impl.GetNextTexture = [](void* userData, nxtSwapChainNextTexture* nextTexture) {
|
||||
return reinterpret_cast<TImpl*>(userData)->GetNextTexture(
|
||||
nextTexture);
|
||||
};
|
||||
impl.Present = [](void* userData) {
|
||||
return reinterpret_cast<TImpl*>(userData)->Present();
|
||||
};
|
||||
return impl;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // UTILS_SWAPCHAINIMPL_H_
|
Loading…
Reference in New Issue