Split BackendBinding from example/Utils into src/utils
This will make it possible to reuse the backend bindings for test suites
This commit is contained in:
parent
931e6e82fd
commit
1bd219d8a8
|
@ -79,6 +79,7 @@ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
|||
|
||||
add_subdirectory(src/backend)
|
||||
add_subdirectory(src/wire)
|
||||
add_subdirectory(src/utils)
|
||||
add_subdirectory(src/tests)
|
||||
|
||||
add_subdirectory(examples)
|
||||
|
|
|
@ -12,67 +12,52 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
list(APPEND UTILS_SOURCES
|
||||
Utils.h
|
||||
add_library(sample_utils
|
||||
Utils.cpp
|
||||
BackendBinding.h
|
||||
Utils.h
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND UTILS_SOURCES
|
||||
MetalBinding.mm
|
||||
)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND UTILS_SOURCES
|
||||
D3D12Binding.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(utils STATIC ${UTILS_SOURCES})
|
||||
target_link_libraries(utils nxt_backend nxt_wire shaderc nxtcpp nxt)
|
||||
SetCXX14(utils)
|
||||
target_link_libraries(sample_utils utils nxt_wire)
|
||||
SetCXX14(sample_utils)
|
||||
|
||||
add_executable(CHelloTriangle CHelloTriangle.cpp)
|
||||
target_link_libraries(CHelloTriangle utils)
|
||||
target_link_libraries(CHelloTriangle sample_utils)
|
||||
SetCXX14(CHelloTriangle)
|
||||
|
||||
add_executable(CppHelloTriangle HelloTriangle.cpp)
|
||||
target_link_libraries(CppHelloTriangle utils)
|
||||
target_link_libraries(CppHelloTriangle sample_utils)
|
||||
SetCXX14(CppHelloTriangle)
|
||||
|
||||
add_executable(ComputeBoids ComputeBoids.cpp)
|
||||
target_link_libraries(ComputeBoids utils)
|
||||
target_link_libraries(ComputeBoids sample_utils)
|
||||
target_include_directories(ComputeBoids PUBLIC ../ ${GLM_INCLUDE_DIR})
|
||||
SetCXX14(ComputeBoids)
|
||||
|
||||
add_executable(HelloVertices HelloVertices.cpp)
|
||||
target_link_libraries(HelloVertices utils)
|
||||
target_link_libraries(HelloVertices sample_utils)
|
||||
SetCXX14(HelloVertices)
|
||||
|
||||
add_executable(HelloInstancing HelloInstancing.cpp)
|
||||
target_link_libraries(HelloInstancing utils)
|
||||
target_link_libraries(HelloInstancing sample_utils)
|
||||
SetCXX14(HelloInstancing)
|
||||
|
||||
add_executable(HelloIndices HelloIndices.cpp)
|
||||
target_link_libraries(HelloIndices utils)
|
||||
target_link_libraries(HelloIndices sample_utils)
|
||||
SetCXX14(HelloIndices)
|
||||
|
||||
add_executable(HelloUBO HelloUBO.cpp)
|
||||
target_link_libraries(HelloUBO utils)
|
||||
target_link_libraries(HelloUBO sample_utils)
|
||||
SetCXX14(HelloUBO)
|
||||
|
||||
add_executable(HelloCompute HelloCompute.cpp)
|
||||
target_link_libraries(HelloCompute utils)
|
||||
target_link_libraries(HelloCompute sample_utils)
|
||||
SetCXX14(HelloCompute)
|
||||
|
||||
add_executable(RenderToTexture RenderToTexture.cpp)
|
||||
target_link_libraries(RenderToTexture utils)
|
||||
target_link_libraries(RenderToTexture sample_utils)
|
||||
SetCXX14(RenderToTexture)
|
||||
|
||||
add_executable(Animometer Animometer.cpp)
|
||||
target_link_libraries(Animometer utils)
|
||||
target_link_libraries(Animometer sample_utils)
|
||||
SetCXX14(Animometer)
|
||||
|
||||
add_executable(SpirvTest SpirvTest.cpp)
|
||||
|
@ -80,7 +65,7 @@ target_link_libraries(SpirvTest shaderc spirv-cross nxtcpp)
|
|||
SetCXX14(SpirvTest)
|
||||
|
||||
add_executable(CppHelloDepthStencil HelloDepthStencil.cpp)
|
||||
target_link_libraries(CppHelloDepthStencil utils)
|
||||
target_link_libraries(CppHelloDepthStencil sample_utils)
|
||||
SetCXX14(CppHelloDepthStencil)
|
||||
|
||||
add_subdirectory(glTFViewer)
|
||||
|
|
|
@ -1,254 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#include "BackendBinding.h"
|
||||
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "GLFW/glfw3native.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <assert.h>
|
||||
#include <wrl.h>
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_4.h>
|
||||
|
||||
#define ASSERT assert
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
namespace backend {
|
||||
namespace d3d12 {
|
||||
void Init(ComPtr<ID3D12Device> d3d12Device, nxtProcTable* procs, nxtDevice* device);
|
||||
ComPtr<ID3D12CommandQueue> GetCommandQueue(nxtDevice device);
|
||||
void SetNextRenderTargetDescriptor(nxtDevice device, D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor);
|
||||
uint64_t GetSerial(const nxtDevice device);
|
||||
void NextSerial(nxtDevice device);
|
||||
void ExecuteCommandLists(nxtDevice device, std::initializer_list<ID3D12CommandList*> commandLists);
|
||||
void WaitForSerial(nxtDevice device, uint64_t serial);
|
||||
void OpenCommandList(nxtDevice device, ComPtr<ID3D12GraphicsCommandList>* commandList);
|
||||
}
|
||||
}
|
||||
|
||||
class D3D12Binding : public BackendBinding {
|
||||
public:
|
||||
void SetupGLFWWindowHints() override {
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
}
|
||||
|
||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
uint32_t dxgiFactoryFlags = 0;
|
||||
#ifdef _DEBUG
|
||||
// Enable the debug layer (requires the Graphics Tools "optional feature").
|
||||
// NOTE: Enabling the debug layer after device creation will invalidate the active device.
|
||||
{
|
||||
ComPtr<ID3D12Debug> debugController;
|
||||
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
|
||||
{
|
||||
debugController->EnableDebugLayer();
|
||||
|
||||
// Enable additional debug layers.
|
||||
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ASSERT_SUCCESS(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)));
|
||||
ASSERT(GetHardwareAdapter(factory.Get(), &hardwareAdapter));
|
||||
ASSERT_SUCCESS(D3D12CreateDevice(
|
||||
hardwareAdapter.Get(),
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
IID_PPV_ARGS(&d3d12Device)
|
||||
));
|
||||
|
||||
backend::d3d12::Init(d3d12Device, procs, device);
|
||||
backendDevice = *device;
|
||||
commandQueue = backend::d3d12::GetCommandQueue(backendDevice);
|
||||
|
||||
int width, height;
|
||||
glfwGetWindowSize(window, &width, &height);
|
||||
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
|
||||
swapChainDesc.Width = width;
|
||||
swapChainDesc.Height = height;
|
||||
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapChainDesc.BufferCount = kFrameCount;
|
||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
swapChainDesc.SampleDesc.Count = 1;
|
||||
|
||||
HWND win32Window = glfwGetWin32Window(window);
|
||||
ComPtr<IDXGISwapChain1> swapChain1;
|
||||
ASSERT_SUCCESS(factory->CreateSwapChainForHwnd(
|
||||
commandQueue.Get(),
|
||||
win32Window,
|
||||
&swapChainDesc,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&swapChain1
|
||||
));
|
||||
ASSERT_SUCCESS(swapChain1.As(&swapChain));
|
||||
|
||||
// Describe and create a render target view (RTV) descriptor heap.
|
||||
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
|
||||
rtvHeapDesc.NumDescriptors = kFrameCount;
|
||||
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||
ASSERT_SUCCESS(d3d12Device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&renderTargetViewHeap)));
|
||||
|
||||
rtvDescriptorSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
|
||||
// Create a RTV for each frame.
|
||||
{
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle = renderTargetViewHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
for (uint32_t n = 0; n < kFrameCount; ++n) {
|
||||
ASSERT_SUCCESS(swapChain->GetBuffer(n, IID_PPV_ARGS(&renderTargetResources[n])));
|
||||
d3d12Device->CreateRenderTargetView(renderTargetResources[n].Get(), nullptr, renderTargetViewHandle);
|
||||
renderTargetViewHandle.ptr += rtvDescriptorSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the initial render target and arbitrarily choose a "previous" render target that's different
|
||||
previousRenderTargetIndex = renderTargetIndex = swapChain->GetCurrentBackBufferIndex();
|
||||
previousRenderTargetIndex = renderTargetIndex == 0 ? 1 : 0;
|
||||
|
||||
// Initial the serial for all render targets
|
||||
const uint64_t initialSerial = backend::d3d12::GetSerial(backendDevice);
|
||||
for (uint32_t n = 0; n < kFrameCount; ++n) {
|
||||
lastSerialRenderTargetWasUsed[n] = initialSerial;
|
||||
}
|
||||
|
||||
// Transition the first frame to be a render target
|
||||
{
|
||||
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
||||
|
||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
||||
resourceBarrier.Transition.pResource = renderTargetResources[renderTargetIndex].Get();
|
||||
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
resourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
resourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
commandList->ResourceBarrier(1, &resourceBarrier);
|
||||
ASSERT_SUCCESS(commandList->Close());
|
||||
ID3D12CommandList* commandLists[] = { commandList.Get() };
|
||||
backend::d3d12::ExecuteCommandLists(backendDevice, { commandList.Get() });
|
||||
|
||||
backend::d3d12::NextSerial(backendDevice);
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle = renderTargetViewHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
renderTargetViewHandle.ptr += rtvDescriptorSize * renderTargetIndex;
|
||||
backend::d3d12::SetNextRenderTargetDescriptor(backendDevice, renderTargetViewHandle);
|
||||
}
|
||||
|
||||
void SwapBuffers() override {
|
||||
// Transition current frame's render target for presenting
|
||||
{
|
||||
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
||||
resourceBarrier.Transition.pResource = renderTargetResources[renderTargetIndex].Get();
|
||||
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
resourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
resourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
commandList->ResourceBarrier(1, &resourceBarrier);
|
||||
ASSERT_SUCCESS(commandList->Close());
|
||||
ID3D12CommandList* commandLists[] = { commandList.Get() };
|
||||
backend::d3d12::ExecuteCommandLists(backendDevice, { commandList.Get() });
|
||||
}
|
||||
|
||||
ASSERT_SUCCESS(swapChain->Present(1, 0));
|
||||
|
||||
// Transition last frame's render target back to being a render target
|
||||
{
|
||||
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
||||
resourceBarrier.Transition.pResource = renderTargetResources[previousRenderTargetIndex].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());
|
||||
ID3D12CommandList* commandLists[] = { commandList.Get() };
|
||||
backend::d3d12::ExecuteCommandLists(backendDevice, { commandList.Get() });
|
||||
}
|
||||
|
||||
backend::d3d12::NextSerial(backendDevice);
|
||||
|
||||
previousRenderTargetIndex = renderTargetIndex;
|
||||
renderTargetIndex = swapChain->GetCurrentBackBufferIndex();
|
||||
|
||||
// If the next render target is not ready to be rendered yet, wait until it is ready.
|
||||
// If the last completed serial is less than the last requested serial for this render target,
|
||||
// then the commands previously executed on this render target have not yet completed
|
||||
backend::d3d12::WaitForSerial(backendDevice, lastSerialRenderTargetWasUsed[renderTargetIndex]);
|
||||
|
||||
lastSerialRenderTargetWasUsed[renderTargetIndex] = backend::d3d12::GetSerial(backendDevice);
|
||||
|
||||
// Tell the backend to render to the current render target
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle = renderTargetViewHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
renderTargetViewHandle.ptr += rtvDescriptorSize * renderTargetIndex;
|
||||
backend::d3d12::SetNextRenderTargetDescriptor(backendDevice, renderTargetViewHandle);
|
||||
}
|
||||
|
||||
private:
|
||||
nxtDevice backendDevice = nullptr;
|
||||
|
||||
static constexpr unsigned int kFrameCount = 2;
|
||||
|
||||
// Initialization
|
||||
ComPtr<IDXGIFactory4> factory;
|
||||
ComPtr<IDXGIAdapter1> hardwareAdapter;
|
||||
ComPtr<ID3D12Device> d3d12Device;
|
||||
ComPtr<ID3D12CommandQueue> commandQueue;
|
||||
ComPtr<IDXGISwapChain3> swapChain;
|
||||
ComPtr<ID3D12DescriptorHeap> renderTargetViewHeap;
|
||||
ComPtr<ID3D12Resource> renderTargetResources[kFrameCount];
|
||||
uint32_t rtvDescriptorSize;
|
||||
|
||||
// Frame synchronization. Updated every frame
|
||||
uint32_t renderTargetIndex;
|
||||
uint32_t previousRenderTargetIndex;
|
||||
uint64_t lastSerialRenderTargetWasUsed[kFrameCount];
|
||||
ComPtr<ID3D12GraphicsCommandList> commandList;
|
||||
|
||||
static void ASSERT_SUCCESS(HRESULT hr) {
|
||||
assert(SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
static bool GetHardwareAdapter(IDXGIFactory4* factory, IDXGIAdapter1** hardwareAdapter) {
|
||||
*hardwareAdapter = nullptr;
|
||||
for (uint32_t adapterIndex = 0; ; ++adapterIndex) {
|
||||
IDXGIAdapter1* adapter = nullptr;
|
||||
if (factory->EnumAdapters1(adapterIndex, &adapter) == DXGI_ERROR_NOT_FOUND) {
|
||||
break; // No more adapters to enumerate.
|
||||
}
|
||||
|
||||
// Check to see if the adapter supports Direct3D 12, but don't create the actual device yet.
|
||||
if (SUCCEEDED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) {
|
||||
*hardwareAdapter = adapter;
|
||||
return true;
|
||||
}
|
||||
adapter->Release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
BackendBinding* CreateD3D12Binding() {
|
||||
return new D3D12Binding;
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#include "BackendBinding.h"
|
||||
|
||||
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "GLFW/glfw3native.h"
|
||||
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
namespace backend {
|
||||
namespace metal {
|
||||
void Init(id<MTLDevice> metalDevice, nxtProcTable* procs, nxtDevice* device);
|
||||
void SetNextDrawable(nxtDevice device, id<CAMetalDrawable> drawable);
|
||||
void Present(nxtDevice device);
|
||||
}
|
||||
}
|
||||
|
||||
class MetalBinding : public BackendBinding {
|
||||
public:
|
||||
void SetupGLFWWindowHints() override {
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
}
|
||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
metalDevice = MTLCreateSystemDefaultDevice();
|
||||
|
||||
id nsWindow = glfwGetCocoaWindow(window);
|
||||
NSView* contentView = [nsWindow contentView];
|
||||
[contentView setWantsLayer: YES];
|
||||
|
||||
layer = [CAMetalLayer layer];
|
||||
[layer setDevice: metalDevice];
|
||||
[layer setPixelFormat: MTLPixelFormatBGRA8Unorm];
|
||||
[layer setFramebufferOnly: YES];
|
||||
[layer setDrawableSize: [contentView bounds].size];
|
||||
|
||||
[contentView setLayer: layer];
|
||||
|
||||
backend::metal::Init(metalDevice, procs, device);
|
||||
backendDevice = *device;
|
||||
|
||||
backend::metal::SetNextDrawable(backendDevice, GetNextDrawable());
|
||||
}
|
||||
void SwapBuffers() override {
|
||||
backend::metal::Present(backendDevice);
|
||||
backend::metal::SetNextDrawable(backendDevice, GetNextDrawable());
|
||||
}
|
||||
|
||||
private:
|
||||
id<CAMetalDrawable> GetNextDrawable() {
|
||||
lastDrawable = [layer nextDrawable];
|
||||
return lastDrawable;
|
||||
}
|
||||
|
||||
id<MTLDevice> metalDevice = nil;
|
||||
CAMetalLayer* layer = nullptr;
|
||||
|
||||
id<CAMetalDrawable> lastDrawable = nil;
|
||||
|
||||
nxtDevice backendDevice = nullptr;
|
||||
};
|
||||
|
||||
BackendBinding* CreateMetalBinding() {
|
||||
return new MetalBinding;
|
||||
}
|
|
@ -12,14 +12,14 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "utils/BackendBinding.h"
|
||||
#include "../src/wire/TerribleCommandBuffer.h"
|
||||
|
||||
#include <nxt/nxt.h>
|
||||
#include <nxt/nxtcpp.h>
|
||||
#include <shaderc/shaderc.hpp>
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
#include "BackendBinding.h"
|
||||
#include "../src/wire/TerribleCommandBuffer.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
@ -31,69 +31,10 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
BackendBinding* CreateMetalBinding();
|
||||
BackendBinding* CreateD3D12Binding();
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
|
||||
void HACKCLEAR();
|
||||
}
|
||||
}
|
||||
|
||||
class OpenGLBinding : public BackendBinding {
|
||||
public:
|
||||
void SetupGLFWWindowHints() override {
|
||||
#ifdef __APPLE__
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
#else
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
#endif
|
||||
}
|
||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
glfwMakeContextCurrent(window);
|
||||
backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
|
||||
}
|
||||
void SwapBuffers() override {
|
||||
glfwSwapBuffers(window);
|
||||
backend::opengl::HACKCLEAR();
|
||||
}
|
||||
};
|
||||
|
||||
namespace backend {
|
||||
namespace null {
|
||||
void Init(nxtProcTable* procs, nxtDevice* device);
|
||||
}
|
||||
}
|
||||
|
||||
class NullBinding : public BackendBinding {
|
||||
public:
|
||||
void SetupGLFWWindowHints() override {
|
||||
}
|
||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
backend::null::Init(procs, device);
|
||||
}
|
||||
void SwapBuffers() override {
|
||||
}
|
||||
};
|
||||
|
||||
void PrintDeviceError(const char* message, nxt::CallbackUserdata) {
|
||||
std::cout << "Device error: " << message << std::endl;
|
||||
}
|
||||
|
||||
enum class BackendType {
|
||||
OpenGL,
|
||||
Metal,
|
||||
D3D12,
|
||||
Null,
|
||||
};
|
||||
|
||||
enum class CmdBufType {
|
||||
None,
|
||||
Terrible,
|
||||
|
@ -101,15 +42,15 @@ enum class CmdBufType {
|
|||
};
|
||||
|
||||
#if defined(__APPLE__)
|
||||
static BackendType backendType = BackendType::Metal;
|
||||
static utils::BackendType backendType = utils::BackendType::Metal;
|
||||
#elif defined(_WIN32)
|
||||
static BackendType backendType = BackendType::D3D12;
|
||||
static utils::BackendType backendType = utils::BackendType::D3D12;
|
||||
#else
|
||||
static BackendType backendType = BackendType::OpenGL;
|
||||
static utils::BackendType backendType = utils::BackendType::OpenGL;
|
||||
#endif
|
||||
|
||||
static CmdBufType cmdBufType = CmdBufType::Terrible;
|
||||
static BackendBinding* binding = nullptr;
|
||||
static utils::BackendBinding* binding = nullptr;
|
||||
|
||||
static GLFWwindow* window = nullptr;
|
||||
|
||||
|
@ -119,27 +60,9 @@ static nxt::wire::TerribleCommandBuffer* c2sBuf = nullptr;
|
|||
static nxt::wire::TerribleCommandBuffer* s2cBuf = nullptr;
|
||||
|
||||
nxt::Device CreateCppNXTDevice() {
|
||||
switch (backendType) {
|
||||
case BackendType::OpenGL:
|
||||
binding = new OpenGLBinding;
|
||||
break;
|
||||
case BackendType::Metal:
|
||||
#if defined(__APPLE__)
|
||||
binding = CreateMetalBinding();
|
||||
#else
|
||||
fprintf(stderr, "Metal backend not present on this platform\n");
|
||||
#endif
|
||||
break;
|
||||
case BackendType::D3D12:
|
||||
#if defined(_WIN32)
|
||||
binding = CreateD3D12Binding();
|
||||
#else
|
||||
fprintf(stderr, "D3D12 backend not present on this platform\n");
|
||||
#endif
|
||||
break;
|
||||
case BackendType::Null:
|
||||
binding = new NullBinding;
|
||||
break;
|
||||
binding = utils::CreateBinding(backendType);
|
||||
if (binding == nullptr) {
|
||||
return nxt::Device();
|
||||
}
|
||||
|
||||
if (!glfwInit()) {
|
||||
|
@ -275,23 +198,27 @@ bool InitUtils(int argc, const char** argv) {
|
|||
for (int i = 0; i < argc; i++) {
|
||||
if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) {
|
||||
i++;
|
||||
if (i < argc && std::string("opengl") == argv[i]) {
|
||||
backendType = BackendType::OpenGL;
|
||||
if (i < argc && std::string("d3d12") == argv[i]) {
|
||||
backendType = utils::BackendType::D3D12;
|
||||
continue;
|
||||
}
|
||||
if (i < argc && std::string("metal") == argv[i]) {
|
||||
backendType = BackendType::Metal;
|
||||
continue;
|
||||
}
|
||||
if (i < argc && std::string("d3d12") == argv[i]) {
|
||||
backendType = BackendType::D3D12;
|
||||
backendType = utils::BackendType::Metal;
|
||||
continue;
|
||||
}
|
||||
if (i < argc && std::string("null") == argv[i]) {
|
||||
backendType = BackendType::Null;
|
||||
backendType = utils::BackendType::Null;
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "--backend expects a backend name (opengl, metal, d3d12, null)\n");
|
||||
if (i < argc && std::string("opengl") == argv[i]) {
|
||||
backendType = utils::BackendType::OpenGL;
|
||||
continue;
|
||||
}
|
||||
if (i < argc && std::string("vulkan") == argv[i]) {
|
||||
backendType = utils::BackendType::Vulkan;
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "--backend expects a backend name (opengl, metal, d3d12, null, vulkan)\n");
|
||||
return false;
|
||||
}
|
||||
if (std::string("-c") == argv[i] || std::string("--comand-buffer") == argv[i]) {
|
||||
|
@ -309,7 +236,7 @@ bool InitUtils(int argc, const char** argv) {
|
|||
}
|
||||
if (std::string("-h") == argv[i] || std::string("--help") == argv[i]) {
|
||||
printf("Usage: %s [-b BACKEND] [-c COMMAND_BUFFER]\n", argv[0]);
|
||||
printf(" BACKEND is one of: opengl, metal, d3d12, null\n");
|
||||
printf(" BACKEND is one of: d3d12, metal, null, opengl, vulkan\n");
|
||||
printf(" COMMAND_BUFFER is one of: none, terrible\n");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,6 @@
|
|||
# limitations under the License.
|
||||
|
||||
add_executable(glTFViewer glTFViewer.cpp)
|
||||
target_link_libraries(glTFViewer utils)
|
||||
target_link_libraries(glTFViewer sample_utils)
|
||||
target_include_directories(glTFViewer PUBLIC ../ ${GLM_INCLUDE_DIR})
|
||||
SetCXX14(glTFViewer)
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
// 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.
|
||||
|
||||
#include "BackendBinding.h"
|
||||
|
||||
namespace utils {
|
||||
|
||||
BackendBinding* CreateD3D12Binding();
|
||||
BackendBinding* CreateMetalBinding();
|
||||
BackendBinding* CreateOpenGLBinding();
|
||||
BackendBinding* CreateNullBinding();
|
||||
BackendBinding* CreateVulkanBinding();
|
||||
|
||||
void BackendBinding::SetWindow(GLFWwindow* window) {
|
||||
this->window = window;
|
||||
}
|
||||
|
||||
BackendBinding* CreateBinding(BackendType type) {
|
||||
switch (type) {
|
||||
case BackendType::D3D12:
|
||||
#if defined(_WIN32)
|
||||
return CreateD3D12Binding();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
case BackendType::OpenGL:
|
||||
return CreateOpenGLBinding();
|
||||
|
||||
case BackendType::Metal:
|
||||
#if defined(__APPLE__)
|
||||
return CreateMetalBinding();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
case BackendType::Null:
|
||||
return CreateNullBinding();
|
||||
|
||||
case BackendType::Vulkan:
|
||||
return nullptr; // TODO(cwallez@chromium.org) change it to CreateVulkanBinding();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -15,20 +15,33 @@
|
|||
#ifndef UTILS_BACKENDBINDING_H_
|
||||
#define UTILS_BACKENDBINDING_H_
|
||||
|
||||
#include <nxt/nxt.h>
|
||||
|
||||
struct GLFWwindow;
|
||||
typedef struct nxtProcTable_s nxtProcTable;
|
||||
typedef struct nxtDeviceImpl* nxtDevice;
|
||||
|
||||
class BackendBinding {
|
||||
public:
|
||||
virtual void SetupGLFWWindowHints() = 0;
|
||||
virtual void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) = 0;
|
||||
virtual void SwapBuffers() = 0;
|
||||
namespace utils {
|
||||
|
||||
void SetWindow(GLFWwindow* window) {this->window = window;}
|
||||
enum class BackendType {
|
||||
D3D12,
|
||||
Metal,
|
||||
OpenGL,
|
||||
Null,
|
||||
Vulkan,
|
||||
};
|
||||
|
||||
protected:
|
||||
GLFWwindow* window = nullptr;
|
||||
};
|
||||
class BackendBinding {
|
||||
public:
|
||||
virtual void SetupGLFWWindowHints() = 0;
|
||||
virtual void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) = 0;
|
||||
virtual void SwapBuffers() = 0;
|
||||
|
||||
void SetWindow(GLFWwindow* window);
|
||||
|
||||
protected:
|
||||
GLFWwindow* window = nullptr;
|
||||
};
|
||||
|
||||
BackendBinding* CreateBinding(BackendType type);
|
||||
}
|
||||
|
||||
#endif // UTILS_BACKENDBINDING_H_
|
|
@ -0,0 +1,39 @@
|
|||
# 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.
|
||||
|
||||
set(UTILS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
list(APPEND UTILS_SOURCES
|
||||
${UTILS_DIR}/BackendBinding.cpp
|
||||
${UTILS_DIR}/BackendBinding.h
|
||||
${UTILS_DIR}/NullBinding.cpp
|
||||
${UTILS_DIR}/OpenGLBinding.cpp
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND UTILS_SOURCES
|
||||
${UTILS_DIR}/MetalBinding.mm
|
||||
)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND UTILS_SOURCES
|
||||
${UTILS_DIR}/D3D12Binding.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(utils STATIC ${UTILS_SOURCES})
|
||||
target_link_libraries(utils nxt_backend shaderc nxtcpp nxt)
|
||||
target_include_directories(utils PUBLIC ${SRC_DIR})
|
||||
SetCXX14(utils)
|
|
@ -0,0 +1,257 @@
|
|||
// 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.
|
||||
|
||||
#include "BackendBinding.h"
|
||||
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "GLFW/glfw3native.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <wrl.h>
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_4.h>
|
||||
|
||||
#define ASSERT assert
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
namespace backend {
|
||||
namespace d3d12 {
|
||||
void Init(ComPtr<ID3D12Device> d3d12Device, nxtProcTable* procs, nxtDevice* device);
|
||||
ComPtr<ID3D12CommandQueue> GetCommandQueue(nxtDevice device);
|
||||
void SetNextRenderTargetDescriptor(nxtDevice device, D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor);
|
||||
uint64_t GetSerial(const nxtDevice device);
|
||||
void NextSerial(nxtDevice device);
|
||||
void ExecuteCommandLists(nxtDevice device, std::initializer_list<ID3D12CommandList*> commandLists);
|
||||
void WaitForSerial(nxtDevice device, uint64_t serial);
|
||||
void OpenCommandList(nxtDevice device, ComPtr<ID3D12GraphicsCommandList>* commandList);
|
||||
}
|
||||
}
|
||||
|
||||
namespace utils {
|
||||
|
||||
class D3D12Binding : public BackendBinding {
|
||||
public:
|
||||
void SetupGLFWWindowHints() override {
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
}
|
||||
|
||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
uint32_t dxgiFactoryFlags = 0;
|
||||
#ifdef _DEBUG
|
||||
// Enable the debug layer (requires the Graphics Tools "optional feature").
|
||||
// NOTE: Enabling the debug layer after device creation will invalidate the active device.
|
||||
{
|
||||
ComPtr<ID3D12Debug> debugController;
|
||||
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
|
||||
{
|
||||
debugController->EnableDebugLayer();
|
||||
|
||||
// Enable additional debug layers.
|
||||
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ASSERT_SUCCESS(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)));
|
||||
ASSERT(GetHardwareAdapter(factory.Get(), &hardwareAdapter));
|
||||
ASSERT_SUCCESS(D3D12CreateDevice(
|
||||
hardwareAdapter.Get(),
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
IID_PPV_ARGS(&d3d12Device)
|
||||
));
|
||||
|
||||
backend::d3d12::Init(d3d12Device, procs, device);
|
||||
backendDevice = *device;
|
||||
commandQueue = backend::d3d12::GetCommandQueue(backendDevice);
|
||||
|
||||
int width, height;
|
||||
glfwGetWindowSize(window, &width, &height);
|
||||
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
|
||||
swapChainDesc.Width = width;
|
||||
swapChainDesc.Height = height;
|
||||
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapChainDesc.BufferCount = kFrameCount;
|
||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
swapChainDesc.SampleDesc.Count = 1;
|
||||
|
||||
HWND win32Window = glfwGetWin32Window(window);
|
||||
ComPtr<IDXGISwapChain1> swapChain1;
|
||||
ASSERT_SUCCESS(factory->CreateSwapChainForHwnd(
|
||||
commandQueue.Get(),
|
||||
win32Window,
|
||||
&swapChainDesc,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&swapChain1
|
||||
));
|
||||
ASSERT_SUCCESS(swapChain1.As(&swapChain));
|
||||
|
||||
// Describe and create a render target view (RTV) descriptor heap.
|
||||
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
|
||||
rtvHeapDesc.NumDescriptors = kFrameCount;
|
||||
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||
ASSERT_SUCCESS(d3d12Device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&renderTargetViewHeap)));
|
||||
|
||||
rtvDescriptorSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
|
||||
// Create a RTV for each frame.
|
||||
{
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle = renderTargetViewHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
for (uint32_t n = 0; n < kFrameCount; ++n) {
|
||||
ASSERT_SUCCESS(swapChain->GetBuffer(n, IID_PPV_ARGS(&renderTargetResources[n])));
|
||||
d3d12Device->CreateRenderTargetView(renderTargetResources[n].Get(), nullptr, renderTargetViewHandle);
|
||||
renderTargetViewHandle.ptr += rtvDescriptorSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the initial render target and arbitrarily choose a "previous" render target that's different
|
||||
previousRenderTargetIndex = renderTargetIndex = swapChain->GetCurrentBackBufferIndex();
|
||||
previousRenderTargetIndex = renderTargetIndex == 0 ? 1 : 0;
|
||||
|
||||
// Initial the serial for all render targets
|
||||
const uint64_t initialSerial = backend::d3d12::GetSerial(backendDevice);
|
||||
for (uint32_t n = 0; n < kFrameCount; ++n) {
|
||||
lastSerialRenderTargetWasUsed[n] = initialSerial;
|
||||
}
|
||||
|
||||
// Transition the first frame to be a render target
|
||||
{
|
||||
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
||||
|
||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
||||
resourceBarrier.Transition.pResource = renderTargetResources[renderTargetIndex].Get();
|
||||
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
resourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
resourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
commandList->ResourceBarrier(1, &resourceBarrier);
|
||||
ASSERT_SUCCESS(commandList->Close());
|
||||
ID3D12CommandList* commandLists[] = { commandList.Get() };
|
||||
backend::d3d12::ExecuteCommandLists(backendDevice, { commandList.Get() });
|
||||
|
||||
backend::d3d12::NextSerial(backendDevice);
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle = renderTargetViewHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
renderTargetViewHandle.ptr += rtvDescriptorSize * renderTargetIndex;
|
||||
backend::d3d12::SetNextRenderTargetDescriptor(backendDevice, renderTargetViewHandle);
|
||||
}
|
||||
|
||||
void SwapBuffers() override {
|
||||
// Transition current frame's render target for presenting
|
||||
{
|
||||
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
||||
resourceBarrier.Transition.pResource = renderTargetResources[renderTargetIndex].Get();
|
||||
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
resourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
resourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
commandList->ResourceBarrier(1, &resourceBarrier);
|
||||
ASSERT_SUCCESS(commandList->Close());
|
||||
ID3D12CommandList* commandLists[] = { commandList.Get() };
|
||||
backend::d3d12::ExecuteCommandLists(backendDevice, { commandList.Get() });
|
||||
}
|
||||
|
||||
ASSERT_SUCCESS(swapChain->Present(1, 0));
|
||||
|
||||
// Transition last frame's render target back to being a render target
|
||||
{
|
||||
backend::d3d12::OpenCommandList(backendDevice, &commandList);
|
||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
||||
resourceBarrier.Transition.pResource = renderTargetResources[previousRenderTargetIndex].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());
|
||||
ID3D12CommandList* commandLists[] = { commandList.Get() };
|
||||
backend::d3d12::ExecuteCommandLists(backendDevice, { commandList.Get() });
|
||||
}
|
||||
|
||||
backend::d3d12::NextSerial(backendDevice);
|
||||
|
||||
previousRenderTargetIndex = renderTargetIndex;
|
||||
renderTargetIndex = swapChain->GetCurrentBackBufferIndex();
|
||||
|
||||
// If the next render target is not ready to be rendered yet, wait until it is ready.
|
||||
// If the last completed serial is less than the last requested serial for this render target,
|
||||
// then the commands previously executed on this render target have not yet completed
|
||||
backend::d3d12::WaitForSerial(backendDevice, lastSerialRenderTargetWasUsed[renderTargetIndex]);
|
||||
|
||||
lastSerialRenderTargetWasUsed[renderTargetIndex] = backend::d3d12::GetSerial(backendDevice);
|
||||
|
||||
// Tell the backend to render to the current render target
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle = renderTargetViewHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
renderTargetViewHandle.ptr += rtvDescriptorSize * renderTargetIndex;
|
||||
backend::d3d12::SetNextRenderTargetDescriptor(backendDevice, renderTargetViewHandle);
|
||||
}
|
||||
|
||||
private:
|
||||
nxtDevice backendDevice = nullptr;
|
||||
|
||||
static constexpr unsigned int kFrameCount = 2;
|
||||
|
||||
// Initialization
|
||||
ComPtr<IDXGIFactory4> factory;
|
||||
ComPtr<IDXGIAdapter1> hardwareAdapter;
|
||||
ComPtr<ID3D12Device> d3d12Device;
|
||||
ComPtr<ID3D12CommandQueue> commandQueue;
|
||||
ComPtr<IDXGISwapChain3> swapChain;
|
||||
ComPtr<ID3D12DescriptorHeap> renderTargetViewHeap;
|
||||
ComPtr<ID3D12Resource> renderTargetResources[kFrameCount];
|
||||
uint32_t rtvDescriptorSize;
|
||||
|
||||
// Frame synchronization. Updated every frame
|
||||
uint32_t renderTargetIndex;
|
||||
uint32_t previousRenderTargetIndex;
|
||||
uint64_t lastSerialRenderTargetWasUsed[kFrameCount];
|
||||
ComPtr<ID3D12GraphicsCommandList> commandList;
|
||||
|
||||
static void ASSERT_SUCCESS(HRESULT hr) {
|
||||
assert(SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
static bool GetHardwareAdapter(IDXGIFactory4* factory, IDXGIAdapter1** hardwareAdapter) {
|
||||
*hardwareAdapter = nullptr;
|
||||
for (uint32_t adapterIndex = 0; ; ++adapterIndex) {
|
||||
IDXGIAdapter1* adapter = nullptr;
|
||||
if (factory->EnumAdapters1(adapterIndex, &adapter) == DXGI_ERROR_NOT_FOUND) {
|
||||
break; // No more adapters to enumerate.
|
||||
}
|
||||
|
||||
// Check to see if the adapter supports Direct3D 12, but don't create the actual device yet.
|
||||
if (SUCCEEDED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) {
|
||||
*hardwareAdapter = adapter;
|
||||
return true;
|
||||
}
|
||||
adapter->Release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
BackendBinding* CreateD3D12Binding() {
|
||||
return new D3D12Binding;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// 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.
|
||||
|
||||
#include "BackendBinding.h"
|
||||
|
||||
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "GLFW/glfw3native.h"
|
||||
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
namespace backend {
|
||||
namespace metal {
|
||||
void Init(id<MTLDevice> metalDevice, nxtProcTable* procs, nxtDevice* device);
|
||||
void SetNextDrawable(nxtDevice device, id<CAMetalDrawable> drawable);
|
||||
void Present(nxtDevice device);
|
||||
}
|
||||
}
|
||||
|
||||
namespace utils {
|
||||
|
||||
class MetalBinding : public BackendBinding {
|
||||
public:
|
||||
void SetupGLFWWindowHints() override {
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
}
|
||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
metalDevice = MTLCreateSystemDefaultDevice();
|
||||
|
||||
id nsWindow = glfwGetCocoaWindow(window);
|
||||
NSView* contentView = [nsWindow contentView];
|
||||
[contentView setWantsLayer: YES];
|
||||
|
||||
layer = [CAMetalLayer layer];
|
||||
[layer setDevice: metalDevice];
|
||||
[layer setPixelFormat: MTLPixelFormatBGRA8Unorm];
|
||||
[layer setFramebufferOnly: YES];
|
||||
[layer setDrawableSize: [contentView bounds].size];
|
||||
|
||||
[contentView setLayer: layer];
|
||||
|
||||
backend::metal::Init(metalDevice, procs, device);
|
||||
backendDevice = *device;
|
||||
|
||||
backend::metal::SetNextDrawable(backendDevice, GetNextDrawable());
|
||||
}
|
||||
void SwapBuffers() override {
|
||||
backend::metal::Present(backendDevice);
|
||||
backend::metal::SetNextDrawable(backendDevice, GetNextDrawable());
|
||||
}
|
||||
|
||||
private:
|
||||
id<CAMetalDrawable> GetNextDrawable() {
|
||||
lastDrawable = [layer nextDrawable];
|
||||
return lastDrawable;
|
||||
}
|
||||
|
||||
id<MTLDevice> metalDevice = nil;
|
||||
CAMetalLayer* layer = nullptr;
|
||||
|
||||
id<CAMetalDrawable> lastDrawable = nil;
|
||||
|
||||
nxtDevice backendDevice = nullptr;
|
||||
};
|
||||
|
||||
BackendBinding* CreateMetalBinding() {
|
||||
return new MetalBinding;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
// 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.
|
||||
|
||||
#include "BackendBinding.h"
|
||||
|
||||
namespace backend {
|
||||
namespace null {
|
||||
void Init(nxtProcTable* procs, nxtDevice* device);
|
||||
}
|
||||
}
|
||||
|
||||
namespace utils {
|
||||
|
||||
class NullBinding : public BackendBinding {
|
||||
public:
|
||||
void SetupGLFWWindowHints() override {
|
||||
}
|
||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
backend::null::Init(procs, device);
|
||||
}
|
||||
void SwapBuffers() override {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
BackendBinding* CreateNullBinding() {
|
||||
return new NullBinding;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// 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.
|
||||
|
||||
#include "BackendBinding.h"
|
||||
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
namespace backend {
|
||||
namespace opengl {
|
||||
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
|
||||
void HACKCLEAR();
|
||||
}
|
||||
}
|
||||
|
||||
namespace utils {
|
||||
class OpenGLBinding : public BackendBinding {
|
||||
public:
|
||||
void SetupGLFWWindowHints() override {
|
||||
#ifdef __APPLE__
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
#else
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
#endif
|
||||
}
|
||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||
glfwMakeContextCurrent(window);
|
||||
backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
|
||||
}
|
||||
void SwapBuffers() override {
|
||||
glfwSwapBuffers(window);
|
||||
backend::opengl::HACKCLEAR();
|
||||
}
|
||||
};
|
||||
|
||||
BackendBinding* CreateOpenGLBinding() {
|
||||
return new OpenGLBinding;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue