Swap chains, part 2 (#94)
This commit is contained in:
parent
3818e18c5c
commit
c16a67ae52
|
@ -23,9 +23,10 @@
|
||||||
|
|
||||||
nxt::Device device;
|
nxt::Device device;
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
|
nxt::TextureView depthStencilView;
|
||||||
nxt::RenderPipeline pipeline;
|
nxt::RenderPipeline pipeline;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer framebuffer;
|
|
||||||
|
|
||||||
float RandomFloat(float min, float max) {
|
float RandomFloat(float min, float max) {
|
||||||
float zeroOne = rand() / float(RAND_MAX);
|
float zeroOne = rand() / float(RAND_MAX);
|
||||||
|
@ -47,6 +48,8 @@ void init() {
|
||||||
device = CreateCppNXTDevice();
|
device = CreateCppNXTDevice();
|
||||||
|
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
queue = device.CreateQueueBuilder().GetResult();
|
||||||
|
swapchain = GetSwapChain(device);
|
||||||
|
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||||
|
|
||||||
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||||
#version 450
|
#version 450
|
||||||
|
@ -105,7 +108,9 @@ void init() {
|
||||||
})"
|
})"
|
||||||
);
|
);
|
||||||
|
|
||||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
renderpass = CreateDefaultRenderPass(device);
|
||||||
|
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||||
|
|
||||||
pipeline = device.CreateRenderPipelineBuilder()
|
pipeline = device.CreateRenderPipelineBuilder()
|
||||||
.SetSubpass(renderpass, 0)
|
.SetSubpass(renderpass, 0)
|
||||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||||
|
@ -124,6 +129,10 @@ void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame() {
|
void frame() {
|
||||||
|
nxt::Texture backbuffer;
|
||||||
|
nxt::Framebuffer framebuffer;
|
||||||
|
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||||
|
|
||||||
static int f = 0;
|
static int f = 0;
|
||||||
f++;
|
f++;
|
||||||
|
|
||||||
|
@ -152,7 +161,9 @@ void frame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.Submit(50, commands.data());
|
queue.Submit(50, commands.data());
|
||||||
DoSwapBuffers();
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
|
swapchain.Present(backbuffer);
|
||||||
|
DoFlush();
|
||||||
fprintf(stderr, "frame %i\n", f);
|
fprintf(stderr, "frame %i\n", f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,9 @@
|
||||||
|
|
||||||
nxtDevice device;
|
nxtDevice device;
|
||||||
nxtQueue queue;
|
nxtQueue queue;
|
||||||
|
nxtSwapChain swapchain;
|
||||||
nxtRenderPipeline pipeline;
|
nxtRenderPipeline pipeline;
|
||||||
nxtRenderPass renderpass;
|
nxtRenderPass renderpass;
|
||||||
nxtFramebuffer framebuffer;
|
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
device = CreateCppNXTDevice().Release();
|
device = CreateCppNXTDevice().Release();
|
||||||
|
@ -32,6 +32,15 @@ void init() {
|
||||||
nxtQueueBuilderRelease(builder);
|
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 =
|
const char* vs =
|
||||||
"#version 450\n"
|
"#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"
|
"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);
|
renderpass = nxtRenderPassBuilderGetResult(builder);
|
||||||
nxtRenderPassBuilderRelease(builder);
|
nxtRenderPassBuilderRelease(builder);
|
||||||
}
|
}
|
||||||
{
|
|
||||||
nxtFramebufferBuilder builder = nxtDeviceCreateFramebufferBuilder(device);
|
|
||||||
nxtFramebufferBuilderSetRenderPass(builder, renderpass);
|
|
||||||
nxtFramebufferBuilderSetDimensions(builder, 640, 480);
|
|
||||||
framebuffer = nxtFramebufferBuilderGetResult(builder);
|
|
||||||
nxtFramebufferBuilderRelease(builder);
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
nxtRenderPipelineBuilder builder = nxtDeviceCreateRenderPipelineBuilder(device);
|
nxtRenderPipelineBuilder builder = nxtDeviceCreateRenderPipelineBuilder(device);
|
||||||
nxtRenderPipelineBuilderSetSubpass(builder, renderpass, 0);
|
nxtRenderPipelineBuilderSetSubpass(builder, renderpass, 0);
|
||||||
|
@ -78,6 +80,22 @@ void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame() {
|
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;
|
nxtCommandBuffer commands;
|
||||||
{
|
{
|
||||||
nxtCommandBufferBuilder builder = nxtDeviceCreateCommandBufferBuilder(device);
|
nxtCommandBufferBuilder builder = nxtDeviceCreateCommandBufferBuilder(device);
|
||||||
|
@ -93,8 +111,12 @@ void frame() {
|
||||||
|
|
||||||
nxtQueueSubmit(queue, 1, &commands);
|
nxtQueueSubmit(queue, 1, &commands);
|
||||||
nxtCommandBufferRelease(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[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
|
|
|
@ -25,20 +25,19 @@
|
||||||
|
|
||||||
nxt::Device device;
|
nxt::Device device;
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
|
nxt::TextureView depthStencilView;
|
||||||
|
|
||||||
nxt::Buffer modelBuffer;
|
nxt::Buffer modelBuffer;
|
||||||
std::array<nxt::Buffer, 2> particleBuffers;
|
std::array<nxt::Buffer, 2> particleBuffers;
|
||||||
|
|
||||||
nxt::RenderPipeline renderPipeline;
|
nxt::RenderPipeline renderPipeline;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer framebuffer;
|
|
||||||
|
|
||||||
nxt::Buffer updateParams;
|
nxt::Buffer updateParams;
|
||||||
nxt::ComputePipeline updatePipeline;
|
nxt::ComputePipeline updatePipeline;
|
||||||
std::array<nxt::BindGroup, 2> updateBGs;
|
std::array<nxt::BindGroup, 2> updateBGs;
|
||||||
|
|
||||||
std::array<nxt::CommandBuffer, 2> commandBuffers;
|
|
||||||
|
|
||||||
size_t pingpong = 0;
|
size_t pingpong = 0;
|
||||||
|
|
||||||
static const uint32_t kNumParticles = 1000;
|
static const uint32_t kNumParticles = 1000;
|
||||||
|
@ -124,7 +123,9 @@ void initRender() {
|
||||||
.SetInput(1, sizeof(glm::vec2), nxt::InputStepMode::Vertex)
|
.SetInput(1, sizeof(glm::vec2), nxt::InputStepMode::Vertex)
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
renderpass = CreateDefaultRenderPass(device);
|
||||||
|
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||||
|
|
||||||
renderPipeline = device.CreateRenderPipelineBuilder()
|
renderPipeline = device.CreateRenderPipelineBuilder()
|
||||||
.SetSubpass(renderpass, 0)
|
.SetSubpass(renderpass, 0)
|
||||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
.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};
|
static const uint32_t zeroOffsets[1] = {0};
|
||||||
for (size_t i = 0; i < 2; ++i) {
|
auto& bufferSrc = particleBuffers[i];
|
||||||
auto& bufferSrc = particleBuffers[i];
|
auto& bufferDst = particleBuffers[(i + 1) % 2];
|
||||||
auto& bufferDst = particleBuffers[(i + 1) % 2];
|
return device.CreateCommandBufferBuilder()
|
||||||
commandBuffers[i] = device.CreateCommandBufferBuilder()
|
.BeginComputePass()
|
||||||
.BeginComputePass()
|
.SetComputePipeline(updatePipeline)
|
||||||
.SetComputePipeline(updatePipeline)
|
.TransitionBufferUsage(bufferSrc, nxt::BufferUsageBit::Storage)
|
||||||
.TransitionBufferUsage(bufferSrc, nxt::BufferUsageBit::Storage)
|
.TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Storage)
|
||||||
.TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Storage)
|
.SetBindGroup(0, updateBGs[i])
|
||||||
.SetBindGroup(0, updateBGs[i])
|
.Dispatch(kNumParticles, 1, 1)
|
||||||
.Dispatch(kNumParticles, 1, 1)
|
.EndComputePass()
|
||||||
.EndComputePass()
|
|
||||||
|
|
||||||
.BeginRenderPass(renderpass, framebuffer)
|
.BeginRenderPass(renderpass, framebuffer)
|
||||||
.BeginRenderSubpass()
|
.BeginRenderSubpass()
|
||||||
.SetRenderPipeline(renderPipeline)
|
.SetRenderPipeline(renderPipeline)
|
||||||
.TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Vertex)
|
.TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Vertex)
|
||||||
.SetVertexBuffers(0, 1, &bufferDst, zeroOffsets)
|
.SetVertexBuffers(0, 1, &bufferDst, zeroOffsets)
|
||||||
.SetVertexBuffers(1, 1, &modelBuffer, zeroOffsets)
|
.SetVertexBuffers(1, 1, &modelBuffer, zeroOffsets)
|
||||||
.DrawArrays(3, kNumParticles, 0, 0)
|
.DrawArrays(3, kNumParticles, 0, 0)
|
||||||
.EndRenderSubpass()
|
.EndRenderSubpass()
|
||||||
.EndRenderPass()
|
.EndRenderPass()
|
||||||
|
|
||||||
.GetResult();
|
.GetResult();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
device = CreateCppNXTDevice();
|
device = CreateCppNXTDevice();
|
||||||
|
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
queue = device.CreateQueueBuilder().GetResult();
|
||||||
|
swapchain = GetSwapChain(device);
|
||||||
|
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||||
|
|
||||||
initBuffers();
|
initBuffers();
|
||||||
initRender();
|
initRender();
|
||||||
initSim();
|
initSim();
|
||||||
initCommandBuffers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame() {
|
void frame() {
|
||||||
queue.Submit(1, &commandBuffers[pingpong]);
|
nxt::Texture backbuffer;
|
||||||
DoSwapBuffers();
|
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;
|
pingpong = (pingpong + 1) % 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,12 @@
|
||||||
|
|
||||||
nxt::Device device;
|
nxt::Device device;
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
|
nxt::TextureView depthStencilView;
|
||||||
nxt::Buffer buffer;
|
nxt::Buffer buffer;
|
||||||
nxt::RenderPipeline renderPipeline;
|
nxt::RenderPipeline renderPipeline;
|
||||||
nxt::BindGroup renderBindGroup;
|
nxt::BindGroup renderBindGroup;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer framebuffer;
|
|
||||||
nxt::ComputePipeline computePipeline;
|
nxt::ComputePipeline computePipeline;
|
||||||
nxt::BindGroup computeBindGroup;
|
nxt::BindGroup computeBindGroup;
|
||||||
|
|
||||||
|
@ -33,6 +34,8 @@ void init() {
|
||||||
device = CreateCppNXTDevice();
|
device = CreateCppNXTDevice();
|
||||||
|
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
queue = device.CreateQueueBuilder().GetResult();
|
||||||
|
swapchain = GetSwapChain(device);
|
||||||
|
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||||
|
|
||||||
struct {uint32_t a; float b;} s;
|
struct {uint32_t a; float b;} s;
|
||||||
memset(&s, 0, sizeof(s));
|
memset(&s, 0, sizeof(s));
|
||||||
|
@ -109,7 +112,9 @@ void init() {
|
||||||
.SetBindGroupLayout(0, bgl)
|
.SetBindGroupLayout(0, bgl)
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
renderpass = CreateDefaultRenderPass(device);
|
||||||
|
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||||
|
|
||||||
renderPipeline = device.CreateRenderPipelineBuilder()
|
renderPipeline = device.CreateRenderPipelineBuilder()
|
||||||
.SetSubpass(renderpass, 0)
|
.SetSubpass(renderpass, 0)
|
||||||
.SetLayout(pl)
|
.SetLayout(pl)
|
||||||
|
@ -126,6 +131,10 @@ void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame() {
|
void frame() {
|
||||||
|
nxt::Texture backbuffer;
|
||||||
|
nxt::Framebuffer framebuffer;
|
||||||
|
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||||
|
|
||||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||||
.BeginComputePass()
|
.BeginComputePass()
|
||||||
.SetComputePipeline(computePipeline)
|
.SetComputePipeline(computePipeline)
|
||||||
|
@ -146,7 +155,9 @@ void frame() {
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
DoSwapBuffers();
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
|
swapchain.Present(backbuffer);
|
||||||
|
DoFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
|
|
|
@ -35,11 +35,12 @@ nxt::BindGroup bindGroup[2];
|
||||||
nxt::BindGroup cubeTransformBindGroup[2];
|
nxt::BindGroup cubeTransformBindGroup[2];
|
||||||
|
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
|
nxt::TextureView depthStencilView;
|
||||||
nxt::RenderPipeline pipeline;
|
nxt::RenderPipeline pipeline;
|
||||||
nxt::RenderPipeline planePipeline;
|
nxt::RenderPipeline planePipeline;
|
||||||
nxt::RenderPipeline reflectionPipeline;
|
nxt::RenderPipeline reflectionPipeline;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer framebuffer;
|
|
||||||
|
|
||||||
void initBuffers() {
|
void initBuffers() {
|
||||||
static const uint32_t indexData[6*6] = {
|
static const uint32_t indexData[6*6] = {
|
||||||
|
@ -114,6 +115,8 @@ void init() {
|
||||||
device = CreateCppNXTDevice();
|
device = CreateCppNXTDevice();
|
||||||
|
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
queue = device.CreateQueueBuilder().GetResult();
|
||||||
|
swapchain = GetSwapChain(device);
|
||||||
|
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||||
|
|
||||||
initBuffers();
|
initBuffers();
|
||||||
|
|
||||||
|
@ -206,7 +209,8 @@ void init() {
|
||||||
.SetBufferViews(1, 1, &transformBufferView[1])
|
.SetBufferViews(1, 1, &transformBufferView[1])
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
renderpass = CreateDefaultRenderPass(device);
|
||||||
|
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||||
|
|
||||||
auto depthStencilState = device.CreateDepthStencilStateBuilder()
|
auto depthStencilState = device.CreateDepthStencilStateBuilder()
|
||||||
.SetDepthCompareFunction(nxt::CompareFunction::Less)
|
.SetDepthCompareFunction(nxt::CompareFunction::Less)
|
||||||
|
@ -271,6 +275,10 @@ void frame() {
|
||||||
cameraBuffer.TransitionUsage(nxt::BufferUsageBit::TransferDst);
|
cameraBuffer.TransitionUsage(nxt::BufferUsageBit::TransferDst);
|
||||||
cameraBuffer.SetSubData(0, sizeof(CameraData) / sizeof(uint32_t), reinterpret_cast<uint32_t*>(&cameraData));
|
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()
|
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||||
.BeginRenderPass(renderpass, framebuffer)
|
.BeginRenderPass(renderpass, framebuffer)
|
||||||
.BeginRenderSubpass()
|
.BeginRenderSubpass()
|
||||||
|
@ -296,7 +304,9 @@ void frame() {
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
DoSwapBuffers();
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
|
swapchain.Present(backbuffer);
|
||||||
|
DoFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
|
|
|
@ -25,9 +25,10 @@ nxt::Buffer indexBuffer;
|
||||||
nxt::Buffer vertexBuffer;
|
nxt::Buffer vertexBuffer;
|
||||||
|
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
|
nxt::TextureView depthStencilView;
|
||||||
nxt::RenderPipeline pipeline;
|
nxt::RenderPipeline pipeline;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer framebuffer;
|
|
||||||
|
|
||||||
void initBuffers() {
|
void initBuffers() {
|
||||||
static const uint32_t indexData[3] = {
|
static const uint32_t indexData[3] = {
|
||||||
|
@ -47,6 +48,8 @@ void init() {
|
||||||
device = CreateCppNXTDevice();
|
device = CreateCppNXTDevice();
|
||||||
|
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
queue = device.CreateQueueBuilder().GetResult();
|
||||||
|
swapchain = GetSwapChain(device);
|
||||||
|
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||||
|
|
||||||
initBuffers();
|
initBuffers();
|
||||||
|
|
||||||
|
@ -71,7 +74,9 @@ void init() {
|
||||||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
renderpass = CreateDefaultRenderPass(device);
|
||||||
|
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||||
|
|
||||||
pipeline = device.CreateRenderPipelineBuilder()
|
pipeline = device.CreateRenderPipelineBuilder()
|
||||||
.SetSubpass(renderpass, 0)
|
.SetSubpass(renderpass, 0)
|
||||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||||
|
@ -81,6 +86,10 @@ void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame() {
|
void frame() {
|
||||||
|
nxt::Texture backbuffer;
|
||||||
|
nxt::Framebuffer framebuffer;
|
||||||
|
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||||
|
|
||||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||||
.BeginRenderPass(renderpass, framebuffer)
|
.BeginRenderPass(renderpass, framebuffer)
|
||||||
|
@ -94,7 +103,9 @@ void frame() {
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
DoSwapBuffers();
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
|
swapchain.Present(backbuffer);
|
||||||
|
DoFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
|
|
|
@ -25,9 +25,10 @@ nxt::Buffer vertexBuffer;
|
||||||
nxt::Buffer instanceBuffer;
|
nxt::Buffer instanceBuffer;
|
||||||
|
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
|
nxt::TextureView depthStencilView;
|
||||||
nxt::RenderPipeline pipeline;
|
nxt::RenderPipeline pipeline;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer framebuffer;
|
|
||||||
|
|
||||||
void initBuffers() {
|
void initBuffers() {
|
||||||
static const float vertexData[12] = {
|
static const float vertexData[12] = {
|
||||||
|
@ -50,6 +51,8 @@ void init() {
|
||||||
device = CreateCppNXTDevice();
|
device = CreateCppNXTDevice();
|
||||||
|
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
queue = device.CreateQueueBuilder().GetResult();
|
||||||
|
swapchain = GetSwapChain(device);
|
||||||
|
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||||
|
|
||||||
initBuffers();
|
initBuffers();
|
||||||
|
|
||||||
|
@ -77,7 +80,9 @@ void init() {
|
||||||
.SetInput(1, 2 * sizeof(float), nxt::InputStepMode::Instance)
|
.SetInput(1, 2 * sizeof(float), nxt::InputStepMode::Instance)
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
renderpass = CreateDefaultRenderPass(device);
|
||||||
|
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||||
|
|
||||||
pipeline = device.CreateRenderPipelineBuilder()
|
pipeline = device.CreateRenderPipelineBuilder()
|
||||||
.SetSubpass(renderpass, 0)
|
.SetSubpass(renderpass, 0)
|
||||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||||
|
@ -87,6 +92,10 @@ void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame() {
|
void frame() {
|
||||||
|
nxt::Texture backbuffer;
|
||||||
|
nxt::Framebuffer framebuffer;
|
||||||
|
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||||
|
|
||||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||||
.BeginRenderPass(renderpass, framebuffer)
|
.BeginRenderPass(renderpass, framebuffer)
|
||||||
|
@ -100,7 +109,9 @@ void frame() {
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
DoSwapBuffers();
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
|
swapchain.Present(backbuffer);
|
||||||
|
DoFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
|
|
|
@ -28,9 +28,10 @@ nxt::Texture texture;
|
||||||
nxt::Sampler sampler;
|
nxt::Sampler sampler;
|
||||||
|
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
|
nxt::TextureView depthStencilView;
|
||||||
nxt::RenderPipeline pipeline;
|
nxt::RenderPipeline pipeline;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer framebuffer;
|
|
||||||
nxt::BindGroup bindGroup;
|
nxt::BindGroup bindGroup;
|
||||||
|
|
||||||
void initBuffers() {
|
void initBuffers() {
|
||||||
|
@ -81,6 +82,8 @@ void init() {
|
||||||
device = CreateCppNXTDevice();
|
device = CreateCppNXTDevice();
|
||||||
|
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
queue = device.CreateQueueBuilder().GetResult();
|
||||||
|
swapchain = GetSwapChain(device);
|
||||||
|
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||||
|
|
||||||
initBuffers();
|
initBuffers();
|
||||||
initTextures();
|
initTextures();
|
||||||
|
@ -118,7 +121,9 @@ void init() {
|
||||||
.SetBindGroupLayout(0, bgl)
|
.SetBindGroupLayout(0, bgl)
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
renderpass = CreateDefaultRenderPass(device);
|
||||||
|
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||||
|
|
||||||
pipeline = device.CreateRenderPipelineBuilder()
|
pipeline = device.CreateRenderPipelineBuilder()
|
||||||
.SetSubpass(renderpass, 0)
|
.SetSubpass(renderpass, 0)
|
||||||
.SetLayout(pl)
|
.SetLayout(pl)
|
||||||
|
@ -142,6 +147,11 @@ void frame() {
|
||||||
s.a = (s.a + 1) % 256;
|
s.a = (s.a + 1) % 256;
|
||||||
s.b += 0.02f;
|
s.b += 0.02f;
|
||||||
if (s.b >= 1.0f) {s.b = 0.0f;}
|
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};
|
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||||
.BeginRenderPass(renderpass, framebuffer)
|
.BeginRenderPass(renderpass, framebuffer)
|
||||||
|
@ -156,7 +166,9 @@ void frame() {
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
DoSwapBuffers();
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
|
swapchain.Present(backbuffer);
|
||||||
|
DoFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
|
|
|
@ -19,9 +19,10 @@
|
||||||
|
|
||||||
nxt::Device device;
|
nxt::Device device;
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
|
nxt::TextureView depthStencilView;
|
||||||
nxt::RenderPipeline pipeline;
|
nxt::RenderPipeline pipeline;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer framebuffer;
|
|
||||||
nxt::Buffer buffer;
|
nxt::Buffer buffer;
|
||||||
nxt::BindGroup bindGroup;
|
nxt::BindGroup bindGroup;
|
||||||
|
|
||||||
|
@ -31,6 +32,8 @@ void init() {
|
||||||
device = CreateCppNXTDevice();
|
device = CreateCppNXTDevice();
|
||||||
|
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
queue = device.CreateQueueBuilder().GetResult();
|
||||||
|
swapchain = GetSwapChain(device);
|
||||||
|
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||||
|
|
||||||
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||||
#version 450
|
#version 450
|
||||||
|
@ -60,7 +63,9 @@ void init() {
|
||||||
.SetBindGroupLayout(0, bgl)
|
.SetBindGroupLayout(0, bgl)
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
renderpass = CreateDefaultRenderPass(device);
|
||||||
|
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||||
|
|
||||||
pipeline = device.CreateRenderPipelineBuilder()
|
pipeline = device.CreateRenderPipelineBuilder()
|
||||||
.SetSubpass(renderpass, 0)
|
.SetSubpass(renderpass, 0)
|
||||||
.SetLayout(pl)
|
.SetLayout(pl)
|
||||||
|
@ -93,6 +98,10 @@ void frame() {
|
||||||
buffer.TransitionUsage(nxt::BufferUsageBit::TransferDst);
|
buffer.TransitionUsage(nxt::BufferUsageBit::TransferDst);
|
||||||
buffer.SetSubData(0, sizeof(s) / sizeof(uint32_t), reinterpret_cast<uint32_t*>(&s));
|
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()
|
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||||
.BeginRenderPass(renderpass, framebuffer)
|
.BeginRenderPass(renderpass, framebuffer)
|
||||||
.BeginRenderSubpass()
|
.BeginRenderSubpass()
|
||||||
|
@ -105,7 +114,9 @@ void frame() {
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
DoSwapBuffers();
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
|
swapchain.Present(backbuffer);
|
||||||
|
DoFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
|
|
|
@ -24,9 +24,10 @@ nxt::Device device;
|
||||||
nxt::Buffer vertexBuffer;
|
nxt::Buffer vertexBuffer;
|
||||||
|
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
|
nxt::TextureView depthStencilView;
|
||||||
nxt::RenderPipeline pipeline;
|
nxt::RenderPipeline pipeline;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer framebuffer;
|
|
||||||
|
|
||||||
void initBuffers() {
|
void initBuffers() {
|
||||||
static const float vertexData[12] = {
|
static const float vertexData[12] = {
|
||||||
|
@ -41,6 +42,8 @@ void init() {
|
||||||
device = CreateCppNXTDevice();
|
device = CreateCppNXTDevice();
|
||||||
|
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
queue = device.CreateQueueBuilder().GetResult();
|
||||||
|
swapchain = GetSwapChain(device);
|
||||||
|
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||||
|
|
||||||
initBuffers();
|
initBuffers();
|
||||||
|
|
||||||
|
@ -65,7 +68,9 @@ void init() {
|
||||||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
renderpass = CreateDefaultRenderPass(device);
|
||||||
|
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||||
|
|
||||||
pipeline = device.CreateRenderPipelineBuilder()
|
pipeline = device.CreateRenderPipelineBuilder()
|
||||||
.SetSubpass(renderpass, 0)
|
.SetSubpass(renderpass, 0)
|
||||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||||
|
@ -75,6 +80,10 @@ void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame() {
|
void frame() {
|
||||||
|
nxt::Texture backbuffer;
|
||||||
|
nxt::Framebuffer framebuffer;
|
||||||
|
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||||
|
|
||||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||||
.BeginRenderPass(renderpass, framebuffer)
|
.BeginRenderPass(renderpass, framebuffer)
|
||||||
|
@ -87,7 +96,9 @@ void frame() {
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
DoSwapBuffers();
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
|
swapchain.Present(backbuffer);
|
||||||
|
DoFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
|
|
|
@ -29,11 +29,11 @@ nxt::TextureView renderTargetView;
|
||||||
nxt::Sampler samplerPost;
|
nxt::Sampler samplerPost;
|
||||||
|
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
nxt::RenderPipeline pipeline;
|
nxt::RenderPipeline pipeline;
|
||||||
nxt::RenderPipeline pipelinePost;
|
nxt::RenderPipeline pipelinePost;
|
||||||
nxt::BindGroup bindGroup;
|
nxt::BindGroup bindGroup;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer framebuffer;
|
|
||||||
|
|
||||||
void initBuffers() {
|
void initBuffers() {
|
||||||
static const float vertexData[12] = {
|
static const float vertexData[12] = {
|
||||||
|
@ -81,14 +81,6 @@ void initRenderPass() {
|
||||||
// subpass 1
|
// subpass 1
|
||||||
.SubpassSetColorAttachment(1, 0, 1) // -> back buffer
|
.SubpassSetColorAttachment(1, 0, 1) // -> back buffer
|
||||||
.GetResult();
|
.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() {
|
void initPipeline() {
|
||||||
|
@ -174,6 +166,8 @@ void init() {
|
||||||
device = CreateCppNXTDevice();
|
device = CreateCppNXTDevice();
|
||||||
|
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
queue = device.CreateQueueBuilder().GetResult();
|
||||||
|
swapchain = GetSwapChain(device);
|
||||||
|
swapchain.Configure(nxt::TextureFormat::R8G8B8A8Unorm, 640, 480);
|
||||||
|
|
||||||
initBuffers();
|
initBuffers();
|
||||||
initTextures();
|
initTextures();
|
||||||
|
@ -183,6 +177,15 @@ void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame() {
|
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};
|
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||||
.BeginRenderPass(renderpass, framebuffer)
|
.BeginRenderPass(renderpass, framebuffer)
|
||||||
|
@ -204,7 +207,9 @@ void frame() {
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
DoSwapBuffers();
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
|
swapchain.Present(backbuffer);
|
||||||
|
DoFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <nxt/nxt.h>
|
#include <nxt/nxt.h>
|
||||||
#include <nxt/nxtcpp.h>
|
#include <nxt/nxtcpp.h>
|
||||||
|
#include <nxt/nxt_wsi.h>
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -39,9 +40,9 @@ enum class CmdBufType {
|
||||||
static utils::BackendType backendType = utils::BackendType::D3D12;
|
static utils::BackendType backendType = utils::BackendType::D3D12;
|
||||||
#elif defined(NXT_ENABLE_BACKEND_METAL)
|
#elif defined(NXT_ENABLE_BACKEND_METAL)
|
||||||
static utils::BackendType backendType = utils::BackendType::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)
|
#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;
|
static utils::BackendType backendType = utils::BackendType::Vulkan;
|
||||||
#else
|
#else
|
||||||
#error
|
#error
|
||||||
|
@ -111,6 +112,56 @@ nxt::Device CreateCppNXTDevice() {
|
||||||
return nxt::Device::Acquire(cDevice);
|
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) {
|
bool InitSample(int argc, const char** argv) {
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
if (std::string("-b") == argv[i] || std::string("--backend") == argv[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");
|
fprintf(stderr, "--backend expects a backend name (opengl, metal, d3d12, null, vulkan)\n");
|
||||||
return false;
|
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++;
|
i++;
|
||||||
if (i < argc && std::string("none") == argv[i]) {
|
if (i < argc && std::string("none") == argv[i]) {
|
||||||
cmdBufType = CmdBufType::None;
|
cmdBufType = CmdBufType::None;
|
||||||
|
@ -161,13 +212,12 @@ bool InitSample(int argc, const char** argv) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoSwapBuffers() {
|
void DoFlush() {
|
||||||
if (cmdBufType == CmdBufType::Terrible) {
|
if (cmdBufType == CmdBufType::Terrible) {
|
||||||
c2sBuf->Flush();
|
c2sBuf->Flush();
|
||||||
s2cBuf->Flush();
|
s2cBuf->Flush();
|
||||||
}
|
}
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
binding->SwapBuffers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldQuit() {
|
bool ShouldQuit() {
|
||||||
|
|
|
@ -13,12 +13,23 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include <nxt/nxtcpp.h>
|
#include <nxt/nxtcpp.h>
|
||||||
|
#include <nxt/nxt_wsi.h>
|
||||||
|
|
||||||
bool InitSample(int argc, const char** argv);
|
bool InitSample(int argc, const char** argv);
|
||||||
void DoSwapBuffers();
|
void DoFlush();
|
||||||
bool ShouldQuit();
|
bool ShouldQuit();
|
||||||
|
|
||||||
struct GLFWwindow;
|
struct GLFWwindow;
|
||||||
struct GLFWwindow* GetGLFWWindow();
|
struct GLFWwindow* GetGLFWWindow();
|
||||||
|
|
||||||
nxt::Device CreateCppNXTDevice();
|
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::Device device;
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
|
nxt::TextureView depthStencilView;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer framebuffer;
|
nxt::Framebuffer lastFramebuffer;
|
||||||
|
|
||||||
nxt::Buffer defaultBuffer;
|
nxt::Buffer defaultBuffer;
|
||||||
std::map<std::string, nxt::Buffer> buffers;
|
std::map<std::string, nxt::Buffer> buffers;
|
||||||
|
@ -467,7 +469,11 @@ namespace {
|
||||||
device = CreateCppNXTDevice();
|
device = CreateCppNXTDevice();
|
||||||
|
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
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();
|
initBuffers();
|
||||||
initSamplers();
|
initSamplers();
|
||||||
|
@ -506,7 +512,7 @@ namespace {
|
||||||
material.uniformBuffer.SetSubData(0,
|
material.uniformBuffer.SetSubData(0,
|
||||||
sizeof(u_transform_block) / sizeof(uint32_t),
|
sizeof(u_transform_block) / sizeof(uint32_t),
|
||||||
reinterpret_cast<const uint32_t*>(&transforms));
|
reinterpret_cast<const uint32_t*>(&transforms));
|
||||||
cmd.BeginRenderPass(renderpass, framebuffer);
|
cmd.BeginRenderPass(renderpass, lastFramebuffer);
|
||||||
cmd.BeginRenderSubpass();
|
cmd.BeginRenderSubpass();
|
||||||
cmd.SetRenderPipeline(material.pipeline);
|
cmd.SetRenderPipeline(material.pipeline);
|
||||||
cmd.TransitionBufferUsage(material.uniformBuffer, nxt::BufferUsageBit::Uniform);
|
cmd.TransitionBufferUsage(material.uniformBuffer, nxt::BufferUsageBit::Uniform);
|
||||||
|
@ -586,12 +592,17 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame() {
|
void frame() {
|
||||||
|
nxt::Texture backbuffer;
|
||||||
|
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &lastFramebuffer);
|
||||||
|
|
||||||
const auto& defaultSceneNodes = scene.scenes.at(scene.defaultScene);
|
const auto& defaultSceneNodes = scene.scenes.at(scene.defaultScene);
|
||||||
for (const auto& n : defaultSceneNodes) {
|
for (const auto& n : defaultSceneNodes) {
|
||||||
const auto& node = scene.nodes.at(n);
|
const auto& node = scene.nodes.at(n);
|
||||||
drawNode(node);
|
drawNode(node);
|
||||||
}
|
}
|
||||||
DoSwapBuffers();
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
|
swapchain.Present(backbuffer);
|
||||||
|
DoFlush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -521,6 +521,10 @@
|
||||||
"name": "create shader module builder",
|
"name": "create shader module builder",
|
||||||
"returns": "shader module builder"
|
"returns": "shader module builder"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "create swap chain builder",
|
||||||
|
"returns": "swap chain builder"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "create texture builder",
|
"name": "create texture builder",
|
||||||
"returns": "texture builder"
|
"returns": "texture builder"
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "backend/RenderPipeline.h"
|
#include "backend/RenderPipeline.h"
|
||||||
#include "backend/Sampler.h"
|
#include "backend/Sampler.h"
|
||||||
#include "backend/ShaderModule.h"
|
#include "backend/ShaderModule.h"
|
||||||
|
#include "backend/SwapChain.h"
|
||||||
#include "backend/Texture.h"
|
#include "backend/Texture.h"
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
@ -130,6 +131,9 @@ namespace backend {
|
||||||
ShaderModuleBuilder* DeviceBase::CreateShaderModuleBuilder() {
|
ShaderModuleBuilder* DeviceBase::CreateShaderModuleBuilder() {
|
||||||
return new ShaderModuleBuilder(this);
|
return new ShaderModuleBuilder(this);
|
||||||
}
|
}
|
||||||
|
SwapChainBuilder* DeviceBase::CreateSwapChainBuilder() {
|
||||||
|
return new SwapChainBuilder(this);
|
||||||
|
}
|
||||||
TextureBuilder* DeviceBase::CreateTextureBuilder() {
|
TextureBuilder* DeviceBase::CreateTextureBuilder() {
|
||||||
return new TextureBuilder(this);
|
return new TextureBuilder(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ namespace backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
SwapChainBase::~SwapChainBase() {
|
SwapChainBase::~SwapChainBase() {
|
||||||
|
const auto& im = GetImplementation();
|
||||||
|
im.Destroy(im.userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceBase* SwapChainBase::GetDevice() {
|
DeviceBase* SwapChainBase::GetDevice() {
|
||||||
|
@ -41,6 +43,8 @@ namespace backend {
|
||||||
this->format = format;
|
this->format = format;
|
||||||
this->width = width;
|
this->width = width;
|
||||||
this->height = height;
|
this->height = height;
|
||||||
|
implementation.Configure(implementation.userData,
|
||||||
|
static_cast<nxtTextureFormat>(format), width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureBase* SwapChainBase::GetNextTexture() {
|
TextureBase* SwapChainBase::GetNextTexture() {
|
||||||
|
@ -102,7 +106,7 @@ namespace backend {
|
||||||
|
|
||||||
nxtSwapChainImplementation& impl = *reinterpret_cast<nxtSwapChainImplementation*>(implementation);
|
nxtSwapChainImplementation& impl = *reinterpret_cast<nxtSwapChainImplementation*>(implementation);
|
||||||
|
|
||||||
if (!impl.Init || impl.Destroy || !impl.Configure ||
|
if (!impl.Init || !impl.Destroy || !impl.Configure ||
|
||||||
!impl.GetNextTexture || !impl.Present) {
|
!impl.GetNextTexture || !impl.Present) {
|
||||||
HandleError("Implementation is incomplete");
|
HandleError("Implementation is incomplete");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace d3d12 {
|
||||||
{
|
{
|
||||||
auto* view = ToBackend(GetBindingAsTextureView(binding));
|
auto* view = ToBackend(GetBindingAsTextureView(binding));
|
||||||
auto& srv = view->GetSRVDescriptor();
|
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;
|
break;
|
||||||
case nxt::BindingType::Sampler:
|
case nxt::BindingType::Sampler:
|
||||||
|
|
|
@ -309,7 +309,7 @@ namespace d3d12 {
|
||||||
);
|
);
|
||||||
|
|
||||||
D3D12_TEXTURE_COPY_LOCATION textureLocation;
|
D3D12_TEXTURE_COPY_LOCATION textureLocation;
|
||||||
textureLocation.pResource = texture->GetD3D12Resource().Get();
|
textureLocation.pResource = texture->GetD3D12Resource();
|
||||||
textureLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
textureLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||||
textureLocation.SubresourceIndex = copy->destination.level;
|
textureLocation.SubresourceIndex = copy->destination.level;
|
||||||
|
|
||||||
|
@ -358,7 +358,7 @@ namespace d3d12 {
|
||||||
);
|
);
|
||||||
|
|
||||||
D3D12_TEXTURE_COPY_LOCATION textureLocation;
|
D3D12_TEXTURE_COPY_LOCATION textureLocation;
|
||||||
textureLocation.pResource = texture->GetD3D12Resource().Get();
|
textureLocation.pResource = texture->GetD3D12Resource();
|
||||||
textureLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
textureLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||||
textureLocation.SubresourceIndex = copy->source.level;
|
textureLocation.SubresourceIndex = copy->source.level;
|
||||||
|
|
||||||
|
|
|
@ -51,11 +51,6 @@ namespace d3d12 {
|
||||||
return backendDevice->GetCommandQueue();
|
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) {
|
uint64_t GetSerial(const nxtDevice device) {
|
||||||
const Device* backendDevice = reinterpret_cast<const Device*>(device);
|
const Device* backendDevice = reinterpret_cast<const Device*>(device);
|
||||||
return backendDevice->GetSerial();
|
return backendDevice->GetSerial();
|
||||||
|
@ -101,6 +96,8 @@ namespace d3d12 {
|
||||||
ASSERT_SUCCESS(d3d12Device->CreateFence(serial, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)));
|
ASSERT_SUCCESS(d3d12Device->CreateFence(serial, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)));
|
||||||
fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||||
ASSERT(fenceEvent != nullptr);
|
ASSERT(fenceEvent != nullptr);
|
||||||
|
|
||||||
|
NextSerial();
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::~Device() {
|
Device::~Device() {
|
||||||
|
@ -163,15 +160,6 @@ namespace d3d12 {
|
||||||
return pendingCommands.commandList;
|
return pendingCommands.commandList;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComPtr<ID3D12Resource> Device::GetCurrentTexture() {
|
|
||||||
return nextTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Device::SetNextTexture(ComPtr<ID3D12Resource> resource) {
|
|
||||||
nextTexture = resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Device::TickImpl() {
|
void Device::TickImpl() {
|
||||||
// Perform cleanup operations to free unused objects
|
// Perform cleanup operations to free unused objects
|
||||||
const uint64_t lastCompletedSerial = fence->GetCompletedValue();
|
const uint64_t lastCompletedSerial = fence->GetCompletedValue();
|
||||||
|
|
|
@ -120,9 +120,6 @@ namespace d3d12 {
|
||||||
void OpenCommandList(ComPtr<ID3D12GraphicsCommandList>* commandList);
|
void OpenCommandList(ComPtr<ID3D12GraphicsCommandList>* commandList);
|
||||||
ComPtr<ID3D12GraphicsCommandList> GetPendingCommandList();
|
ComPtr<ID3D12GraphicsCommandList> GetPendingCommandList();
|
||||||
|
|
||||||
ComPtr<ID3D12Resource> GetCurrentTexture();
|
|
||||||
void SetNextTexture(ComPtr<ID3D12Resource> resource);
|
|
||||||
|
|
||||||
uint64_t GetSerial() const;
|
uint64_t GetSerial() const;
|
||||||
void NextSerial();
|
void NextSerial();
|
||||||
void WaitForSerial(uint64_t serial);
|
void WaitForSerial(uint64_t serial);
|
||||||
|
@ -147,8 +144,6 @@ namespace d3d12 {
|
||||||
ComPtr<ID3D12GraphicsCommandList> commandList;
|
ComPtr<ID3D12GraphicsCommandList> commandList;
|
||||||
bool open = false;
|
bool open = false;
|
||||||
} pendingCommands;
|
} pendingCommands;
|
||||||
|
|
||||||
ComPtr<ID3D12Resource> nextTexture;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DepthStencilState : public DepthStencilStateBase {
|
class DepthStencilState : public DepthStencilStateBase {
|
||||||
|
|
|
@ -78,20 +78,7 @@ namespace d3d12 {
|
||||||
|
|
||||||
for (uint32_t index : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
for (uint32_t index : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
||||||
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.colorAttachments[index]];
|
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.colorAttachments[index]];
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(heapIndex);
|
args.RTVs[args.numRTVs++] = 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;
|
|
||||||
}
|
}
|
||||||
if (subpassInfo.depthStencilAttachmentSet) {
|
if (subpassInfo.depthStencilAttachmentSet) {
|
||||||
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.depthStencilAttachment];
|
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.depthStencilAttachment];
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "backend/d3d12/SwapChainD3D12.h"
|
#include "backend/d3d12/SwapChainD3D12.h"
|
||||||
|
|
||||||
|
#include "backend/d3d12/D3D12Backend.h"
|
||||||
#include "backend/d3d12/TextureD3D12.h"
|
#include "backend/d3d12/TextureD3D12.h"
|
||||||
|
|
||||||
#include <nxt/nxt_wsi.h>
|
#include <nxt/nxt_wsi.h>
|
||||||
|
@ -25,19 +26,23 @@ namespace d3d12 {
|
||||||
: SwapChainBase(builder) {
|
: SwapChainBase(builder) {
|
||||||
const auto& im = GetImplementation();
|
const auto& im = GetImplementation();
|
||||||
nxtWSIContextD3D12 wsiContext = {};
|
nxtWSIContextD3D12 wsiContext = {};
|
||||||
// TODO(kainino@chromium.org): set up wsiContext
|
wsiContext.device = reinterpret_cast<nxtDevice>(GetDevice());
|
||||||
im.Init(im.userData, &wsiContext);
|
im.Init(im.userData, &wsiContext);
|
||||||
|
|
||||||
// TODO(kainino@chromium.org): set up D3D12 swapchain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SwapChain::~SwapChain() {
|
SwapChain::~SwapChain() {
|
||||||
// TODO(kainino@chromium.org): clean up D3D12 swapchain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
|
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
|
||||||
ComPtr<ID3D12Resource> nativeTexture = nullptr;
|
const auto& im = GetImplementation();
|
||||||
// TODO(kainino@chromium.org): obtain native texture from D3D12 swapchain
|
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);
|
return new Texture(builder, nativeTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,23 +105,28 @@ namespace d3d12 {
|
||||||
resourceDescriptor.Flags = D3D12ResourceFlags(GetAllowedUsage(), GetFormat());
|
resourceDescriptor.Flags = D3D12ResourceFlags(GetAllowedUsage(), GetFormat());
|
||||||
|
|
||||||
resource = device->GetResourceAllocator()->Allocate(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, D3D12TextureUsage(GetUsage(), GetFormat()));
|
resource = device->GetResourceAllocator()->Allocate(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, D3D12TextureUsage(GetUsage(), GetFormat()));
|
||||||
|
resourcePtr = resource.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture::Texture(TextureBuilder* builder, ComPtr<ID3D12Resource> nativeTexture)
|
// With this constructor, the lifetime of the ID3D12Resource is externally managed.
|
||||||
: TextureBase(builder), device(ToBackend(builder->GetDevice())), resource(nativeTexture) {
|
Texture::Texture(TextureBuilder* builder, ID3D12Resource* nativeTexture)
|
||||||
|
: TextureBase(builder), device(ToBackend(builder->GetDevice())),
|
||||||
|
resourcePtr(nativeTexture) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture::~Texture() {
|
Texture::~Texture() {
|
||||||
// TODO(kainino@chromium.org): Maybe don't release when using the native texture constructor?
|
if (resource) {
|
||||||
device->GetResourceAllocator()->Release(resource);
|
// If we own the resource, release it.
|
||||||
|
device->GetResourceAllocator()->Release(resource);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DXGI_FORMAT Texture::GetD3D12Format() const {
|
DXGI_FORMAT Texture::GetD3D12Format() const {
|
||||||
return D3D12TextureFormat(GetFormat());
|
return D3D12TextureFormat(GetFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
ComPtr<ID3D12Resource> Texture::GetD3D12Resource() {
|
ID3D12Resource* Texture::GetD3D12Resource() {
|
||||||
return resource;
|
return resourcePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Texture::GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier) {
|
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->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
barrier->Transition.pResource = resource.Get();
|
barrier->Transition.pResource = resourcePtr;
|
||||||
barrier->Transition.StateBefore = stateBefore;
|
barrier->Transition.StateBefore = stateBefore;
|
||||||
barrier->Transition.StateAfter = stateAfter;
|
barrier->Transition.StateAfter = stateAfter;
|
||||||
barrier->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
barrier->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
|
|
@ -29,16 +29,17 @@ namespace d3d12 {
|
||||||
class Texture : public TextureBase {
|
class Texture : public TextureBase {
|
||||||
public:
|
public:
|
||||||
Texture(TextureBuilder* builder);
|
Texture(TextureBuilder* builder);
|
||||||
Texture(TextureBuilder* builder, ComPtr<ID3D12Resource> nativeTexture);
|
Texture(TextureBuilder* builder, ID3D12Resource* nativeTexture);
|
||||||
~Texture();
|
~Texture();
|
||||||
|
|
||||||
DXGI_FORMAT GetD3D12Format() const;
|
DXGI_FORMAT GetD3D12Format() const;
|
||||||
ComPtr<ID3D12Resource> GetD3D12Resource();
|
ID3D12Resource* GetD3D12Resource();
|
||||||
bool GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier);
|
bool GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Device* device;
|
Device* device;
|
||||||
ComPtr<ID3D12Resource> resource;
|
ComPtr<ID3D12Resource> resource = {};
|
||||||
|
ID3D12Resource* resourcePtr = nullptr;
|
||||||
|
|
||||||
// NXT API
|
// NXT API
|
||||||
void TransitionUsageImpl(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage) override;
|
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) {
|
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
|
||||||
uint32_t attachment = info.colorAttachments[index];
|
uint32_t attachment = info.colorAttachments[index];
|
||||||
|
|
||||||
// TODO(kainino@chromium.org): currently a 'null' texture view
|
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
||||||
// falls back to the 'back buffer' but this should go away
|
auto texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
|
||||||
// when we have WSI.
|
|
||||||
id<MTLTexture> texture = nil;
|
|
||||||
if (auto textureView = currentFramebuffer->GetTextureView(attachment)) {
|
|
||||||
texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
|
|
||||||
} else {
|
|
||||||
texture = device->GetCurrentTexture();
|
|
||||||
}
|
|
||||||
descriptor.colorAttachments[index].texture = texture;
|
descriptor.colorAttachments[index].texture = texture;
|
||||||
descriptor.colorAttachments[index].loadAction = MTLLoadActionLoad;
|
descriptor.colorAttachments[index].loadAction = MTLLoadActionLoad;
|
||||||
descriptor.colorAttachments[index].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
|
descriptor.colorAttachments[index].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
|
||||||
|
|
|
@ -109,11 +109,7 @@ namespace metal {
|
||||||
|
|
||||||
void TickImpl() override;
|
void TickImpl() override;
|
||||||
|
|
||||||
void SetNextDrawable(id<CAMetalDrawable> drawable);
|
|
||||||
void Present();
|
|
||||||
|
|
||||||
id<MTLDevice> GetMTLDevice();
|
id<MTLDevice> GetMTLDevice();
|
||||||
id<MTLTexture> GetCurrentTexture();
|
|
||||||
|
|
||||||
id<MTLCommandBuffer> GetPendingCommandBuffer();
|
id<MTLCommandBuffer> GetPendingCommandBuffer();
|
||||||
void SubmitPendingCommandBuffer();
|
void SubmitPendingCommandBuffer();
|
||||||
|
@ -130,9 +126,6 @@ namespace metal {
|
||||||
MapReadRequestTracker* mapReadTracker;
|
MapReadRequestTracker* mapReadTracker;
|
||||||
ResourceUploader* resourceUploader;
|
ResourceUploader* resourceUploader;
|
||||||
|
|
||||||
id<CAMetalDrawable> currentDrawable = nil;
|
|
||||||
id<MTLTexture> currentTexture = nil;
|
|
||||||
|
|
||||||
Serial finishedCommandSerial = 0;
|
Serial finishedCommandSerial = 0;
|
||||||
Serial pendingCommandSerial = 1;
|
Serial pendingCommandSerial = 1;
|
||||||
id<MTLCommandBuffer> pendingCommands = nil;
|
id<MTLCommandBuffer> pendingCommands = nil;
|
||||||
|
|
|
@ -41,16 +41,6 @@ namespace metal {
|
||||||
*device = reinterpret_cast<nxtDevice>(new Device(metalDevice));
|
*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::Device(id<MTLDevice> mtlDevice)
|
Device::Device(id<MTLDevice> mtlDevice)
|
||||||
|
@ -86,9 +76,6 @@ namespace metal {
|
||||||
|
|
||||||
[commandQueue release];
|
[commandQueue release];
|
||||||
commandQueue = nil;
|
commandQueue = nil;
|
||||||
|
|
||||||
[currentTexture release];
|
|
||||||
currentTexture = nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
|
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
|
||||||
|
@ -155,43 +142,10 @@ namespace metal {
|
||||||
SubmitPendingCommandBuffer();
|
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() {
|
id<MTLDevice> Device::GetMTLDevice() {
|
||||||
return mtlDevice;
|
return mtlDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
id<MTLTexture> Device::GetCurrentTexture() {
|
|
||||||
return currentTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLCommandBuffer> Device::GetPendingCommandBuffer() {
|
id<MTLCommandBuffer> Device::GetPendingCommandBuffer() {
|
||||||
if (pendingCommands == nil) {
|
if (pendingCommands == nil) {
|
||||||
pendingCommands = [commandQueue commandBuffer];
|
pendingCommands = [commandQueue commandBuffer];
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "backend/metal/SwapChainMTL.h"
|
#include "backend/metal/SwapChainMTL.h"
|
||||||
|
|
||||||
|
#include "backend/metal/MetalBackend.h"
|
||||||
#include "backend/metal/TextureMTL.h"
|
#include "backend/metal/TextureMTL.h"
|
||||||
|
|
||||||
#include <nxt/nxt_wsi.h>
|
#include <nxt/nxt_wsi.h>
|
||||||
|
@ -25,19 +26,23 @@ namespace metal {
|
||||||
: SwapChainBase(builder) {
|
: SwapChainBase(builder) {
|
||||||
const auto& im = GetImplementation();
|
const auto& im = GetImplementation();
|
||||||
nxtWSIContextMetal wsiContext = {};
|
nxtWSIContextMetal wsiContext = {};
|
||||||
// TODO(kainino@chromium.org): set up wsiContext
|
wsiContext.device = ToBackend(GetDevice())->GetMTLDevice();
|
||||||
im.Init(im.userData, &wsiContext);
|
im.Init(im.userData, &wsiContext);
|
||||||
|
|
||||||
// TODO(kainino@chromium.org): set up Metal swapchain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SwapChain::~SwapChain() {
|
SwapChain::~SwapChain() {
|
||||||
// TODO(kainino@chromium.org): clean up Metal swapchain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
|
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
|
||||||
id<MTLTexture> nativeTexture = nil;
|
const auto& im = GetImplementation();
|
||||||
// TODO(kainino@chromium.org): obtain MTLTexture from Metal swapchain
|
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);
|
return new Texture(builder, nativeTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,21 +104,13 @@ namespace opengl {
|
||||||
glGenFramebuffers(1, ¤tFBO);
|
glGenFramebuffers(1, ¤tFBO);
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
|
||||||
|
|
||||||
auto* device = ToBackend(GetDevice());
|
|
||||||
const auto& info = currentRenderPass->GetSubpassInfo(currentSubpass);
|
const auto& info = currentRenderPass->GetSubpassInfo(currentSubpass);
|
||||||
|
|
||||||
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
|
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
|
||||||
uint32_t attachment = info.colorAttachments[index];
|
uint32_t attachment = info.colorAttachments[index];
|
||||||
|
|
||||||
// TODO(kainino@chromium.org): currently a 'null' texture view
|
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
||||||
// falls back to the 'back buffer' but this should go away
|
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
|
||||||
// when we have WSI.
|
|
||||||
GLuint texture = 0;
|
|
||||||
if (auto textureView = currentFramebuffer->GetTextureView(attachment)) {
|
|
||||||
texture = ToBackend(textureView->GetTexture())->GetHandle();
|
|
||||||
} else {
|
|
||||||
texture = device->GetCurrentTexture();
|
|
||||||
}
|
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
|
||||||
GL_COLOR_ATTACHMENT0 + index,
|
GL_COLOR_ATTACHMENT0 + index,
|
||||||
GL_TEXTURE_2D, texture, 0);
|
GL_TEXTURE_2D, texture, 0);
|
||||||
|
@ -131,6 +123,7 @@ namespace opengl {
|
||||||
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
|
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
|
||||||
|
|
||||||
GLenum glAttachment = 0;
|
GLenum glAttachment = 0;
|
||||||
|
// TODO(kainino@chromium.org): it may be valid to just always use GL_DEPTH_STENCIL_ATTACHMENT here.
|
||||||
if (TextureFormatHasDepth(format)) {
|
if (TextureFormatHasDepth(format)) {
|
||||||
if (TextureFormatHasStencil(format)) {
|
if (TextureFormatHasStencil(format)) {
|
||||||
glAttachment = GL_DEPTH_STENCIL_ATTACHMENT;
|
glAttachment = GL_DEPTH_STENCIL_ATTACHMENT;
|
||||||
|
|
|
@ -30,11 +30,6 @@ namespace opengl {
|
||||||
nxtProcTable GetNonValidatingProcs();
|
nxtProcTable GetNonValidatingProcs();
|
||||||
nxtProcTable GetValidatingProcs();
|
nxtProcTable GetValidatingProcs();
|
||||||
|
|
||||||
void HACKCLEAR(nxtDevice device) {
|
|
||||||
Device* backendDevice = reinterpret_cast<Device*>(device);
|
|
||||||
backendDevice->HACKCLEAR();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device) {
|
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device) {
|
||||||
*device = nullptr;
|
*device = nullptr;
|
||||||
|
|
||||||
|
@ -44,17 +39,6 @@ namespace opengl {
|
||||||
*device = reinterpret_cast<nxtDevice>(new Device);
|
*device = reinterpret_cast<nxtDevice>(new Device);
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
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
|
// Device
|
||||||
|
@ -117,36 +101,6 @@ namespace opengl {
|
||||||
void Device::TickImpl() {
|
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
|
// Bind Group
|
||||||
|
|
||||||
BindGroup::BindGroup(BindGroupBuilder* builder)
|
BindGroup::BindGroup(BindGroupBuilder* builder)
|
||||||
|
|
|
@ -104,15 +104,6 @@ namespace opengl {
|
||||||
TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
|
TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
|
||||||
|
|
||||||
void TickImpl() override;
|
void TickImpl() override;
|
||||||
|
|
||||||
void HACKCLEAR();
|
|
||||||
void InitBackbuffer();
|
|
||||||
void CommitBackbuffer();
|
|
||||||
GLuint GetCurrentTexture();
|
|
||||||
|
|
||||||
private:
|
|
||||||
GLuint backFBO = 0;
|
|
||||||
GLuint backTexture = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BindGroup : public BindGroupBase {
|
class BindGroup : public BindGroupBase {
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "backend/opengl/SwapChainGL.h"
|
#include "backend/opengl/SwapChainGL.h"
|
||||||
|
|
||||||
|
#include "backend/Device.h"
|
||||||
#include "backend/opengl/TextureGL.h"
|
#include "backend/opengl/TextureGL.h"
|
||||||
|
|
||||||
#include <nxt/nxt_wsi.h>
|
#include <nxt/nxt_wsi.h>
|
||||||
|
@ -24,18 +25,21 @@ namespace opengl {
|
||||||
SwapChain::SwapChain(SwapChainBuilder* builder)
|
SwapChain::SwapChain(SwapChainBuilder* builder)
|
||||||
: SwapChainBase(builder) {
|
: SwapChainBase(builder) {
|
||||||
const auto& im = GetImplementation();
|
const auto& im = GetImplementation();
|
||||||
nxtWSIContextGL wsiContext = {};
|
im.Init(im.userData, nullptr);
|
||||||
// TODO(kainino@chromium.org): set up wsiContext
|
|
||||||
im.Init(im.userData, &wsiContext);
|
|
||||||
|
|
||||||
// TODO(kainino@chromium.org): set up FBO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SwapChain::~SwapChain() {
|
SwapChain::~SwapChain() {
|
||||||
// TODO(kainino@chromium.org): clean up FBO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
|
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);
|
return new Texture(builder, nativeTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,6 @@ namespace opengl {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TextureBase* GetNextTextureImpl(TextureBuilder* builder) override;
|
TextureBase* GetNextTextureImpl(TextureBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
|
||||||
GLuint nativeTexture = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
// Error message (or nullptr if there was no error)
|
// Error message (or nullptr if there was no error)
|
||||||
typedef const char* nxtSwapChainError;
|
typedef const char* nxtSwapChainError;
|
||||||
|
constexpr nxtSwapChainError NXT_SWAP_CHAIN_NO_ERROR = nullptr;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/// Backend-specific texture id/name/pointer
|
/// Backend-specific texture id/name/pointer
|
||||||
|
@ -46,13 +47,17 @@ typedef struct {
|
||||||
void* userData = nullptr;
|
void* userData = nullptr;
|
||||||
} nxtSwapChainImplementation;
|
} nxtSwapChainImplementation;
|
||||||
|
|
||||||
#ifdef NXT_ENABLE_BACKEND_D3D12
|
#if defined(NXT_ENABLE_BACKEND_D3D12) && defined(__cplusplus)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
nxtDevice device = nullptr;
|
||||||
} nxtWSIContextD3D12;
|
} nxtWSIContextD3D12;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NXT_ENABLE_BACKEND_METAL
|
#if defined(NXT_ENABLE_BACKEND_METAL) && defined(__OBJC__)
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
id<MTLDevice> device = nil;
|
||||||
} nxtWSIContextMetal;
|
} nxtWSIContextMetal;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -137,6 +137,10 @@ void NXTTest::SetUp() {
|
||||||
device = nxt::Device::Acquire(backendDevice);
|
device = nxt::Device::Acquire(backendDevice);
|
||||||
queue = device.CreateQueueBuilder().GetResult();
|
queue = device.CreateQueueBuilder().GetResult();
|
||||||
|
|
||||||
|
swapchain = device.CreateSwapChainBuilder()
|
||||||
|
.SetImplementation(binding->GetSwapChainImplementation())
|
||||||
|
.GetResult();
|
||||||
|
|
||||||
device.SetErrorCallback(DeviceErrorCauseTestFailure, 0);
|
device.SetErrorCallback(DeviceErrorCauseTestFailure, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,8 +221,11 @@ void NXTTest::WaitABit() {
|
||||||
utils::USleep(100);
|
utils::USleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NXTTest::SwapBuffers() {
|
void NXTTest::SwapBuffersForCapture() {
|
||||||
binding->SwapBuffers();
|
// 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) {
|
NXTTest::ReadbackReservation NXTTest::ReserveReadback(uint32_t readbackSize) {
|
||||||
|
|
|
@ -77,13 +77,15 @@ class NXTTest : public ::testing::TestWithParam<BackendType> {
|
||||||
protected:
|
protected:
|
||||||
nxt::Device device;
|
nxt::Device device;
|
||||||
nxt::Queue queue;
|
nxt::Queue queue;
|
||||||
|
nxt::SwapChain swapchain;
|
||||||
|
|
||||||
// Helper methods to implement the EXPECT_ macros
|
// 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& 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);
|
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 WaitABit();
|
||||||
void SwapBuffers();
|
|
||||||
|
void SwapBuffersForCapture();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// MapRead buffers used to get data for the expectations
|
// MapRead buffers used to get data for the expectations
|
||||||
|
|
|
@ -21,7 +21,7 @@ class RenderPipelineValidationTest : public ValidationTest {
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
ValidationTest::SetUp();
|
ValidationTest::SetUp();
|
||||||
|
|
||||||
utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
|
CreateSimpleRenderPassAndFramebuffer(device, &renderpass, &framebuffer);
|
||||||
|
|
||||||
pipelineLayout = device.CreatePipelineLayoutBuilder().GetResult();
|
pipelineLayout = device.CreatePipelineLayoutBuilder().GetResult();
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,32 @@ bool ValidationTest::EndExpectDeviceError() {
|
||||||
return error;
|
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) {
|
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
|
// 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.
|
// 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();
|
void StartExpectDeviceError();
|
||||||
bool EndExpectDeviceError();
|
bool EndExpectDeviceError();
|
||||||
|
|
||||||
|
void CreateSimpleRenderPassAndFramebuffer(const nxt::Device& device, nxt::RenderPass* renderpass, nxt::Framebuffer* framebuffer);
|
||||||
|
|
||||||
// Helper functions to create objects to test validation.
|
// Helper functions to create objects to test validation.
|
||||||
|
|
||||||
struct DummyRenderPass {
|
struct DummyRenderPass {
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#ifndef UTILS_BACKENDBINDING_H_
|
#ifndef UTILS_BACKENDBINDING_H_
|
||||||
#define UTILS_BACKENDBINDING_H_
|
#define UTILS_BACKENDBINDING_H_
|
||||||
|
|
||||||
|
#include <nxt/nxt_wsi.h>
|
||||||
|
|
||||||
struct GLFWwindow;
|
struct GLFWwindow;
|
||||||
typedef struct nxtProcTable_s nxtProcTable;
|
typedef struct nxtProcTable_s nxtProcTable;
|
||||||
typedef struct nxtDeviceImpl* nxtDevice;
|
typedef struct nxtDeviceImpl* nxtDevice;
|
||||||
|
@ -35,7 +37,7 @@ namespace utils {
|
||||||
|
|
||||||
virtual void SetupGLFWWindowHints() = 0;
|
virtual void SetupGLFWWindowHints() = 0;
|
||||||
virtual void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) = 0;
|
virtual void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) = 0;
|
||||||
virtual void SwapBuffers() = 0;
|
virtual uint64_t GetSwapChainImplementation() = 0;
|
||||||
|
|
||||||
void SetWindow(GLFWwindow* window);
|
void SetWindow(GLFWwindow* window);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ list(APPEND UTILS_SOURCES
|
||||||
${UTILS_DIR}/BackendBinding.h
|
${UTILS_DIR}/BackendBinding.h
|
||||||
${UTILS_DIR}/NXTHelpers.cpp
|
${UTILS_DIR}/NXTHelpers.cpp
|
||||||
${UTILS_DIR}/NXTHelpers.h
|
${UTILS_DIR}/NXTHelpers.h
|
||||||
|
${UTILS_DIR}/SwapChainImpl.h
|
||||||
${UTILS_DIR}/SystemUtils.cpp
|
${UTILS_DIR}/SystemUtils.cpp
|
||||||
${UTILS_DIR}/SystemUtils.h
|
${UTILS_DIR}/SystemUtils.h
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include "utils/BackendBinding.h"
|
#include "utils/BackendBinding.h"
|
||||||
|
|
||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
|
#include "nxt/nxt_wsi.h"
|
||||||
|
#include "utils/SwapChainImpl.h"
|
||||||
|
|
||||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
|
@ -34,7 +36,6 @@ namespace backend {
|
||||||
namespace d3d12 {
|
namespace d3d12 {
|
||||||
void Init(ComPtr<ID3D12Device> d3d12Device, nxtProcTable* procs, nxtDevice* device);
|
void Init(ComPtr<ID3D12Device> d3d12Device, nxtProcTable* procs, nxtDevice* device);
|
||||||
ComPtr<ID3D12CommandQueue> GetCommandQueue(nxtDevice device);
|
ComPtr<ID3D12CommandQueue> GetCommandQueue(nxtDevice device);
|
||||||
void SetNextTexture(nxtDevice device, ComPtr<ID3D12Resource> resource);
|
|
||||||
uint64_t GetSerial(const nxtDevice device);
|
uint64_t GetSerial(const nxtDevice device);
|
||||||
void NextSerial(nxtDevice device);
|
void NextSerial(nxtDevice device);
|
||||||
void ExecuteCommandLists(nxtDevice device, std::initializer_list<ID3D12CommandList*> commandLists);
|
void ExecuteCommandLists(nxtDevice device, std::initializer_list<ID3D12CommandList*> commandLists);
|
||||||
|
@ -44,48 +45,88 @@ namespace d3d12 {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
namespace {
|
||||||
|
void ASSERT_SUCCESS(HRESULT hr) {
|
||||||
|
ASSERT(SUCCEEDED(hr));
|
||||||
|
}
|
||||||
|
|
||||||
class D3D12Binding : public BackendBinding {
|
ComPtr<IDXGIFactory4> CreateFactory() {
|
||||||
public:
|
ComPtr<IDXGIFactory4> factory;
|
||||||
void SetupGLFWWindowHints() override {
|
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
uint32_t dxgiFactoryFlags = 0;
|
||||||
uint32_t dxgiFactoryFlags = 0;
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// Enable the debug layer (requires the Graphics Tools "optional feature").
|
// Enable the debug layer (requires the Graphics Tools "optional feature").
|
||||||
// NOTE: Enabling the debug layer after device creation will invalidate the active device.
|
// NOTE: Enabling the debug layer after device creation will invalidate the active device.
|
||||||
{
|
{
|
||||||
ComPtr<ID3D12Debug> debugController;
|
ComPtr<ID3D12Debug> debugController;
|
||||||
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
|
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
|
||||||
debugController->EnableDebugLayer();
|
debugController->EnableDebugLayer();
|
||||||
|
|
||||||
// Enable additional debug layers.
|
// Enable additional debug layers.
|
||||||
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
|
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
#endif
|
||||||
|
|
||||||
ASSERT_SUCCESS(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)));
|
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);
|
return factory;
|
||||||
backendDevice = *device;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
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 = {};
|
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
|
||||||
swapChainDesc.Width = width;
|
swapChainDesc.Width = width;
|
||||||
swapChainDesc.Height = height;
|
swapChainDesc.Height = height;
|
||||||
|
@ -96,11 +137,10 @@ namespace utils {
|
||||||
swapChainDesc.SampleDesc.Count = 1;
|
swapChainDesc.SampleDesc.Count = 1;
|
||||||
swapChainDesc.SampleDesc.Quality = 0;
|
swapChainDesc.SampleDesc.Quality = 0;
|
||||||
|
|
||||||
HWND win32Window = glfwGetWin32Window(window);
|
|
||||||
ComPtr<IDXGISwapChain1> swapChain1;
|
ComPtr<IDXGISwapChain1> swapChain1;
|
||||||
ASSERT_SUCCESS(factory->CreateSwapChainForHwnd(
|
ASSERT_SUCCESS(factory->CreateSwapChainForHwnd(
|
||||||
commandQueue.Get(),
|
commandQueue.Get(),
|
||||||
win32Window,
|
window,
|
||||||
&swapChainDesc,
|
&swapChainDesc,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -122,48 +162,26 @@ namespace utils {
|
||||||
lastSerialRenderTargetWasUsed[n] = initialSerial;
|
lastSerialRenderTargetWasUsed[n] = initialSerial;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transition the first frame to be a render target
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
{
|
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwapBuffers() override {
|
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
|
||||||
// Transition current frame's render target for presenting
|
nextTexture->texture = renderTargetResources[renderTargetIndex].Get();
|
||||||
{
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
}
|
||||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
|
||||||
resourceBarrier.Transition.pResource = renderTargetResources[renderTargetIndex].Get();
|
nxtSwapChainError Present() {
|
||||||
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
// Current frame already transitioned to Present by the application, but
|
||||||
resourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
// we need to flush the D3D12 backend's pending transitions.
|
||||||
resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
procs.deviceTick(backendDevice);
|
||||||
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() });
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_SUCCESS(swapChain->Present(1, 0));
|
ASSERT_SUCCESS(swapChain->Present(1, 0));
|
||||||
|
|
||||||
// Transition last frame's render target back to being a render target
|
// Transition last frame's render target back to being a render target
|
||||||
{
|
{
|
||||||
|
ComPtr<ID3D12GraphicsCommandList> commandList = {};
|
||||||
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
D3D12_RESOURCE_BARRIER resourceBarrier;
|
||||||
resourceBarrier.Transition.pResource = renderTargetResources[previousRenderTargetIndex].Get();
|
resourceBarrier.Transition.pResource = renderTargetResources[previousRenderTargetIndex].Get();
|
||||||
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
|
@ -188,32 +206,47 @@ namespace utils {
|
||||||
|
|
||||||
lastSerialRenderTargetWasUsed[renderTargetIndex] = backend::d3d12::GetSerial(backendDevice);
|
lastSerialRenderTargetWasUsed[renderTargetIndex] = backend::d3d12::GetSerial(backendDevice);
|
||||||
|
|
||||||
// Tell the backend to render to the current render target
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex]);
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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:
|
private:
|
||||||
nxtDevice backendDevice = nullptr;
|
nxtDevice backendDevice = nullptr;
|
||||||
|
nxtSwapChainImplementation swapchainImpl = {};
|
||||||
static constexpr unsigned int kFrameCount = 2;
|
nxtProcTable procTable = {};
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
ComPtr<IDXGIFactory4> factory;
|
ComPtr<IDXGIFactory4> factory;
|
||||||
ComPtr<IDXGIAdapter1> hardwareAdapter;
|
ComPtr<IDXGIAdapter1> hardwareAdapter;
|
||||||
ComPtr<ID3D12Device> d3d12Device;
|
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) {
|
static bool GetHardwareAdapter(IDXGIFactory4* factory, IDXGIAdapter1** hardwareAdapter) {
|
||||||
*hardwareAdapter = nullptr;
|
*hardwareAdapter = nullptr;
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
|
|
||||||
#include "utils/BackendBinding.h"
|
#include "utils/BackendBinding.h"
|
||||||
|
|
||||||
|
#include "common/Assert.h"
|
||||||
|
#include "nxt/nxt_wsi.h"
|
||||||
|
#include "utils/SwapChainImpl.h"
|
||||||
|
|
||||||
#define GLFW_EXPOSE_NATIVE_COCOA
|
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
#include "GLFW/glfw3native.h"
|
#include "GLFW/glfw3native.h"
|
||||||
|
@ -30,6 +34,103 @@ namespace metal {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace utils {
|
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 {
|
class MetalBinding : public BackendBinding {
|
||||||
public:
|
public:
|
||||||
|
@ -39,40 +140,21 @@ namespace utils {
|
||||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||||
metalDevice = MTLCreateSystemDefaultDevice();
|
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);
|
backend::metal::Init(metalDevice, procs, device);
|
||||||
backendDevice = *device;
|
backendDevice = *device;
|
||||||
|
|
||||||
backend::metal::SetNextDrawable(backendDevice, GetNextDrawable());
|
|
||||||
}
|
}
|
||||||
void SwapBuffers() override {
|
|
||||||
backend::metal::Present(backendDevice);
|
uint64_t GetSwapChainImplementation() override {
|
||||||
backend::metal::SetNextDrawable(backendDevice, GetNextDrawable());
|
if (swapchainImpl.userData == nullptr) {
|
||||||
|
swapchainImpl = SwapChainImplMTL::Create(glfwGetCocoaWindow(window));
|
||||||
|
}
|
||||||
|
return reinterpret_cast<uint64_t>(&swapchainImpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
id<CAMetalDrawable> GetNextDrawable() {
|
|
||||||
lastDrawable = [layer nextDrawable];
|
|
||||||
return lastDrawable;
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLDevice> metalDevice = nil;
|
id<MTLDevice> metalDevice = nil;
|
||||||
CAMetalLayer* layer = nullptr;
|
|
||||||
|
|
||||||
id<CAMetalDrawable> lastDrawable = nil;
|
|
||||||
|
|
||||||
nxtDevice backendDevice = nullptr;
|
nxtDevice backendDevice = nullptr;
|
||||||
|
nxtSwapChainImplementation swapchainImpl = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
BackendBinding* CreateMetalBinding() {
|
BackendBinding* CreateMetalBinding() {
|
||||||
|
|
|
@ -92,34 +92,6 @@ namespace utils {
|
||||||
return builder.GetResult();
|
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 CreateFrozenBufferFromData(const nxt::Device& device, const void* data, uint32_t size, nxt::BufferUsageBit usage) {
|
||||||
nxt::Buffer buffer = device.CreateBufferBuilder()
|
nxt::Buffer buffer = device.CreateBufferBuilder()
|
||||||
.SetAllowedUsage(nxt::BufferUsageBit::TransferDst | usage)
|
.SetAllowedUsage(nxt::BufferUsageBit::TransferDst | usage)
|
||||||
|
|
|
@ -18,7 +18,6 @@ namespace utils {
|
||||||
|
|
||||||
void FillShaderModuleBuilder(const nxt::ShaderModuleBuilder& builder, nxt::ShaderStage stage, const char* source);
|
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);
|
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);
|
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 {
|
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||||
backend::null::Init(procs, device);
|
backend::null::Init(procs, device);
|
||||||
}
|
}
|
||||||
void SwapBuffers() override {
|
uint64_t GetSwapChainImplementation() override {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,20 +14,104 @@
|
||||||
|
|
||||||
#include "utils/BackendBinding.h"
|
#include "utils/BackendBinding.h"
|
||||||
|
|
||||||
|
#include "common/Assert.h"
|
||||||
#include "common/Platform.h"
|
#include "common/Platform.h"
|
||||||
|
#include "nxt/nxt_wsi.h"
|
||||||
|
#include "utils/SwapChainImpl.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include "glad/glad.h"
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
namespace backend {
|
namespace backend {
|
||||||
namespace opengl {
|
namespace opengl {
|
||||||
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
|
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
|
||||||
void HACKCLEAR(nxtDevice device);
|
|
||||||
void InitBackbuffer(nxtDevice device);
|
|
||||||
void CommitBackbuffer(nxtDevice device);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace utils {
|
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 {
|
class OpenGLBinding : public BackendBinding {
|
||||||
public:
|
public:
|
||||||
void SetupGLFWWindowHints() override {
|
void SetupGLFWWindowHints() override {
|
||||||
|
@ -48,16 +132,18 @@ namespace utils {
|
||||||
backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
|
backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
|
||||||
|
|
||||||
backendDevice = *device;
|
backendDevice = *device;
|
||||||
backend::opengl::InitBackbuffer(backendDevice);
|
|
||||||
}
|
}
|
||||||
void SwapBuffers() override {
|
|
||||||
backend::opengl::CommitBackbuffer(backendDevice);
|
uint64_t GetSwapChainImplementation() override {
|
||||||
glfwSwapBuffers(window);
|
if (swapchainImpl.userData == nullptr) {
|
||||||
backend::opengl::HACKCLEAR(backendDevice);
|
swapchainImpl = SwapChainImplGL::Create(window);
|
||||||
|
}
|
||||||
|
return reinterpret_cast<uint64_t>(&swapchainImpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nxtDevice backendDevice = nullptr;
|
nxtDevice backendDevice = nullptr;
|
||||||
|
nxtSwapChainImplementation swapchainImpl = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
BackendBinding* CreateOpenGLBinding() {
|
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