gfx/layers/d3d10/ReadbackManagerD3D10.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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 "ReadbackManagerD3D10.h"
michael@0 7 #include "ReadbackProcessor.h"
michael@0 8 #include "ReadbackLayer.h"
michael@0 9
michael@0 10 #include "nsIThread.h"
michael@0 11 #include "nsThreadUtils.h"
michael@0 12 #include "gfxImageSurface.h"
michael@0 13 #include "gfxContext.h"
michael@0 14
michael@0 15 namespace mozilla {
michael@0 16 namespace layers {
michael@0 17
michael@0 18 // Structure that contains the information required to execute a readback task,
michael@0 19 // the only member accessed off the main thread here is mReadbackTexture. Since
michael@0 20 // mLayer may be released only on the main thread this object should always be
michael@0 21 // destroyed on the main thread!
michael@0 22 struct ReadbackTask {
michael@0 23 // The texture that we copied the contents of the thebeslayer to.
michael@0 24 nsRefPtr<ID3D10Texture2D> mReadbackTexture;
michael@0 25 // This exists purely to keep the ReadbackLayer alive for the lifetime of
michael@0 26 // mUpdate. Note that this addref and release should occur -solely- on the
michael@0 27 // main thread.
michael@0 28 nsRefPtr<ReadbackLayer> mLayer;
michael@0 29 ReadbackProcessor::Update mUpdate;
michael@0 30 // The origin in ThebesLayer coordinates of mReadbackTexture.
michael@0 31 gfxPoint mOrigin;
michael@0 32 // mLayer->GetBackgroundOffset() when the task is created. We have
michael@0 33 // to save this in the ReadbackTask because it might change before
michael@0 34 // the update is delivered to the readback sink.
michael@0 35 nsIntPoint mBackgroundOffset;
michael@0 36 };
michael@0 37
michael@0 38 // This class is created and dispatched from the Readback thread but it must be
michael@0 39 // destroyed by the main thread.
michael@0 40 class ReadbackResultWriter MOZ_FINAL : public nsIRunnable
michael@0 41 {
michael@0 42 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 43 public:
michael@0 44 ReadbackResultWriter(ReadbackTask *aTask) : mTask(aTask) {}
michael@0 45
michael@0 46 NS_IMETHODIMP Run()
michael@0 47 {
michael@0 48 ReadbackProcessor::Update *update = &mTask->mUpdate;
michael@0 49
michael@0 50 if (!update->mLayer->GetSink()) {
michael@0 51 // This can happen when a plugin is destroyed.
michael@0 52 return NS_OK;
michael@0 53 }
michael@0 54
michael@0 55 nsIntPoint offset = mTask->mBackgroundOffset;
michael@0 56
michael@0 57 D3D10_TEXTURE2D_DESC desc;
michael@0 58 mTask->mReadbackTexture->GetDesc(&desc);
michael@0 59
michael@0 60 D3D10_MAPPED_TEXTURE2D mappedTex;
michael@0 61 // We know this map will immediately succeed, as we've already mapped this
michael@0 62 // copied data on our task thread.
michael@0 63 HRESULT hr = mTask->mReadbackTexture->Map(0, D3D10_MAP_READ, 0, &mappedTex);
michael@0 64
michael@0 65 if (FAILED(hr)) {
michael@0 66 // If this fails we're never going to get our ThebesLayer content.
michael@0 67 update->mLayer->GetSink()->SetUnknown(update->mSequenceCounter);
michael@0 68 return NS_OK;
michael@0 69 }
michael@0 70
michael@0 71 nsRefPtr<gfxImageSurface> sourceSurface =
michael@0 72 new gfxImageSurface((unsigned char*)mappedTex.pData,
michael@0 73 gfxIntSize(desc.Width, desc.Height),
michael@0 74 mappedTex.RowPitch,
michael@0 75 gfxImageFormat::RGB24);
michael@0 76
michael@0 77 nsRefPtr<gfxContext> ctx =
michael@0 78 update->mLayer->GetSink()->BeginUpdate(update->mUpdateRect + offset,
michael@0 79 update->mSequenceCounter);
michael@0 80
michael@0 81 if (ctx) {
michael@0 82 ctx->Translate(gfxPoint(offset.x, offset.y));
michael@0 83 ctx->SetSource(sourceSurface, gfxPoint(mTask->mOrigin.x,
michael@0 84 mTask->mOrigin.y));
michael@0 85 ctx->Paint();
michael@0 86
michael@0 87 update->mLayer->GetSink()->EndUpdate(ctx, update->mUpdateRect + offset);
michael@0 88 }
michael@0 89
michael@0 90 mTask->mReadbackTexture->Unmap(0);
michael@0 91
michael@0 92 return NS_OK;
michael@0 93 }
michael@0 94
michael@0 95 private:
michael@0 96 nsAutoPtr<ReadbackTask> mTask;
michael@0 97 };
michael@0 98
michael@0 99 NS_IMPL_ISUPPORTS(ReadbackResultWriter, nsIRunnable)
michael@0 100
michael@0 101 DWORD WINAPI StartTaskThread(void *aManager)
michael@0 102 {
michael@0 103 static_cast<ReadbackManagerD3D10*>(aManager)->ProcessTasks();
michael@0 104
michael@0 105 return 0;
michael@0 106 }
michael@0 107
michael@0 108 ReadbackManagerD3D10::ReadbackManagerD3D10()
michael@0 109 : mRefCnt(0)
michael@0 110 {
michael@0 111 ::InitializeCriticalSection(&mTaskMutex);
michael@0 112 mShutdownEvent = ::CreateEventA(nullptr, FALSE, FALSE, nullptr);
michael@0 113 mTaskSemaphore = ::CreateSemaphoreA(nullptr, 0, 1000000, nullptr);
michael@0 114 mTaskThread = ::CreateThread(nullptr, 0, StartTaskThread, this, 0, 0);
michael@0 115 }
michael@0 116
michael@0 117 ReadbackManagerD3D10::~ReadbackManagerD3D10()
michael@0 118 {
michael@0 119 ::SetEvent(mShutdownEvent);
michael@0 120
michael@0 121 // This shouldn't take longer than 5 seconds, if it does we're going to choose
michael@0 122 // to leak the thread and its synchronisation in favor of crashing or freezing
michael@0 123 DWORD result = ::WaitForSingleObject(mTaskThread, 5000);
michael@0 124 if (result != WAIT_TIMEOUT) {
michael@0 125 ::DeleteCriticalSection(&mTaskMutex);
michael@0 126 ::CloseHandle(mShutdownEvent);
michael@0 127 ::CloseHandle(mTaskSemaphore);
michael@0 128 ::CloseHandle(mTaskThread);
michael@0 129 } else {
michael@0 130 NS_RUNTIMEABORT("ReadbackManager: Task thread did not shutdown in 5 seconds.");
michael@0 131 }
michael@0 132 }
michael@0 133
michael@0 134 void
michael@0 135 ReadbackManagerD3D10::PostTask(ID3D10Texture2D *aTexture, void *aUpdate, const gfxPoint &aOrigin)
michael@0 136 {
michael@0 137 ReadbackTask *task = new ReadbackTask;
michael@0 138 task->mReadbackTexture = aTexture;
michael@0 139 task->mUpdate = *static_cast<ReadbackProcessor::Update*>(aUpdate);
michael@0 140 task->mOrigin = aOrigin;
michael@0 141 task->mLayer = task->mUpdate.mLayer;
michael@0 142 task->mBackgroundOffset = task->mLayer->GetBackgroundLayerOffset();
michael@0 143
michael@0 144 ::EnterCriticalSection(&mTaskMutex);
michael@0 145 mPendingReadbackTasks.AppendElement(task);
michael@0 146 ::LeaveCriticalSection(&mTaskMutex);
michael@0 147
michael@0 148 ::ReleaseSemaphore(mTaskSemaphore, 1, nullptr);
michael@0 149 }
michael@0 150
michael@0 151 HRESULT
michael@0 152 ReadbackManagerD3D10::QueryInterface(REFIID riid, void **ppvObject)
michael@0 153 {
michael@0 154 if (!ppvObject) {
michael@0 155 return E_POINTER;
michael@0 156 }
michael@0 157
michael@0 158 if (riid == IID_IUnknown) {
michael@0 159 *ppvObject = this;
michael@0 160 } else {
michael@0 161 return E_NOINTERFACE;
michael@0 162 }
michael@0 163
michael@0 164 return S_OK;
michael@0 165 }
michael@0 166
michael@0 167 ULONG
michael@0 168 ReadbackManagerD3D10::AddRef()
michael@0 169 {
michael@0 170 NS_ASSERTION(NS_IsMainThread(),
michael@0 171 "ReadbackManagerD3D10 should only be refcounted on main thread.");
michael@0 172 return ++mRefCnt;
michael@0 173 }
michael@0 174
michael@0 175 ULONG
michael@0 176 ReadbackManagerD3D10::Release()
michael@0 177 {
michael@0 178 NS_ASSERTION(NS_IsMainThread(),
michael@0 179 "ReadbackManagerD3D10 should only be refcounted on main thread.");
michael@0 180 ULONG newRefCnt = --mRefCnt;
michael@0 181 if (!newRefCnt) {
michael@0 182 mRefCnt++;
michael@0 183 delete this;
michael@0 184 }
michael@0 185 return newRefCnt;
michael@0 186 }
michael@0 187
michael@0 188 void
michael@0 189 ReadbackManagerD3D10::ProcessTasks()
michael@0 190 {
michael@0 191 HANDLE handles[] = { mTaskSemaphore, mShutdownEvent };
michael@0 192
michael@0 193 while (true) {
michael@0 194 DWORD result = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
michael@0 195 if (result != WAIT_OBJECT_0) {
michael@0 196 return;
michael@0 197 }
michael@0 198
michael@0 199 ::EnterCriticalSection(&mTaskMutex);
michael@0 200 if (mPendingReadbackTasks.Length() == 0) {
michael@0 201 NS_RUNTIMEABORT("Trying to read from an empty array, bad bad bad");
michael@0 202 }
michael@0 203 ReadbackTask *nextReadbackTask = mPendingReadbackTasks[0].forget();
michael@0 204 mPendingReadbackTasks.RemoveElementAt(0);
michael@0 205 ::LeaveCriticalSection(&mTaskMutex);
michael@0 206
michael@0 207 // We want to block here until the texture contents are available, the
michael@0 208 // easiest thing is to simply map and unmap.
michael@0 209 D3D10_MAPPED_TEXTURE2D mappedTex;
michael@0 210 nextReadbackTask->mReadbackTexture->Map(0, D3D10_MAP_READ, 0, &mappedTex);
michael@0 211 nextReadbackTask->mReadbackTexture->Unmap(0);
michael@0 212
michael@0 213 // We can only send the update to the sink on the main thread, so post an
michael@0 214 // event there to do so. Ownership of the task is passed from
michael@0 215 // mPendingReadbackTasks to ReadbackResultWriter here.
michael@0 216 nsCOMPtr<nsIThread> thread = do_GetMainThread();
michael@0 217 thread->Dispatch(new ReadbackResultWriter(nextReadbackTask),
michael@0 218 nsIEventTarget::DISPATCH_NORMAL);
michael@0 219 }
michael@0 220 }
michael@0 221
michael@0 222 }
michael@0 223 }

mercurial