/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "DeviceAttachmentsD3D11.h" #include "mozilla/Telemetry.h" #include "mozilla/layers/Compositor.h" #include "CompositorD3D11Shaders.h" #include "Layers.h" #include "ShaderDefinitionsD3D11.h" namespace mozilla { namespace layers { using namespace gfx; static const size_t kInitialMaximumTriangles = 64; DeviceAttachmentsD3D11::DeviceAttachmentsD3D11(ID3D11Device* device) : mMaximumTriangles(kInitialMaximumTriangles), mDevice(device), mContinueInit(true), mInitialized(false), mDeviceReset(false) {} DeviceAttachmentsD3D11::~DeviceAttachmentsD3D11() {} /* static */ RefPtr DeviceAttachmentsD3D11::Create( ID3D11Device* aDevice) { // We don't return null even if the attachments object even if it fails to // initialize, so the compositor can grab the failure ID. RefPtr attachments = new DeviceAttachmentsD3D11(aDevice); attachments->Initialize(); return attachments.forget(); } bool DeviceAttachmentsD3D11::Initialize() { D3D11_INPUT_ELEMENT_DESC layout[] = { {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, }; HRESULT hr; hr = mDevice->CreateInputLayout( layout, sizeof(layout) / sizeof(D3D11_INPUT_ELEMENT_DESC), LayerQuadVS, sizeof(LayerQuadVS), getter_AddRefs(mInputLayout)); if (Failed(hr, "CreateInputLayout")) { mInitFailureId = "FEATURE_FAILURE_D3D11_INPUT_LAYOUT"; 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, getter_AddRefs(mVertexBuffer)); if (Failed(hr, "create vertex buffer")) { mInitFailureId = "FEATURE_FAILURE_D3D11_VERTEX_BUFFER"; return false; } // Create a second input layout for layers with dynamic geometry. D3D11_INPUT_ELEMENT_DESC dynamicLayout[] = { {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, }; hr = mDevice->CreateInputLayout( dynamicLayout, sizeof(dynamicLayout) / sizeof(D3D11_INPUT_ELEMENT_DESC), LayerDynamicVS, sizeof(LayerDynamicVS), getter_AddRefs(mDynamicInputLayout)); if (Failed(hr, "CreateInputLayout")) { mInitFailureId = "FEATURE_FAILURE_D3D11_INPUT_LAYOUT"; return false; } // Allocate memory for the dynamic vertex buffer. bufferDesc = CD3D11_BUFFER_DESC( sizeof(TexturedVertex) * mMaximumTriangles * 3, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); hr = mDevice->CreateBuffer(&bufferDesc, nullptr, getter_AddRefs(mDynamicVertexBuffer)); if (Failed(hr, "create dynamic vertex buffer")) { mInitFailureId = "FEATURE_FAILURE_D3D11_VERTEX_BUFFER"; return false; } if (!CreateShaders()) { mInitFailureId = "FEATURE_FAILURE_D3D11_CREATE_SHADERS"; return false; } CD3D11_BUFFER_DESC cBufferDesc(sizeof(VertexShaderConstants), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, getter_AddRefs(mVSConstantBuffer)); if (Failed(hr, "create vs buffer")) { mInitFailureId = "FEATURE_FAILURE_D3D11_VS_BUFFER"; return false; } cBufferDesc.ByteWidth = sizeof(PixelShaderConstants); hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, getter_AddRefs(mPSConstantBuffer)); if (Failed(hr, "create ps buffer")) { mInitFailureId = "FEATURE_FAILURE_D3D11_PS_BUFFER"; return false; } CD3D11_RASTERIZER_DESC rastDesc(D3D11_DEFAULT); rastDesc.CullMode = D3D11_CULL_NONE; rastDesc.ScissorEnable = TRUE; hr = mDevice->CreateRasterizerState(&rastDesc, getter_AddRefs(mRasterizerState)); if (Failed(hr, "create rasterizer")) { mInitFailureId = "FEATURE_FAILURE_D3D11_RASTERIZER"; return false; } CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT); hr = mDevice->CreateSamplerState(&samplerDesc, getter_AddRefs(mLinearSamplerState)); if (Failed(hr, "create linear sampler")) { mInitFailureId = "FEATURE_FAILURE_D3D11_LINEAR_SAMPLER"; return false; } samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; hr = mDevice->CreateSamplerState(&samplerDesc, getter_AddRefs(mPointSamplerState)); if (Failed(hr, "create point sampler")) { mInitFailureId = "FEATURE_FAILURE_D3D11_POINT_SAMPLER"; 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, getter_AddRefs(mPremulBlendState)); if (Failed(hr, "create pm blender")) { mInitFailureId = "FEATURE_FAILURE_D3D11_PM_BLENDER"; 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, getter_AddRefs(mNonPremulBlendState)); if (Failed(hr, "create npm blender")) { mInitFailureId = "FEATURE_FAILURE_D3D11_NPM_BLENDER"; return false; } if (LayerManager::LayersComponentAlphaEnabled()) { 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, getter_AddRefs(mComponentBlendState)); if (Failed(hr, "create component blender")) { mInitFailureId = "FEATURE_FAILURE_D3D11_COMP_BLENDER"; 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, getter_AddRefs(mDisabledBlendState)); if (Failed(hr, "create null blender")) { mInitFailureId = "FEATURE_FAILURE_D3D11_NULL_BLENDER"; return false; } if (!InitSyncObject()) { mInitFailureId = "FEATURE_FAILURE_D3D11_OBJ_SYNC"; return false; } mInitialized = true; return true; } bool DeviceAttachmentsD3D11::InitSyncObject() { // Sync object is not supported on WARP. if (DeviceManagerDx::Get()->IsWARP()) { return true; } MOZ_ASSERT(!mSyncObject); MOZ_ASSERT(mDevice); mSyncObject = SyncObjectHost::CreateSyncObjectHost(mDevice); MOZ_ASSERT(mSyncObject); return mSyncObject->Init(); } bool DeviceAttachmentsD3D11::InitBlendShaders() { if (!mVSQuadBlendShader[MaskType::MaskNone]) { InitVertexShader(sLayerQuadBlendVS, mVSQuadBlendShader, MaskType::MaskNone); InitVertexShader(sLayerQuadBlendMaskVS, mVSQuadBlendShader, MaskType::Mask); } if (!mVSDynamicBlendShader[MaskType::MaskNone]) { InitVertexShader(sLayerDynamicBlendVS, mVSDynamicBlendShader, MaskType::MaskNone); InitVertexShader(sLayerDynamicBlendMaskVS, mVSDynamicBlendShader, MaskType::Mask); } if (!mBlendShader[MaskType::MaskNone]) { InitPixelShader(sBlendShader, mBlendShader, MaskType::MaskNone); } return mContinueInit; } bool DeviceAttachmentsD3D11::CreateShaders() { InitVertexShader(sLayerQuadVS, mVSQuadShader, MaskType::MaskNone); InitVertexShader(sLayerQuadMaskVS, mVSQuadShader, MaskType::Mask); InitVertexShader(sLayerDynamicVS, mVSDynamicShader, MaskType::MaskNone); InitVertexShader(sLayerDynamicMaskVS, mVSDynamicShader, MaskType::Mask); InitPixelShader(sSolidColorShader, mSolidColorShader, MaskType::MaskNone); InitPixelShader(sSolidColorShaderMask, mSolidColorShader, MaskType::Mask); InitPixelShader(sRGBShader, mRGBShader, MaskType::MaskNone); InitPixelShader(sRGBShaderMask, mRGBShader, MaskType::Mask); InitPixelShader(sRGBAShader, mRGBAShader, MaskType::MaskNone); InitPixelShader(sRGBAShaderMask, mRGBAShader, MaskType::Mask); InitPixelShader(sYCbCrShader, mYCbCrShader, MaskType::MaskNone); InitPixelShader(sYCbCrShaderMask, mYCbCrShader, MaskType::Mask); InitPixelShader(sNV12Shader, mNV12Shader, MaskType::MaskNone); InitPixelShader(sNV12ShaderMask, mNV12Shader, MaskType::Mask); if (LayerManager::LayersComponentAlphaEnabled()) { InitPixelShader(sComponentAlphaShader, mComponentAlphaShader, MaskType::MaskNone); InitPixelShader(sComponentAlphaShaderMask, mComponentAlphaShader, MaskType::Mask); } return mContinueInit; } void DeviceAttachmentsD3D11::InitVertexShader(const ShaderBytes& aShader, ID3D11VertexShader** aOut) { if (!mContinueInit) { return; } if (Failed(mDevice->CreateVertexShader(aShader.mData, aShader.mLength, nullptr, aOut), "create vs")) { mContinueInit = false; } } void DeviceAttachmentsD3D11::InitPixelShader(const ShaderBytes& aShader, ID3D11PixelShader** aOut) { if (!mContinueInit) { return; } if (Failed(mDevice->CreatePixelShader(aShader.mData, aShader.mLength, nullptr, aOut), "create ps")) { mContinueInit = false; } } bool DeviceAttachmentsD3D11::Failed(HRESULT hr, const char* aContext) { if (SUCCEEDED(hr)) { return false; } gfxCriticalNote << "[D3D11] " << aContext << " failed: " << hexa(hr); return true; } bool DeviceAttachmentsD3D11::EnsureTriangleBuffer(size_t aNumTriangles) { if (aNumTriangles > mMaximumTriangles) { CD3D11_BUFFER_DESC bufferDesc(sizeof(TexturedVertex) * aNumTriangles * 3, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); HRESULT hr = mDevice->CreateBuffer(&bufferDesc, nullptr, getter_AddRefs(mDynamicVertexBuffer)); if (Failed(hr, "resize dynamic vertex buffer")) { return false; } mMaximumTriangles = aNumTriangles; } MOZ_ASSERT(mMaximumTriangles >= aNumTriangles); return true; } } // namespace layers } // namespace mozilla