bool CompositorD3D11::Initialize() { bool force = gfxPrefs::LayersAccelerationForceEnabled(); ScopedGfxFeatureReporter reporter("D3D11 Layers", force); if (!gfxPlatform::CanUseDirect3D11()) { NS_WARNING("Direct3D 11-accelerated layers are not supported on this system."); return false; } HRESULT hr; mDevice = gfxWindowsPlatform::GetPlatform()->GetD3D11Device(); if (!mDevice) { return false; } mDevice->GetImmediateContext(byRef(mContext)); if (!mContext) { return false; } mFeatureLevel = mDevice->GetFeatureLevel(); mHwnd = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW); memset(&mVSConstants, 0, sizeof(VertexShaderConstants)); int referenceCount = 0; UINT size = sizeof(referenceCount); // If this isn't there yet it'll fail, count will remain 0, which is correct. mDevice->GetPrivateData(sLayerManagerCount, &size, &referenceCount); referenceCount++; mDevice->SetPrivateData(sLayerManagerCount, sizeof(referenceCount), &referenceCount); size = sizeof(DeviceAttachmentsD3D11*); if (FAILED(mDevice->GetPrivateData(sDeviceAttachmentsD3D11, &size, &mAttachments))) { mAttachments = new DeviceAttachmentsD3D11; mDevice->SetPrivateData(sDeviceAttachmentsD3D11, sizeof(mAttachments), &mAttachments); D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; hr = mDevice->CreateInputLayout(layout, sizeof(layout) / sizeof(D3D11_INPUT_ELEMENT_DESC), LayerQuadVS, sizeof(LayerQuadVS), byRef(mAttachments->mInputLayout)); if (FAILED(hr)) { return false; } Vertex vertices[] = { {{0.0, 0.0}}, {{1.0, 0.0}}, {{0.0, 1.0}}, {{1.0, 1.0}} }; CD3D11_BUFFER_DESC bufferDesc(sizeof(vertices), D3D11_BIND_VERTEX_BUFFER); D3D11_SUBRESOURCE_DATA data; data.pSysMem = (void*)vertices; hr = mDevice->CreateBuffer(&bufferDesc, &data, byRef(mAttachments->mVertexBuffer)); if (FAILED(hr)) { return false; } if (!CreateShaders()) { return false; } CD3D11_BUFFER_DESC cBufferDesc(sizeof(VertexShaderConstants), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, byRef(mAttachments->mVSConstantBuffer)); if (FAILED(hr)) { return false; } cBufferDesc.ByteWidth = sizeof(PixelShaderConstants); hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, byRef(mAttachments->mPSConstantBuffer)); if (FAILED(hr)) { return false; } CD3D11_RASTERIZER_DESC rastDesc(D3D11_DEFAULT); rastDesc.CullMode = D3D11_CULL_NONE; rastDesc.ScissorEnable = TRUE; hr = mDevice->CreateRasterizerState(&rastDesc, byRef(mAttachments->mRasterizerState)); if (FAILED(hr)) { return false; } CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT); hr = mDevice->CreateSamplerState(&samplerDesc, byRef(mAttachments->mLinearSamplerState)); if (FAILED(hr)) { return false; } samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; hr = mDevice->CreateSamplerState(&samplerDesc, byRef(mAttachments->mPointSamplerState)); if (FAILED(hr)) { return false; } CD3D11_BLEND_DESC blendDesc(D3D11_DEFAULT); D3D11_RENDER_TARGET_BLEND_DESC rtBlendPremul = { TRUE, D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, D3D11_COLOR_WRITE_ENABLE_ALL }; blendDesc.RenderTarget[0] = rtBlendPremul; hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mPremulBlendState)); if (FAILED(hr)) { return false; } D3D11_RENDER_TARGET_BLEND_DESC rtBlendNonPremul = { TRUE, D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, D3D11_COLOR_WRITE_ENABLE_ALL }; blendDesc.RenderTarget[0] = rtBlendNonPremul; hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mNonPremulBlendState)); if (FAILED(hr)) { return false; } if (gfxPrefs::ComponentAlphaEnabled()) { D3D11_RENDER_TARGET_BLEND_DESC rtBlendComponent = { TRUE, D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC1_COLOR, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, D3D11_COLOR_WRITE_ENABLE_ALL }; blendDesc.RenderTarget[0] = rtBlendComponent; hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mComponentBlendState)); if (FAILED(hr)) { return false; } } D3D11_RENDER_TARGET_BLEND_DESC rtBlendDisabled = { FALSE, D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, D3D11_COLOR_WRITE_ENABLE_ALL }; blendDesc.RenderTarget[0] = rtBlendDisabled; hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mDisabledBlendState)); if (FAILED(hr)) { return false; } } nsRefPtr<IDXGIDevice> dxgiDevice; nsRefPtr<IDXGIAdapter> dxgiAdapter; mDevice->QueryInterface(dxgiDevice.StartAssignment()); dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)); #ifdef MOZ_METRO if (IsRunningInWindowsMetro()) { nsRefPtr<IDXGIFactory2> dxgiFactory; dxgiAdapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment())); nsIntRect rect; mWidget->GetClientBounds(rect); DXGI_SWAP_CHAIN_DESC1 swapDesc = { 0 }; // Automatically detect the width and the height from the winrt CoreWindow swapDesc.Width = rect.width; swapDesc.Height = rect.height; // This is the most common swapchain format swapDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; swapDesc.Stereo = false; // Don't use multi-sampling swapDesc.SampleDesc.Count = 1; swapDesc.SampleDesc.Quality = 0; swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // Use double buffering to enable flip swapDesc.BufferCount = 2; swapDesc.Scaling = DXGI_SCALING_NONE; // All Metro style apps must use this SwapEffect swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; swapDesc.Flags = 0; /** * Create a swap chain, this swap chain will contain the backbuffer for * the window we draw to. The front buffer is the full screen front * buffer. */ nsRefPtr<IDXGISwapChain1> swapChain1; hr = dxgiFactory->CreateSwapChainForCoreWindow( dxgiDevice, (IUnknown *)mWidget->GetNativeData(NS_NATIVE_ICOREWINDOW), &swapDesc, nullptr, getter_AddRefs(swapChain1)); if (FAILED(hr)) { return false; } mSwapChain = swapChain1; } else #endif { nsRefPtr<IDXGIFactory> dxgiFactory; dxgiAdapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment())); DXGI_SWAP_CHAIN_DESC swapDesc; ::ZeroMemory(&swapDesc, sizeof(swapDesc)); swapDesc.BufferDesc.Width = 0; swapDesc.BufferDesc.Height = 0; swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; swapDesc.BufferDesc.RefreshRate.Numerator = 60; swapDesc.BufferDesc.RefreshRate.Denominator = 1; swapDesc.SampleDesc.Count = 1; swapDesc.SampleDesc.Quality = 0; swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapDesc.BufferCount = 1; swapDesc.OutputWindow = mHwnd; swapDesc.Windowed = TRUE; swapDesc.Flags = 0; /** * Create a swap chain, this swap chain will contain the backbuffer for * the window we draw to. The front buffer is the full screen front * buffer. */ hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc, byRef(mSwapChain)); if (FAILED(hr)) { return false; } // We need this because we don't want DXGI to respond to Alt+Enter. dxgiFactory->MakeWindowAssociation(swapDesc.OutputWindow, DXGI_MWA_NO_WINDOW_CHANGES); } reporter.SetSuccessful(); return true; }
// Load the sample assets. void D3D12SmallResources::LoadAssets() { // Create a root signature consisting of a single CBV parameter. { CD3DX12_DESCRIPTOR_RANGE ranges[1]; CD3DX12_ROOT_PARAMETER rootParameters[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL); // Allow input layout and deny uneccessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS; CD3DX12_STATIC_SAMPLER_DESC samplerDesc(0, D3D12_FILTER_MIN_MAG_MIP_LINEAR); CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 1, &samplerDesc, rootSignatureFlags); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); NAME_D3D12_OBJECT(m_rootSignature); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; #if defined(_DEBUG) // Enable better shader debugging with the graphics debugging tools. UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT compileFlags = 0; #endif ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr)); // Define the vertex input layout. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; // Describe and create the graphics pipeline state objects (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); NAME_D3D12_OBJECT(m_pipelineState); } // Create the command lists. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList))); NAME_D3D12_OBJECT(m_commandList); ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, m_copyCommandAllocator.Get(), nullptr, IID_PPV_ARGS(&m_copyCommandList))); ThrowIfFailed(m_copyCommandList->Close()); NAME_D3D12_OBJECT(m_copyCommandList); // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> vertexBufferUpload; // Create the vertex buffer. { // Create quads for all of the images that will be generated and drawn to the screen. Vertex quadVertices[TextureCount * 4]; UINT index = 0; float offsetX = 0.15f; float marginX = offsetX / 10.0f;; float startX = (GridWidth / 2.0f) * -(offsetX + marginX) + marginX / 2.0f; float offsetY = offsetX * m_aspectRatio; float marginY = offsetY / 10.0f; float y = (GridHeight / 2.0f) * (offsetY + marginY) - marginY / 2.0f; for (UINT row = 0; row < GridHeight; row++) { float x = startX; for (UINT column = 0; column < GridWidth; column++) { quadVertices[index++] = { { x, y - offsetY, 0.0f }, { 0.0f, 0.0f } }; quadVertices[index++] = { { x, y, 0.0f }, { 0.0f, 1.0f } }; quadVertices[index++] = { { x + offsetX, y - offsetY, 0.0f }, { 1.0f, 0.0f } }; quadVertices[index++] = { { x + offsetX, y, 0.0f }, { 1.0f, 1.0f } }; x += offsetX + marginX; } y -= offsetY + marginY; } const UINT vertexBufferSize = sizeof(quadVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&vertexBufferUpload))); NAME_D3D12_OBJECT(m_vertexBuffer); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. D3D12_SUBRESOURCE_DATA vertexData = {}; vertexData.pData = reinterpret_cast<UINT8*>(quadVertices); vertexData.RowPitch = vertexBufferSize; vertexData.SlicePitch = vertexData.RowPitch; UpdateSubresources<1>(m_commandList.Get(), m_vertexBuffer.Get(), vertexBufferUpload.Get(), 0, 0, 1, &vertexData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = sizeof(quadVertices); } // Close the command list and execute it to begin the vertex buffer copy into // the default heap. ThrowIfFailed(m_commandList->Close()); ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValues[m_frameIndex]++; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForGpu(); } CreateTextures(); }