Swap chains, part 2 (#94)

This commit is contained in:
Kai Ninomiya 2017-07-27 18:30:57 -07:00 committed by GitHub
parent 3818e18c5c
commit c16a67ae52
49 changed files with 771 additions and 435 deletions

View File

@ -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);
}

View File

@ -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[]) {

View File

@ -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,48 +260,54 @@ 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()
.BeginComputePass()
.SetComputePipeline(updatePipeline)
.TransitionBufferUsage(bufferSrc, nxt::BufferUsageBit::Storage)
.TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Storage)
.SetBindGroup(0, updateBGs[i])
.Dispatch(kNumParticles, 1, 1)
.EndComputePass()
auto& bufferSrc = particleBuffers[i];
auto& bufferDst = particleBuffers[(i + 1) % 2];
return device.CreateCommandBufferBuilder()
.BeginComputePass()
.SetComputePipeline(updatePipeline)
.TransitionBufferUsage(bufferSrc, nxt::BufferUsageBit::Storage)
.TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Storage)
.SetBindGroup(0, updateBGs[i])
.Dispatch(kNumParticles, 1, 1)
.EndComputePass()
.BeginRenderPass(renderpass, framebuffer)
.BeginRenderSubpass()
.SetRenderPipeline(renderPipeline)
.TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Vertex)
.SetVertexBuffers(0, 1, &bufferDst, zeroOffsets)
.SetVertexBuffers(1, 1, &modelBuffer, zeroOffsets)
.DrawArrays(3, kNumParticles, 0, 0)
.EndRenderSubpass()
.EndRenderPass()
.BeginRenderPass(renderpass, framebuffer)
.BeginRenderSubpass()
.SetRenderPipeline(renderPipeline)
.TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Vertex)
.SetVertexBuffers(0, 1, &bufferDst, zeroOffsets)
.SetVertexBuffers(1, 1, &modelBuffer, zeroOffsets)
.DrawArrays(3, kNumParticles, 0, 0)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
}
.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;
}

View File

@ -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[]) {

View File

@ -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[]) {

View File

@ -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[]) {

View File

@ -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[]) {

View File

@ -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[]) {

View File

@ -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[]) {

View File

@ -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[]) {

View File

@ -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[]) {

View File

@ -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() {

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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"

View File

@ -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);
}

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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();

View File

@ -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 {

View File

@ -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];

View File

@ -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);
}

View File

@ -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?
device->GetResourceAllocator()->Release(resource);
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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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];

View File

@ -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);
}

View File

@ -104,21 +104,13 @@ namespace opengl {
glGenFramebuffers(1, &currentFBO);
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;

View File

@ -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)

View File

@ -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 {

View File

@ -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);
}

View File

@ -31,9 +31,6 @@ namespace opengl {
protected:
TextureBase* GetNextTextureImpl(TextureBuilder* builder) override;
private:
GLuint nativeTexture = 0;
};
}

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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();

View File

@ -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.

View File

@ -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 {

View File

@ -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);

View File

@ -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
)

View File

@ -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,48 +45,88 @@ namespace d3d12 {
}
namespace utils {
namespace {
void ASSERT_SUCCESS(HRESULT hr) {
ASSERT(SUCCEEDED(hr));
}
class D3D12Binding : public BackendBinding {
public:
void SetupGLFWWindowHints() override {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
}
ComPtr<IDXGIFactory4> CreateFactory() {
ComPtr<IDXGIFactory4> factory;
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
uint32_t dxgiFactoryFlags = 0;
uint32_t dxgiFactoryFlags = 0;
#ifdef _DEBUG
// Enable the debug layer (requires the Graphics Tools "optional feature").
// NOTE: Enabling the debug layer after device creation will invalidate the active device.
{
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
debugController->EnableDebugLayer();
// Enable the debug layer (requires the Graphics Tools "optional feature").
// NOTE: Enabling the debug layer after device creation will invalidate the active device.
{
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
debugController->EnableDebugLayer();
// Enable additional debug layers.
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
}
ComPtr<IDXGIDebug1> dxgiDebug;
if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug)))) {
dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_ALL));
}
// Enable additional debug layers.
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
}
ComPtr<IDXGIDebug1> dxgiDebug;
if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug)))) {
dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_ALL));
}
}
#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)
));
ASSERT_SUCCESS(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)));
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);
}
backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex]);
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 GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
nextTexture->texture = renderTargetResources[renderTargetIndex].Get();
return NXT_SWAP_CHAIN_NO_ERROR;
}
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;

View File

@ -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() {

View File

@ -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)

View File

@ -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);
}

View File

@ -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;
}
};

View File

@ -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() {

47
src/utils/SwapChainImpl.h Normal file
View File

@ -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_