gfx/layers/d3d10/LayerManagerD3D10.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include <algorithm>
michael@0 7
michael@0 8 #include "LayerManagerD3D10.h"
michael@0 9 #include "LayerManagerD3D10Effect.h"
michael@0 10 #include "gfxWindowsPlatform.h"
michael@0 11 #include "gfx2DGlue.h"
michael@0 12 #include "gfxD2DSurface.h"
michael@0 13 #include "gfxFailure.h"
michael@0 14 #include "cairo-win32.h"
michael@0 15 #include "dxgi.h"
michael@0 16
michael@0 17 #include "ContainerLayerD3D10.h"
michael@0 18 #include "ThebesLayerD3D10.h"
michael@0 19 #include "ColorLayerD3D10.h"
michael@0 20 #include "CanvasLayerD3D10.h"
michael@0 21 #include "ReadbackLayerD3D10.h"
michael@0 22 #include "ImageLayerD3D10.h"
michael@0 23 #include "mozilla/layers/PLayerChild.h"
michael@0 24 #include "mozilla/WidgetUtils.h"
michael@0 25
michael@0 26 #include "../d3d9/Nv3DVUtils.h"
michael@0 27
michael@0 28 #include "gfxCrashReporterUtils.h"
michael@0 29 #include "nsWindowsHelpers.h"
michael@0 30 #ifdef MOZ_METRO
michael@0 31 #include "DXGI1_2.h"
michael@0 32 #endif
michael@0 33
michael@0 34 using namespace std;
michael@0 35 using namespace mozilla::dom;
michael@0 36 using namespace mozilla::gfx;
michael@0 37
michael@0 38 namespace mozilla {
michael@0 39 namespace layers {
michael@0 40
michael@0 41 struct Vertex
michael@0 42 {
michael@0 43 float position[2];
michael@0 44 };
michael@0 45
michael@0 46 // {592BF306-0EED-4F76-9D03-A0846450F472}
michael@0 47 static const GUID sDeviceAttachments =
michael@0 48 { 0x592bf306, 0xeed, 0x4f76, { 0x9d, 0x3, 0xa0, 0x84, 0x64, 0x50, 0xf4, 0x72 } };
michael@0 49 // {716AEDB1-C9C3-4B4D-8332-6F65D44AF6A8}
michael@0 50 static const GUID sLayerManagerCount =
michael@0 51 { 0x716aedb1, 0xc9c3, 0x4b4d, { 0x83, 0x32, 0x6f, 0x65, 0xd4, 0x4a, 0xf6, 0xa8 } };
michael@0 52
michael@0 53 LayerManagerD3D10::LayerManagerD3D10(nsIWidget *aWidget)
michael@0 54 : mWidget(aWidget)
michael@0 55 , mDisableSequenceForNextFrame(false)
michael@0 56 {
michael@0 57 }
michael@0 58
michael@0 59 struct DeviceAttachments
michael@0 60 {
michael@0 61 nsRefPtr<ID3D10Effect> mEffect;
michael@0 62 nsRefPtr<ID3D10InputLayout> mInputLayout;
michael@0 63 nsRefPtr<ID3D10Buffer> mVertexBuffer;
michael@0 64 nsRefPtr<ReadbackManagerD3D10> mReadbackManager;
michael@0 65 };
michael@0 66
michael@0 67 LayerManagerD3D10::~LayerManagerD3D10()
michael@0 68 {
michael@0 69 if (mDevice) {
michael@0 70 int referenceCount = 0;
michael@0 71 UINT size = sizeof(referenceCount);
michael@0 72 HRESULT hr = mDevice->GetPrivateData(sLayerManagerCount, &size, &referenceCount);
michael@0 73 NS_ASSERTION(SUCCEEDED(hr), "Reference count not found on device.");
michael@0 74 referenceCount--;
michael@0 75 mDevice->SetPrivateData(sLayerManagerCount, sizeof(referenceCount), &referenceCount);
michael@0 76
michael@0 77 if (!referenceCount) {
michael@0 78 DeviceAttachments *attachments;
michael@0 79 size = sizeof(attachments);
michael@0 80 mDevice->GetPrivateData(sDeviceAttachments, &size, &attachments);
michael@0 81 // No LayerManagers left for this device. Clear out interfaces stored which
michael@0 82 // hold a reference to the device.
michael@0 83 mDevice->SetPrivateData(sDeviceAttachments, 0, nullptr);
michael@0 84
michael@0 85 delete attachments;
michael@0 86 }
michael@0 87 }
michael@0 88
michael@0 89 Destroy();
michael@0 90 }
michael@0 91
michael@0 92 static inline void
michael@0 93 SetHRESULT(HRESULT* aHresultPtr, HRESULT aHresult)
michael@0 94 {
michael@0 95 if (aHresultPtr) {
michael@0 96 *aHresultPtr = aHresult;
michael@0 97 }
michael@0 98 }
michael@0 99
michael@0 100 bool
michael@0 101 LayerManagerD3D10::Initialize(bool force, HRESULT* aHresultPtr)
michael@0 102 {
michael@0 103 ScopedGfxFeatureReporter reporter("D3D10 Layers", force);
michael@0 104
michael@0 105 HRESULT hr = E_UNEXPECTED;
michael@0 106
michael@0 107 /* Create an Nv3DVUtils instance */
michael@0 108 if (!mNv3DVUtils) {
michael@0 109 mNv3DVUtils = new Nv3DVUtils();
michael@0 110 if (!mNv3DVUtils) {
michael@0 111 NS_WARNING("Could not create a new instance of Nv3DVUtils.\n");
michael@0 112 }
michael@0 113 }
michael@0 114
michael@0 115 /* Initialize the Nv3DVUtils object */
michael@0 116 if (mNv3DVUtils) {
michael@0 117 mNv3DVUtils->Initialize();
michael@0 118 }
michael@0 119
michael@0 120 mDevice = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
michael@0 121 if (!mDevice) {
michael@0 122 SetHRESULT(aHresultPtr, hr);
michael@0 123 return false;
michael@0 124 }
michael@0 125
michael@0 126 /*
michael@0 127 * Do some post device creation setup
michael@0 128 */
michael@0 129 if (mNv3DVUtils) {
michael@0 130 IUnknown* devUnknown = nullptr;
michael@0 131 if (mDevice) {
michael@0 132 mDevice->QueryInterface(IID_IUnknown, (void **)&devUnknown);
michael@0 133 }
michael@0 134 mNv3DVUtils->SetDeviceInfo(devUnknown);
michael@0 135 }
michael@0 136
michael@0 137 int referenceCount = 0;
michael@0 138 UINT size = sizeof(referenceCount);
michael@0 139 // If this isn't there yet it'll fail, count will remain 0, which is correct.
michael@0 140 mDevice->GetPrivateData(sLayerManagerCount, &size, &referenceCount);
michael@0 141 referenceCount++;
michael@0 142 mDevice->SetPrivateData(sLayerManagerCount, sizeof(referenceCount), &referenceCount);
michael@0 143
michael@0 144 DeviceAttachments *attachments;
michael@0 145 size = sizeof(DeviceAttachments*);
michael@0 146 if (FAILED(mDevice->GetPrivateData(sDeviceAttachments, &size, &attachments))) {
michael@0 147 attachments = new DeviceAttachments;
michael@0 148 mDevice->SetPrivateData(sDeviceAttachments, sizeof(attachments), &attachments);
michael@0 149
michael@0 150 SetLastError(0);
michael@0 151 decltype(D3D10CreateEffectFromMemory)* createEffect =
michael@0 152 (decltype(D3D10CreateEffectFromMemory)*)
michael@0 153 GetProcAddress(LoadLibraryA("d3d10_1.dll"), "D3D10CreateEffectFromMemory");
michael@0 154 if (!createEffect) {
michael@0 155 SetHRESULT(aHresultPtr, HRESULT_FROM_WIN32(GetLastError()));
michael@0 156 return false;
michael@0 157 }
michael@0 158
michael@0 159 hr = createEffect((void*)g_main,
michael@0 160 sizeof(g_main),
michael@0 161 D3D10_EFFECT_SINGLE_THREADED,
michael@0 162 mDevice,
michael@0 163 nullptr,
michael@0 164 getter_AddRefs(mEffect));
michael@0 165
michael@0 166 if (FAILED(hr)) {
michael@0 167 SetHRESULT(aHresultPtr, hr);
michael@0 168 return false;
michael@0 169 }
michael@0 170
michael@0 171 attachments->mEffect = mEffect;
michael@0 172
michael@0 173 D3D10_INPUT_ELEMENT_DESC layout[] =
michael@0 174 {
michael@0 175 { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
michael@0 176 };
michael@0 177 D3D10_PASS_DESC passDesc;
michael@0 178 mEffect->GetTechniqueByName("RenderRGBLayerPremul")->GetPassByIndex(0)->
michael@0 179 GetDesc(&passDesc);
michael@0 180
michael@0 181 hr = mDevice->CreateInputLayout(layout,
michael@0 182 sizeof(layout) / sizeof(D3D10_INPUT_ELEMENT_DESC),
michael@0 183 passDesc.pIAInputSignature,
michael@0 184 passDesc.IAInputSignatureSize,
michael@0 185 getter_AddRefs(mInputLayout));
michael@0 186
michael@0 187 if (FAILED(hr)) {
michael@0 188 SetHRESULT(aHresultPtr, hr);
michael@0 189 return false;
michael@0 190 }
michael@0 191
michael@0 192 attachments->mInputLayout = mInputLayout;
michael@0 193
michael@0 194 Vertex vertices[] = { {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0} };
michael@0 195 CD3D10_BUFFER_DESC bufferDesc(sizeof(vertices), D3D10_BIND_VERTEX_BUFFER);
michael@0 196 D3D10_SUBRESOURCE_DATA data;
michael@0 197 data.pSysMem = (void*)vertices;
michael@0 198
michael@0 199 hr = mDevice->CreateBuffer(&bufferDesc, &data, getter_AddRefs(mVertexBuffer));
michael@0 200
michael@0 201 if (FAILED(hr)) {
michael@0 202 SetHRESULT(aHresultPtr, hr);
michael@0 203 return false;
michael@0 204 }
michael@0 205
michael@0 206 attachments->mVertexBuffer = mVertexBuffer;
michael@0 207 } else {
michael@0 208 mEffect = attachments->mEffect;
michael@0 209 mVertexBuffer = attachments->mVertexBuffer;
michael@0 210 mInputLayout = attachments->mInputLayout;
michael@0 211 }
michael@0 212
michael@0 213 nsRefPtr<IDXGIDevice> dxgiDevice;
michael@0 214 nsRefPtr<IDXGIAdapter> dxgiAdapter;
michael@0 215
michael@0 216 mDevice->QueryInterface(dxgiDevice.StartAssignment());
michael@0 217 dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter));
michael@0 218
michael@0 219 #ifdef MOZ_METRO
michael@0 220 if (IsRunningInWindowsMetro()) {
michael@0 221 nsRefPtr<IDXGIFactory2> dxgiFactory;
michael@0 222 dxgiAdapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment()));
michael@0 223
michael@0 224 nsIntRect rect;
michael@0 225 mWidget->GetClientBounds(rect);
michael@0 226
michael@0 227 DXGI_SWAP_CHAIN_DESC1 swapDesc = { 0 };
michael@0 228 // Automatically detect the width and the height from the winrt CoreWindow
michael@0 229 swapDesc.Width = rect.width;
michael@0 230 swapDesc.Height = rect.height;
michael@0 231 // This is the most common swapchain format
michael@0 232 swapDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
michael@0 233 swapDesc.Stereo = false;
michael@0 234 // Don't use multi-sampling
michael@0 235 swapDesc.SampleDesc.Count = 1;
michael@0 236 swapDesc.SampleDesc.Quality = 0;
michael@0 237 swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
michael@0 238 // Use double buffering to enable flip
michael@0 239 swapDesc.BufferCount = 2;
michael@0 240 swapDesc.Scaling = DXGI_SCALING_NONE;
michael@0 241 // All Metro style apps must use this SwapEffect
michael@0 242 swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
michael@0 243 swapDesc.Flags = 0;
michael@0 244
michael@0 245 /**
michael@0 246 * Create a swap chain, this swap chain will contain the backbuffer for
michael@0 247 * the window we draw to. The front buffer is the full screen front
michael@0 248 * buffer.
michael@0 249 */
michael@0 250 nsRefPtr<IDXGISwapChain1> swapChain1;
michael@0 251 hr = dxgiFactory->CreateSwapChainForCoreWindow(
michael@0 252 dxgiDevice, (IUnknown *)mWidget->GetNativeData(NS_NATIVE_ICOREWINDOW),
michael@0 253 &swapDesc, nullptr, getter_AddRefs(swapChain1));
michael@0 254 if (FAILED(hr)) {
michael@0 255 SetHRESULT(aHresultPtr, hr);
michael@0 256 return false;
michael@0 257 }
michael@0 258 mSwapChain = swapChain1;
michael@0 259 } else
michael@0 260 #endif
michael@0 261 {
michael@0 262 nsRefPtr<IDXGIFactory> dxgiFactory;
michael@0 263 dxgiAdapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment()));
michael@0 264
michael@0 265 DXGI_SWAP_CHAIN_DESC swapDesc;
michael@0 266 ::ZeroMemory(&swapDesc, sizeof(swapDesc));
michael@0 267 swapDesc.BufferDesc.Width = 0;
michael@0 268 swapDesc.BufferDesc.Height = 0;
michael@0 269 swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
michael@0 270 swapDesc.BufferDesc.RefreshRate.Numerator = 60;
michael@0 271 swapDesc.BufferDesc.RefreshRate.Denominator = 1;
michael@0 272 swapDesc.SampleDesc.Count = 1;
michael@0 273 swapDesc.SampleDesc.Quality = 0;
michael@0 274 swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
michael@0 275 swapDesc.BufferCount = 1;
michael@0 276 swapDesc.OutputWindow = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW);
michael@0 277 swapDesc.Windowed = TRUE;
michael@0 278 // We don't really need this flag, however it seems on some NVidia hardware
michael@0 279 // smaller area windows do not present properly without this flag. This flag
michael@0 280 // should have no negative consequences by itself. See bug 613790. This flag
michael@0 281 // is broken on optimus devices. As a temporary solution we don't set it
michael@0 282 // there, the only way of reliably detecting we're on optimus is looking for
michael@0 283 // the DLL. See Bug 623807.
michael@0 284 if (gfxWindowsPlatform::IsOptimus()) {
michael@0 285 swapDesc.Flags = 0;
michael@0 286 } else {
michael@0 287 swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;
michael@0 288 }
michael@0 289
michael@0 290 /**
michael@0 291 * Create a swap chain, this swap chain will contain the backbuffer for
michael@0 292 * the window we draw to. The front buffer is the full screen front
michael@0 293 * buffer.
michael@0 294 */
michael@0 295 hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc, getter_AddRefs(mSwapChain));
michael@0 296 if (FAILED(hr)) {
michael@0 297 return false;
michael@0 298 }
michael@0 299
michael@0 300 // We need this because we don't want DXGI to respond to Alt+Enter.
michael@0 301 dxgiFactory->MakeWindowAssociation(swapDesc.OutputWindow, DXGI_MWA_NO_WINDOW_CHANGES);
michael@0 302 }
michael@0 303
michael@0 304 reporter.SetSuccessful();
michael@0 305 return true;
michael@0 306 }
michael@0 307
michael@0 308 void
michael@0 309 LayerManagerD3D10::Destroy()
michael@0 310 {
michael@0 311 if (!IsDestroyed()) {
michael@0 312 if (mRoot) {
michael@0 313 static_cast<LayerD3D10*>(mRoot->ImplData())->LayerManagerDestroyed();
michael@0 314 }
michael@0 315 // XXX need to be careful here about surface destruction
michael@0 316 // racing with share-to-chrome message
michael@0 317 }
michael@0 318 LayerManager::Destroy();
michael@0 319 }
michael@0 320
michael@0 321 void
michael@0 322 LayerManagerD3D10::SetRoot(Layer *aRoot)
michael@0 323 {
michael@0 324 mRoot = aRoot;
michael@0 325 }
michael@0 326
michael@0 327 void
michael@0 328 LayerManagerD3D10::BeginTransaction()
michael@0 329 {
michael@0 330 mInTransaction = true;
michael@0 331
michael@0 332 #ifdef MOZ_LAYERS_HAVE_LOG
michael@0 333 MOZ_LAYERS_LOG(("[----- BeginTransaction"));
michael@0 334 Log();
michael@0 335 #endif
michael@0 336 }
michael@0 337
michael@0 338 void
michael@0 339 LayerManagerD3D10::BeginTransactionWithTarget(gfxContext* aTarget)
michael@0 340 {
michael@0 341 mInTransaction = true;
michael@0 342 mTarget = aTarget;
michael@0 343 }
michael@0 344
michael@0 345 bool
michael@0 346 LayerManagerD3D10::EndEmptyTransaction(EndTransactionFlags aFlags)
michael@0 347 {
michael@0 348 mInTransaction = false;
michael@0 349
michael@0 350 if (!mRoot)
michael@0 351 return false;
michael@0 352
michael@0 353 EndTransaction(nullptr, nullptr, aFlags);
michael@0 354 return true;
michael@0 355 }
michael@0 356
michael@0 357 void
michael@0 358 LayerManagerD3D10::EndTransaction(DrawThebesLayerCallback aCallback,
michael@0 359 void* aCallbackData,
michael@0 360 EndTransactionFlags aFlags)
michael@0 361 {
michael@0 362 mInTransaction = false;
michael@0 363
michael@0 364 if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
michael@0 365 mCurrentCallbackInfo.Callback = aCallback;
michael@0 366 mCurrentCallbackInfo.CallbackData = aCallbackData;
michael@0 367
michael@0 368 if (aFlags & END_NO_COMPOSITE) {
michael@0 369 // Apply pending tree updates before recomputing effective
michael@0 370 // properties.
michael@0 371 mRoot->ApplyPendingUpdatesToSubtree();
michael@0 372 }
michael@0 373
michael@0 374 // The results of our drawing always go directly into a pixel buffer,
michael@0 375 // so we don't need to pass any global transform here.
michael@0 376 mRoot->ComputeEffectiveTransforms(Matrix4x4());
michael@0 377
michael@0 378 #ifdef MOZ_LAYERS_HAVE_LOG
michael@0 379 MOZ_LAYERS_LOG((" ----- (beginning paint)"));
michael@0 380 Log();
michael@0 381 #endif
michael@0 382
michael@0 383 Render(aFlags);
michael@0 384 mCurrentCallbackInfo.Callback = nullptr;
michael@0 385 mCurrentCallbackInfo.CallbackData = nullptr;
michael@0 386 }
michael@0 387
michael@0 388 #ifdef MOZ_LAYERS_HAVE_LOG
michael@0 389 Log();
michael@0 390 MOZ_LAYERS_LOG(("]----- EndTransaction"));
michael@0 391 #endif
michael@0 392
michael@0 393 mTarget = nullptr;
michael@0 394 }
michael@0 395
michael@0 396 already_AddRefed<ThebesLayer>
michael@0 397 LayerManagerD3D10::CreateThebesLayer()
michael@0 398 {
michael@0 399 nsRefPtr<ThebesLayer> layer = new ThebesLayerD3D10(this);
michael@0 400 return layer.forget();
michael@0 401 }
michael@0 402
michael@0 403 already_AddRefed<ContainerLayer>
michael@0 404 LayerManagerD3D10::CreateContainerLayer()
michael@0 405 {
michael@0 406 nsRefPtr<ContainerLayer> layer = new ContainerLayerD3D10(this);
michael@0 407 return layer.forget();
michael@0 408 }
michael@0 409
michael@0 410 already_AddRefed<ImageLayer>
michael@0 411 LayerManagerD3D10::CreateImageLayer()
michael@0 412 {
michael@0 413 nsRefPtr<ImageLayer> layer = new ImageLayerD3D10(this);
michael@0 414 return layer.forget();
michael@0 415 }
michael@0 416
michael@0 417 already_AddRefed<ColorLayer>
michael@0 418 LayerManagerD3D10::CreateColorLayer()
michael@0 419 {
michael@0 420 nsRefPtr<ColorLayer> layer = new ColorLayerD3D10(this);
michael@0 421 return layer.forget();
michael@0 422 }
michael@0 423
michael@0 424 already_AddRefed<CanvasLayer>
michael@0 425 LayerManagerD3D10::CreateCanvasLayer()
michael@0 426 {
michael@0 427 nsRefPtr<CanvasLayer> layer = new CanvasLayerD3D10(this);
michael@0 428 return layer.forget();
michael@0 429 }
michael@0 430
michael@0 431 already_AddRefed<ReadbackLayer>
michael@0 432 LayerManagerD3D10::CreateReadbackLayer()
michael@0 433 {
michael@0 434 nsRefPtr<ReadbackLayer> layer = new ReadbackLayerD3D10(this);
michael@0 435 return layer.forget();
michael@0 436 }
michael@0 437
michael@0 438 static void ReleaseTexture(void *texture)
michael@0 439 {
michael@0 440 static_cast<ID3D10Texture2D*>(texture)->Release();
michael@0 441 }
michael@0 442
michael@0 443 TemporaryRef<DrawTarget>
michael@0 444 LayerManagerD3D10::CreateOptimalDrawTarget(const IntSize &aSize,
michael@0 445 SurfaceFormat aFormat)
michael@0 446 {
michael@0 447 if ((aFormat != SurfaceFormat::B8G8R8X8 &&
michael@0 448 aFormat != SurfaceFormat::B8G8R8A8)) {
michael@0 449 return LayerManager::CreateOptimalDrawTarget(aSize, aFormat);
michael@0 450 }
michael@0 451
michael@0 452 nsRefPtr<ID3D10Texture2D> texture;
michael@0 453
michael@0 454 CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1);
michael@0 455 desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
michael@0 456 desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
michael@0 457
michael@0 458 HRESULT hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
michael@0 459
michael@0 460 if (FAILED(hr)) {
michael@0 461 NS_WARNING("Failed to create new texture for CreateOptimalDrawTarget!");
michael@0 462 return LayerManager::CreateOptimalDrawTarget(aSize, aFormat);
michael@0 463 }
michael@0 464
michael@0 465 RefPtr<DrawTarget> dt =
michael@0 466 Factory::CreateDrawTargetForD3D10Texture(texture, aFormat);
michael@0 467
michael@0 468 if (!dt) {
michael@0 469 return LayerManager::CreateOptimalDrawTarget(aSize, aFormat);
michael@0 470 }
michael@0 471
michael@0 472 return dt;
michael@0 473 }
michael@0 474
michael@0 475
michael@0 476 TemporaryRef<DrawTarget>
michael@0 477 LayerManagerD3D10::CreateOptimalMaskDrawTarget(const IntSize &aSize)
michael@0 478 {
michael@0 479 return CreateOptimalDrawTarget(aSize, SurfaceFormat::B8G8R8A8);
michael@0 480 }
michael@0 481
michael@0 482
michael@0 483 TemporaryRef<DrawTarget>
michael@0 484 LayerManagerD3D10::CreateDrawTarget(const IntSize &aSize,
michael@0 485 SurfaceFormat aFormat)
michael@0 486 {
michael@0 487 if ((aFormat != SurfaceFormat::B8G8R8A8 &&
michael@0 488 aFormat != SurfaceFormat::B8G8R8X8) ||
michael@0 489 gfxPlatform::GetPlatform()->GetPreferredCanvasBackend() != BackendType::DIRECT2D) {
michael@0 490 return LayerManager::CreateDrawTarget(aSize, aFormat);
michael@0 491 }
michael@0 492
michael@0 493 nsRefPtr<ID3D10Texture2D> texture;
michael@0 494
michael@0 495 CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1);
michael@0 496 desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
michael@0 497
michael@0 498 HRESULT hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
michael@0 499
michael@0 500 if (FAILED(hr)) {
michael@0 501 NS_WARNING("Failed to create new texture for CreateOptimalDrawTarget!");
michael@0 502 return LayerManager::CreateDrawTarget(aSize, aFormat);
michael@0 503 }
michael@0 504
michael@0 505 RefPtr<DrawTarget> surface =
michael@0 506 Factory::CreateDrawTargetForD3D10Texture(texture, aFormat);
michael@0 507
michael@0 508 if (!surface) {
michael@0 509 return LayerManager::CreateDrawTarget(aSize, aFormat);
michael@0 510 }
michael@0 511
michael@0 512 return surface;
michael@0 513 }
michael@0 514
michael@0 515 ReadbackManagerD3D10*
michael@0 516 LayerManagerD3D10::readbackManager()
michael@0 517 {
michael@0 518 EnsureReadbackManager();
michael@0 519 return mReadbackManager;
michael@0 520 }
michael@0 521
michael@0 522 void
michael@0 523 LayerManagerD3D10::SetViewport(const nsIntSize &aViewport)
michael@0 524 {
michael@0 525 mViewport = aViewport;
michael@0 526
michael@0 527 D3D10_VIEWPORT viewport;
michael@0 528 viewport.MaxDepth = 1.0f;
michael@0 529 viewport.MinDepth = 0;
michael@0 530 viewport.Width = aViewport.width;
michael@0 531 viewport.Height = aViewport.height;
michael@0 532 viewport.TopLeftX = 0;
michael@0 533 viewport.TopLeftY = 0;
michael@0 534
michael@0 535 mDevice->RSSetViewports(1, &viewport);
michael@0 536
michael@0 537 gfx3DMatrix projection;
michael@0 538 /*
michael@0 539 * Matrix to transform to viewport space ( <-1.0, 1.0> topleft,
michael@0 540 * <1.0, -1.0> bottomright)
michael@0 541 */
michael@0 542 projection._11 = 2.0f / aViewport.width;
michael@0 543 projection._22 = -2.0f / aViewport.height;
michael@0 544 projection._33 = 0.0f;
michael@0 545 projection._41 = -1.0f;
michael@0 546 projection._42 = 1.0f;
michael@0 547 projection._44 = 1.0f;
michael@0 548
michael@0 549 HRESULT hr = mEffect->GetVariableByName("mProjection")->
michael@0 550 SetRawValue(&projection._11, 0, 64);
michael@0 551
michael@0 552 if (FAILED(hr)) {
michael@0 553 NS_WARNING("Failed to set projection matrix.");
michael@0 554 }
michael@0 555 }
michael@0 556
michael@0 557 void
michael@0 558 LayerManagerD3D10::SetupInputAssembler()
michael@0 559 {
michael@0 560 mDevice->IASetInputLayout(mInputLayout);
michael@0 561
michael@0 562 UINT stride = sizeof(Vertex);
michael@0 563 UINT offset = 0;
michael@0 564 ID3D10Buffer *buffer = mVertexBuffer;
michael@0 565 mDevice->IASetVertexBuffers(0, 1, &buffer, &stride, &offset);
michael@0 566 mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
michael@0 567 }
michael@0 568
michael@0 569 void
michael@0 570 LayerManagerD3D10::SetupPipeline()
michael@0 571 {
michael@0 572 VerifyBufferSize();
michael@0 573 UpdateRenderTarget();
michael@0 574
michael@0 575 nsIntRect rect;
michael@0 576 mWidget->GetClientBounds(rect);
michael@0 577
michael@0 578 HRESULT hr;
michael@0 579
michael@0 580 hr = mEffect->GetVariableByName("vTextureCoords")->AsVector()->
michael@0 581 SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
michael@0 582
michael@0 583 if (FAILED(hr)) {
michael@0 584 NS_WARNING("Failed to set Texture Coordinates.");
michael@0 585 return;
michael@0 586 }
michael@0 587
michael@0 588 ID3D10RenderTargetView *view = mRTView;
michael@0 589 mDevice->OMSetRenderTargets(1, &view, nullptr);
michael@0 590
michael@0 591 SetupInputAssembler();
michael@0 592
michael@0 593 SetViewport(nsIntSize(rect.width, rect.height));
michael@0 594 }
michael@0 595
michael@0 596 void
michael@0 597 LayerManagerD3D10::UpdateRenderTarget()
michael@0 598 {
michael@0 599 if (mRTView || !mSwapChain) {
michael@0 600 return;
michael@0 601 }
michael@0 602
michael@0 603 HRESULT hr;
michael@0 604
michael@0 605 nsRefPtr<ID3D10Texture2D> backBuf;
michael@0 606 hr = mSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)backBuf.StartAssignment());
michael@0 607 if (FAILED(hr)) {
michael@0 608 return;
michael@0 609 }
michael@0 610 mDevice->CreateRenderTargetView(backBuf, nullptr, getter_AddRefs(mRTView));
michael@0 611 }
michael@0 612
michael@0 613 void
michael@0 614 LayerManagerD3D10::VerifyBufferSize()
michael@0 615 {
michael@0 616 nsIntRect rect;
michael@0 617 mWidget->GetClientBounds(rect);
michael@0 618
michael@0 619 if (mSwapChain) {
michael@0 620 DXGI_SWAP_CHAIN_DESC swapDesc;
michael@0 621 mSwapChain->GetDesc(&swapDesc);
michael@0 622
michael@0 623 if (swapDesc.BufferDesc.Width == rect.width &&
michael@0 624 swapDesc.BufferDesc.Height == rect.height) {
michael@0 625 return;
michael@0 626 }
michael@0 627
michael@0 628 mRTView = nullptr;
michael@0 629 if (IsRunningInWindowsMetro()) {
michael@0 630 mSwapChain->ResizeBuffers(2, rect.width, rect.height,
michael@0 631 DXGI_FORMAT_B8G8R8A8_UNORM,
michael@0 632 0);
michael@0 633 mDisableSequenceForNextFrame = true;
michael@0 634 } else if (gfxWindowsPlatform::IsOptimus()) {
michael@0 635 mSwapChain->ResizeBuffers(1, rect.width, rect.height,
michael@0 636 DXGI_FORMAT_B8G8R8A8_UNORM,
michael@0 637 0);
michael@0 638 } else {
michael@0 639 mSwapChain->ResizeBuffers(1, rect.width, rect.height,
michael@0 640 DXGI_FORMAT_B8G8R8A8_UNORM,
michael@0 641 DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE);
michael@0 642 }
michael@0 643 }
michael@0 644 }
michael@0 645
michael@0 646 void
michael@0 647 LayerManagerD3D10::EnsureReadbackManager()
michael@0 648 {
michael@0 649 if (mReadbackManager) {
michael@0 650 return;
michael@0 651 }
michael@0 652
michael@0 653 DeviceAttachments *attachments;
michael@0 654 UINT size = sizeof(DeviceAttachments*);
michael@0 655 if (FAILED(mDevice->GetPrivateData(sDeviceAttachments, &size, &attachments))) {
michael@0 656 // Strange! This shouldn't happen ... return a readback manager for this
michael@0 657 // layer manager only.
michael@0 658 mReadbackManager = new ReadbackManagerD3D10();
michael@0 659 gfx::LogFailure(NS_LITERAL_CSTRING("Couldn't get device attachments for device."));
michael@0 660 return;
michael@0 661 }
michael@0 662
michael@0 663 if (attachments->mReadbackManager) {
michael@0 664 mReadbackManager = attachments->mReadbackManager;
michael@0 665 return;
michael@0 666 }
michael@0 667
michael@0 668 mReadbackManager = new ReadbackManagerD3D10();
michael@0 669 attachments->mReadbackManager = mReadbackManager;
michael@0 670 }
michael@0 671
michael@0 672 void
michael@0 673 LayerManagerD3D10::Render(EndTransactionFlags aFlags)
michael@0 674 {
michael@0 675 static_cast<LayerD3D10*>(mRoot->ImplData())->Validate();
michael@0 676
michael@0 677 if (aFlags & END_NO_COMPOSITE) {
michael@0 678 return;
michael@0 679 }
michael@0 680
michael@0 681 SetupPipeline();
michael@0 682
michael@0 683 float black[] = { 0, 0, 0, 0 };
michael@0 684 device()->ClearRenderTargetView(mRTView, black);
michael@0 685
michael@0 686 nsIntRect rect;
michael@0 687 mWidget->GetClientBounds(rect);
michael@0 688
michael@0 689 const nsIntRect *clipRect = mRoot->GetClipRect();
michael@0 690 D3D10_RECT r;
michael@0 691 if (clipRect) {
michael@0 692 r.left = (LONG)clipRect->x;
michael@0 693 r.top = (LONG)clipRect->y;
michael@0 694 r.right = (LONG)(clipRect->x + clipRect->width);
michael@0 695 r.bottom = (LONG)(clipRect->y + clipRect->height);
michael@0 696 } else {
michael@0 697 r.left = r.top = 0;
michael@0 698 r.right = rect.width;
michael@0 699 r.bottom = rect.height;
michael@0 700 }
michael@0 701 device()->RSSetScissorRects(1, &r);
michael@0 702
michael@0 703 static_cast<LayerD3D10*>(mRoot->ImplData())->RenderLayer();
michael@0 704
michael@0 705 if (!mRegionToClear.IsEmpty()) {
michael@0 706 float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
michael@0 707 gfx::Matrix4x4 transform;
michael@0 708 effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform, 0, 64);
michael@0 709 effect()->GetVariableByName("fLayerColor")->AsVector()->SetFloatVector(color);
michael@0 710
michael@0 711 ID3D10EffectTechnique *technique = effect()->GetTechniqueByName("RenderClearLayer");
michael@0 712
michael@0 713 nsIntRegionRectIterator iter(mRegionToClear);
michael@0 714 const nsIntRect *r;
michael@0 715 while ((r = iter.Next())) {
michael@0 716 effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
michael@0 717 ShaderConstantRectD3D10(
michael@0 718 (float)r->x,
michael@0 719 (float)r->y,
michael@0 720 (float)r->width,
michael@0 721 (float)r->height)
michael@0 722 );
michael@0 723
michael@0 724 technique->GetPassByIndex(0)->Apply(0);
michael@0 725 device()->Draw(4, 0);
michael@0 726 }
michael@0 727 }
michael@0 728
michael@0 729 // See bug 630197 - we have some reasons to believe if an earlier call
michael@0 730 // returned an error, the upcoming present call may raise an exception.
michael@0 731 // This will check if any of the calls done recently has returned an error
michael@0 732 // and bails on composition. On the -next- frame we will then abandon
michael@0 733 // hardware acceleration from gfxWindowsPlatform::VerifyD2DDevice.
michael@0 734 // This might not be the 'optimal' solution but it will help us assert
michael@0 735 // whether our thoughts of the causes of the issues are correct.
michael@0 736 if (FAILED(mDevice->GetDeviceRemovedReason())) {
michael@0 737 return;
michael@0 738 }
michael@0 739
michael@0 740 if (mTarget) {
michael@0 741 PaintToTarget();
michael@0 742 } else {
michael@0 743 mSwapChain->Present(0, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0);
michael@0 744 mDisableSequenceForNextFrame = false;
michael@0 745 }
michael@0 746 RecordFrame();
michael@0 747 PostPresent();
michael@0 748 }
michael@0 749
michael@0 750 void
michael@0 751 LayerManagerD3D10::PaintToTarget()
michael@0 752 {
michael@0 753 nsRefPtr<ID3D10Texture2D> backBuf;
michael@0 754
michael@0 755 mSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)backBuf.StartAssignment());
michael@0 756
michael@0 757 D3D10_TEXTURE2D_DESC bbDesc;
michael@0 758 backBuf->GetDesc(&bbDesc);
michael@0 759
michael@0 760 CD3D10_TEXTURE2D_DESC softDesc(bbDesc.Format, bbDesc.Width, bbDesc.Height);
michael@0 761 softDesc.MipLevels = 1;
michael@0 762 softDesc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
michael@0 763 softDesc.Usage = D3D10_USAGE_STAGING;
michael@0 764 softDesc.BindFlags = 0;
michael@0 765
michael@0 766 nsRefPtr<ID3D10Texture2D> readTexture;
michael@0 767
michael@0 768 HRESULT hr = device()->CreateTexture2D(&softDesc, nullptr, getter_AddRefs(readTexture));
michael@0 769 if (FAILED(hr)) {
michael@0 770 ReportFailure(NS_LITERAL_CSTRING("LayerManagerD3D10::PaintToTarget(): Failed to create texture"),
michael@0 771 hr);
michael@0 772 return;
michael@0 773 }
michael@0 774
michael@0 775 device()->CopyResource(readTexture, backBuf);
michael@0 776
michael@0 777 D3D10_MAPPED_TEXTURE2D map;
michael@0 778 readTexture->Map(0, D3D10_MAP_READ, 0, &map);
michael@0 779
michael@0 780 nsRefPtr<gfxImageSurface> tmpSurface =
michael@0 781 new gfxImageSurface((unsigned char*)map.pData,
michael@0 782 gfxIntSize(bbDesc.Width, bbDesc.Height),
michael@0 783 map.RowPitch,
michael@0 784 gfxImageFormat::ARGB32);
michael@0 785
michael@0 786 mTarget->SetSource(tmpSurface);
michael@0 787 mTarget->SetOperator(gfxContext::OPERATOR_OVER);
michael@0 788 mTarget->Paint();
michael@0 789
michael@0 790 readTexture->Unmap(0);
michael@0 791 }
michael@0 792
michael@0 793 void
michael@0 794 LayerManagerD3D10::ReportFailure(const nsACString &aMsg, HRESULT aCode)
michael@0 795 {
michael@0 796 // We could choose to abort here when hr == E_OUTOFMEMORY.
michael@0 797 nsCString msg;
michael@0 798 msg.Append(aMsg);
michael@0 799 msg.AppendLiteral(" Error code: ");
michael@0 800 msg.AppendInt(uint32_t(aCode));
michael@0 801 NS_WARNING(msg.BeginReading());
michael@0 802
michael@0 803 gfx::LogFailure(msg);
michael@0 804 }
michael@0 805
michael@0 806 LayerD3D10::LayerD3D10(LayerManagerD3D10 *aManager)
michael@0 807 : mD3DManager(aManager)
michael@0 808 {
michael@0 809 }
michael@0 810
michael@0 811 ID3D10EffectTechnique*
michael@0 812 LayerD3D10::SelectShader(uint8_t aFlags)
michael@0 813 {
michael@0 814 switch (aFlags) {
michael@0 815 case (SHADER_RGBA | SHADER_NON_PREMUL | SHADER_LINEAR | SHADER_MASK):
michael@0 816 return effect()->GetTechniqueByName("RenderRGBALayerNonPremulMask");
michael@0 817 case (SHADER_RGBA | SHADER_NON_PREMUL | SHADER_LINEAR | SHADER_NO_MASK):
michael@0 818 return effect()->GetTechniqueByName("RenderRGBALayerNonPremul");
michael@0 819 case (SHADER_RGBA | SHADER_NON_PREMUL | SHADER_POINT | SHADER_NO_MASK):
michael@0 820 return effect()->GetTechniqueByName("RenderRGBALayerNonPremulPoint");
michael@0 821 case (SHADER_RGBA | SHADER_NON_PREMUL | SHADER_POINT | SHADER_MASK):
michael@0 822 return effect()->GetTechniqueByName("RenderRGBALayerNonPremulPointMask");
michael@0 823 case (SHADER_RGBA | SHADER_PREMUL | SHADER_LINEAR | SHADER_MASK_3D):
michael@0 824 return effect()->GetTechniqueByName("RenderRGBALayerPremulMask3D");
michael@0 825 case (SHADER_RGBA | SHADER_PREMUL | SHADER_LINEAR | SHADER_MASK):
michael@0 826 return effect()->GetTechniqueByName("RenderRGBALayerPremulMask");
michael@0 827 case (SHADER_RGBA | SHADER_PREMUL | SHADER_LINEAR | SHADER_NO_MASK):
michael@0 828 return effect()->GetTechniqueByName("RenderRGBALayerPremul");
michael@0 829 case (SHADER_RGBA | SHADER_PREMUL | SHADER_POINT | SHADER_MASK):
michael@0 830 return effect()->GetTechniqueByName("RenderRGBALayerPremulPointMask");
michael@0 831 case (SHADER_RGBA | SHADER_PREMUL | SHADER_POINT | SHADER_NO_MASK):
michael@0 832 return effect()->GetTechniqueByName("RenderRGBALayerPremulPoint");
michael@0 833 case (SHADER_RGB | SHADER_PREMUL | SHADER_POINT | SHADER_MASK):
michael@0 834 return effect()->GetTechniqueByName("RenderRGBLayerPremulPointMask");
michael@0 835 case (SHADER_RGB | SHADER_PREMUL | SHADER_POINT | SHADER_NO_MASK):
michael@0 836 return effect()->GetTechniqueByName("RenderRGBLayerPremulPoint");
michael@0 837 case (SHADER_RGB | SHADER_PREMUL | SHADER_LINEAR | SHADER_MASK):
michael@0 838 return effect()->GetTechniqueByName("RenderRGBLayerPremulMask");
michael@0 839 case (SHADER_RGB | SHADER_PREMUL | SHADER_LINEAR | SHADER_NO_MASK):
michael@0 840 return effect()->GetTechniqueByName("RenderRGBLayerPremul");
michael@0 841 case (SHADER_SOLID | SHADER_MASK):
michael@0 842 return effect()->GetTechniqueByName("RenderSolidColorLayerMask");
michael@0 843 case (SHADER_SOLID | SHADER_NO_MASK):
michael@0 844 return effect()->GetTechniqueByName("RenderSolidColorLayer");
michael@0 845 case (SHADER_COMPONENT_ALPHA | SHADER_MASK):
michael@0 846 return effect()->GetTechniqueByName("RenderComponentAlphaLayerMask");
michael@0 847 case (SHADER_COMPONENT_ALPHA | SHADER_NO_MASK):
michael@0 848 return effect()->GetTechniqueByName("RenderComponentAlphaLayer");
michael@0 849 case (SHADER_YCBCR | SHADER_MASK):
michael@0 850 return effect()->GetTechniqueByName("RenderYCbCrLayerMask");
michael@0 851 case (SHADER_YCBCR | SHADER_NO_MASK):
michael@0 852 return effect()->GetTechniqueByName("RenderYCbCrLayer");
michael@0 853 default:
michael@0 854 NS_ERROR("Invalid shader.");
michael@0 855 return nullptr;
michael@0 856 }
michael@0 857 }
michael@0 858
michael@0 859 uint8_t
michael@0 860 LayerD3D10::LoadMaskTexture()
michael@0 861 {
michael@0 862 if (Layer* maskLayer = GetLayer()->GetMaskLayer()) {
michael@0 863 IntSize size;
michael@0 864 nsRefPtr<ID3D10ShaderResourceView> maskSRV =
michael@0 865 static_cast<LayerD3D10*>(maskLayer->ImplData())->GetAsTexture(&size);
michael@0 866
michael@0 867 if (!maskSRV) {
michael@0 868 return SHADER_NO_MASK;
michael@0 869 }
michael@0 870
michael@0 871 Matrix maskTransform;
michael@0 872 Matrix4x4 effectiveTransform = maskLayer->GetEffectiveTransform();
michael@0 873 bool maskIs2D = effectiveTransform.CanDraw2D(&maskTransform);
michael@0 874 NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
michael@0 875 Rect bounds = Rect(Point(), Size(size));
michael@0 876 bounds = maskTransform.TransformBounds(bounds);
michael@0 877
michael@0 878 effect()->GetVariableByName("vMaskQuad")->AsVector()->SetFloatVector(
michael@0 879 ShaderConstantRectD3D10(
michael@0 880 (float)bounds.x,
michael@0 881 (float)bounds.y,
michael@0 882 (float)bounds.width,
michael@0 883 (float)bounds.height)
michael@0 884 );
michael@0 885
michael@0 886 effect()->GetVariableByName("tMask")->AsShaderResource()->SetResource(maskSRV);
michael@0 887 return SHADER_MASK;
michael@0 888 }
michael@0 889
michael@0 890 return SHADER_NO_MASK;
michael@0 891 }
michael@0 892
michael@0 893 }
michael@0 894 }

mercurial