Bug 626602, part 6: Implement asynchronous D3D10 readback. r=cjones,jrmuizel

This commit is contained in:
Bas Schouten 2011-02-04 20:30:00 -06:00
parent 3034c9b8d3
commit f732d2dcac
9 changed files with 569 additions and 25 deletions

View File

@ -112,6 +112,7 @@ endif
ifdef MOZ_ENABLE_D3D10_LAYER
EXPORTS += \
LayerManagerD3D10.h \
ReadbackManagerD3D10.h \
$(NULL)
CPPSRCS += \
@ -121,6 +122,7 @@ CPPSRCS += \
ImageLayerD3D10.cpp \
ColorLayerD3D10.cpp \
CanvasLayerD3D10.cpp \
ReadbackManagerD3D10.cpp \
$(NULL)
endif
endif

View File

@ -40,6 +40,9 @@
#include "gfxUtils.h"
#include "nsRect.h"
#include "ThebesLayerD3D10.h"
#include "ReadbackProcessor.h"
namespace mozilla {
namespace layers {
@ -402,9 +405,16 @@ ContainerLayerD3D10::Validate()
(mParent && mParent->SupportsComponentAlphaChildren());
}
ReadbackProcessor readback;
readback.BuildUpdates(this);
Layer *layer = GetFirstChild();
while (layer) {
static_cast<LayerD3D10*>(layer->ImplData())->Validate();
if (layer->GetType() == TYPE_THEBES) {
static_cast<ThebesLayerD3D10*>(layer)->Validate(&readback);
} else {
static_cast<LayerD3D10*>(layer->ImplData())->Validate();
}
layer = layer->GetNextSibling();
}
}

View File

@ -47,6 +47,7 @@
#include "ThebesLayerD3D10.h"
#include "ColorLayerD3D10.h"
#include "CanvasLayerD3D10.h"
#include "ReadbackLayerD3D10.h"
#include "ImageLayerD3D10.h"
#include "../d3d9/Nv3DVUtils.h"
@ -68,15 +69,12 @@ struct Vertex
float position[2];
};
// {17F88CCB-1F49-4c08-8002-ADA7BD44856D}
static const GUID sEffect =
{ 0x17f88ccb, 0x1f49, 0x4c08, { 0x80, 0x2, 0xad, 0xa7, 0xbd, 0x44, 0x85, 0x6d } };
// {19599D91-912C-4C2F-A8C5-299DE85FBD34}
static const GUID sInputLayout =
{ 0x19599d91, 0x912c, 0x4c2f, { 0xa8, 0xc5, 0x29, 0x9d, 0xe8, 0x5f, 0xbd, 0x34 } };
// {293157D2-09C7-4680-AE27-C28E370E418B}
static const GUID sVertexBuffer =
{ 0x293157d2, 0x9c7, 0x4680, { 0xae, 0x27, 0xc2, 0x8e, 0x37, 0xe, 0x41, 0x8b } };
// {592BF306-0EED-4F76-9D03-A0846450F472}
static const GUID sDeviceAttachments =
{ 0x592bf306, 0xeed, 0x4f76, { 0x9d, 0x3, 0xa0, 0x84, 0x64, 0x50, 0xf4, 0x72 } };
// {716AEDB1-C9C3-4B4D-8332-6F65D44AF6A8}
static const GUID sLayerManagerCount =
{ 0x716aedb1, 0xc9c3, 0x4b4d, { 0x83, 0x32, 0x6f, 0x65, 0xd4, 0x4a, 0xf6, 0xa8 } };
cairo_user_data_key_t gKeyD3D10Texture;
@ -85,8 +83,36 @@ LayerManagerD3D10::LayerManagerD3D10(nsIWidget *aWidget)
{
}
struct DeviceAttachments
{
nsRefPtr<ID3D10Effect> mEffect;
nsRefPtr<ID3D10InputLayout> mInputLayout;
nsRefPtr<ID3D10Buffer> mVertexBuffer;
nsRefPtr<ReadbackManagerD3D10> mReadbackManager;
};
LayerManagerD3D10::~LayerManagerD3D10()
{
if (mDevice) {
int referenceCount = 0;
UINT size = sizeof(referenceCount);
HRESULT hr = mDevice->GetPrivateData(sLayerManagerCount, &size, &referenceCount);
NS_ASSERTION(SUCCEEDED(hr), "Reference count not found on device.");
referenceCount--;
mDevice->SetPrivateData(sLayerManagerCount, sizeof(referenceCount), &referenceCount);
if (!referenceCount) {
DeviceAttachments *attachments;
size = sizeof(attachments);
mDevice->GetPrivateData(sDeviceAttachments, &size, &attachments);
// No LayerManagers left for this device. Clear out interfaces stored which
// hold a reference to the device.
mDevice->SetPrivateData(sDeviceAttachments, 0, NULL);
delete attachments;
}
}
Destroy();
}
@ -130,8 +156,19 @@ LayerManagerD3D10::Initialize()
mNv3DVUtils->SetDeviceInfo(devUnknown);
}
UINT size = sizeof(ID3D10Effect*);
if (FAILED(mDevice->GetPrivateData(sEffect, &size, mEffect.StartAssignment()))) {
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);
DeviceAttachments *attachments;
size = sizeof(DeviceAttachments*);
if (FAILED(mDevice->GetPrivateData(sDeviceAttachments, &size, &attachments))) {
attachments = new DeviceAttachments;
mDevice->SetPrivateData(sDeviceAttachments, sizeof(attachments), &attachments);
D3D10CreateEffectFromMemoryFunc createEffect = (D3D10CreateEffectFromMemoryFunc)
GetProcAddress(LoadLibraryA("d3d10_1.dll"), "D3D10CreateEffectFromMemory");
@ -150,11 +187,8 @@ LayerManagerD3D10::Initialize()
return false;
}
mDevice->SetPrivateDataInterface(sEffect, mEffect);
}
size = sizeof(ID3D10InputLayout*);
if (FAILED(mDevice->GetPrivateData(sInputLayout, &size, mInputLayout.StartAssignment()))) {
attachments->mEffect = mEffect;
D3D10_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
@ -173,11 +207,8 @@ LayerManagerD3D10::Initialize()
return false;
}
mDevice->SetPrivateDataInterface(sInputLayout, mInputLayout);
}
size = sizeof(ID3D10Buffer*);
if (FAILED(mDevice->GetPrivateData(sVertexBuffer, &size, mVertexBuffer.StartAssignment()))) {
attachments->mInputLayout = mInputLayout;
Vertex vertices[] = { {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0} };
CD3D10_BUFFER_DESC bufferDesc(sizeof(vertices), D3D10_BIND_VERTEX_BUFFER);
D3D10_SUBRESOURCE_DATA data;
@ -189,7 +220,11 @@ LayerManagerD3D10::Initialize()
return false;
}
mDevice->SetPrivateDataInterface(sVertexBuffer, mVertexBuffer);
attachments->mVertexBuffer = mVertexBuffer;
} else {
mEffect = attachments->mEffect;
mVertexBuffer = attachments->mVertexBuffer;
mInputLayout = attachments->mInputLayout;
}
nsRefPtr<IDXGIDevice> dxgiDevice;
@ -337,6 +372,13 @@ LayerManagerD3D10::CreateCanvasLayer()
return layer.forget();
}
already_AddRefed<ReadbackLayer>
LayerManagerD3D10::CreateReadbackLayer()
{
nsRefPtr<ReadbackLayer> layer = new ReadbackLayerD3D10(this);
return layer.forget();
}
already_AddRefed<ImageContainer>
LayerManagerD3D10::CreateImageContainer()
{
@ -386,6 +428,13 @@ LayerManagerD3D10::CreateOptimalSurface(const gfxIntSize &aSize,
return surface.forget();
}
ReadbackManagerD3D10*
LayerManagerD3D10::readbackManager()
{
EnsureReadbackManager();
return mReadbackManager;
}
void
LayerManagerD3D10::SetViewport(const nsIntSize &aViewport)
{
@ -499,6 +548,32 @@ LayerManagerD3D10::VerifyBufferSize()
}
void
LayerManagerD3D10::EnsureReadbackManager()
{
if (mReadbackManager) {
return;
}
DeviceAttachments *attachments;
UINT size = sizeof(DeviceAttachments*);
if (FAILED(mDevice->GetPrivateData(sDeviceAttachments, &size, &attachments))) {
// Strange! This shouldn't happen ... return a readback manager for this
// layer manager only.
mReadbackManager = new ReadbackManagerD3D10();
gfx::LogFailure(NS_LITERAL_CSTRING("Couldn't get device attachments for device."));
return;
}
if (attachments->mReadbackManager) {
mReadbackManager = attachments->mReadbackManager;
return;
}
mReadbackManager = new ReadbackManagerD3D10();
attachments->mReadbackManager = mReadbackManager;
}
void
LayerManagerD3D10::Render()
{

View File

@ -46,6 +46,8 @@
#include "gfxContext.h"
#include "nsIWidget.h"
#include "ReadbackManagerD3D10.h"
namespace mozilla {
namespace layers {
@ -123,6 +125,8 @@ public:
virtual already_AddRefed<CanvasLayer> CreateCanvasLayer();
virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer();
virtual already_AddRefed<ImageContainer> CreateImageContainer();
virtual already_AddRefed<gfxASurface>
@ -142,6 +146,8 @@ public:
ID3D10Effect *effect() const { return mEffect; }
ReadbackManagerD3D10 *readbackManager();
void SetViewport(const nsIntSize &aViewport);
const nsIntSize &GetViewport() { return mViewport; }
@ -156,6 +162,7 @@ private:
void SetupPipeline();
void UpdateRenderTarget();
void VerifyBufferSize();
void EnsureReadbackManager();
void Render();
@ -164,6 +171,7 @@ private:
nsRefPtr<ID3D10Effect> mEffect;
nsRefPtr<ID3D10InputLayout> mInputLayout;
nsRefPtr<ID3D10Buffer> mVertexBuffer;
nsRefPtr<ReadbackManagerD3D10> mReadbackManager;
nsRefPtr<ID3D10RenderTargetView> mRTView;

View File

@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bas Schouten <bschouten@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef GFX_READBACKLAYERD3D10_H
#define GFX_READBACKLAYERD3D10_H
#include "LayerManagerD3D10.h"
#include "ReadbackLayer.h"
namespace mozilla {
namespace layers {
class THEBES_API ReadbackLayerD3D10 :
public ReadbackLayer,
public LayerD3D10
{
public:
ReadbackLayerD3D10(LayerManagerD3D10 *aManager)
: ReadbackLayer(aManager, NULL),
LayerD3D10(aManager)
{
mImplData = static_cast<LayerD3D10*>(this);
}
virtual Layer* GetLayer() { return this; }
virtual void RenderLayer() {}
};
} /* layers */
} /* mozilla */
#endif /* GFX_READBACKLAYERD3D10_H */

View File

@ -0,0 +1,250 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bas Schouten <bschouten@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "ReadbackManagerD3D10.h"
#include "ReadbackProcessor.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"
#include "gfxImageSurface.h"
namespace mozilla {
namespace layers {
// Structure that contains the information required to execute a readback task,
// the only member accessed off the main thread here is mReadbackTexture. Since
// mLayer may be released only on the main thread this object should always be
// destroyed on the main thread!
struct ReadbackTask {
// The texture that we copied the contents of the thebeslayer to.
nsRefPtr<ID3D10Texture2D> mReadbackTexture;
// This exists purely to keep the ReadbackLayer alive for the lifetime of
// mUpdate. Note that this addref and release should occur -solely- on the
// main thread.
nsRefPtr<ReadbackLayer> mLayer;
ReadbackProcessor::Update mUpdate;
// The origin in ThebesLayer coordinates of mReadbackTexture.
gfxPoint mOrigin;
// mLayer->GetBackgroundOffset() when the task is created. We have
// to save this in the ReadbackTask because it might change before
// the update is delivered to the readback sink.
nsIntPoint mBackgroundOffset;
};
// This class is created and dispatched from the Readback thread but it must be
// destroyed by the main thread.
class ReadbackResultWriter : public nsIRunnable
{
NS_DECL_ISUPPORTS
public:
ReadbackResultWriter(ReadbackTask *aTask) : mTask(aTask) {}
NS_IMETHODIMP Run()
{
ReadbackProcessor::Update *update = &mTask->mUpdate;
if (!update->mLayer->GetSink()) {
// This can happen when a plugin is destroyed.
return NS_OK;
}
nsIntPoint offset = mTask->mBackgroundOffset;
D3D10_TEXTURE2D_DESC desc;
mTask->mReadbackTexture->GetDesc(&desc);
D3D10_MAPPED_TEXTURE2D mappedTex;
// We know this map will immediately succeed, as we've already mapped this
// copied data on our task thread.
HRESULT hr = mTask->mReadbackTexture->Map(0, D3D10_MAP_READ, 0, &mappedTex);
if (FAILED(hr)) {
// If this fails we're never going to get our ThebesLayer content.
update->mLayer->GetSink()->SetUnknown(update->mSequenceCounter);
return NS_OK;
}
nsRefPtr<gfxImageSurface> sourceSurface =
new gfxImageSurface((unsigned char*)mappedTex.pData,
gfxIntSize(desc.Width, desc.Height),
mappedTex.RowPitch,
gfxASurface::ImageFormatRGB24);
nsRefPtr<gfxContext> ctx =
update->mLayer->GetSink()->BeginUpdate(update->mUpdateRect + offset,
update->mSequenceCounter);
if (ctx) {
ctx->Translate(gfxPoint(offset.x, offset.y));
ctx->SetSource(sourceSurface, gfxPoint(mTask->mOrigin.x,
mTask->mOrigin.y));
ctx->Paint();
update->mLayer->GetSink()->EndUpdate(ctx, update->mUpdateRect + offset);
}
mTask->mReadbackTexture->Unmap(0);
return NS_OK;
}
private:
nsAutoPtr<ReadbackTask> mTask;
};
NS_IMPL_THREADSAFE_ISUPPORTS1(ReadbackResultWriter, nsIRunnable)
DWORD WINAPI StartTaskThread(void *aManager)
{
static_cast<ReadbackManagerD3D10*>(aManager)->ProcessTasks();
return 0;
}
ReadbackManagerD3D10::ReadbackManagerD3D10()
: mRefCnt(0)
{
::InitializeCriticalSection(&mTaskMutex);
mShutdownEvent = ::CreateEventA(NULL, FALSE, FALSE, "ReadbackShutdownEvent");
mTaskSemaphore = ::CreateSemaphoreA(NULL, 0, 1000000, "ReadbackTaskSemaphore");
mTaskThread = ::CreateThread(NULL, 0, StartTaskThread, this, 0, 0);
}
ReadbackManagerD3D10::~ReadbackManagerD3D10()
{
::SetEvent(mShutdownEvent);
// This shouldn't take longer than 5 seconds, if it does we're going to choose
// to leak the thread and its synchronisation in favor of crashing or freezing
DWORD result = ::WaitForSingleObject(mTaskThread, 5000);
if (result != WAIT_TIMEOUT) {
::DeleteCriticalSection(&mTaskMutex);
::CloseHandle(mShutdownEvent);
::CloseHandle(mTaskSemaphore);
::CloseHandle(mTaskThread);
} else {
NS_WARNING("ReadbackManager: Task thread did not shutdown in 5 seconds. Leaking.");
}
}
void
ReadbackManagerD3D10::PostTask(ID3D10Texture2D *aTexture, void *aUpdate, const gfxPoint &aOrigin)
{
ReadbackTask *task = new ReadbackTask;
task->mReadbackTexture = aTexture;
task->mUpdate = *static_cast<ReadbackProcessor::Update*>(aUpdate);
task->mOrigin = aOrigin;
task->mLayer = task->mUpdate.mLayer;
task->mBackgroundOffset = task->mLayer->GetBackgroundLayerOffset();
::EnterCriticalSection(&mTaskMutex);
mPendingReadbackTasks.AppendElement(task);
::LeaveCriticalSection(&mTaskMutex);
::ReleaseSemaphore(mTaskSemaphore, 1, NULL);
}
HRESULT
ReadbackManagerD3D10::QueryInterface(REFIID riid, void **ppvObject)
{
if (!ppvObject) {
return E_POINTER;
}
if (riid == IID_IUnknown) {
*ppvObject = this;
} else {
return E_NOINTERFACE;
}
return S_OK;
}
ULONG
ReadbackManagerD3D10::AddRef()
{
NS_ASSERTION(NS_IsMainThread(),
"ReadbackManagerD3D10 should only be refcounted on main thread.");
return ++mRefCnt;
}
ULONG
ReadbackManagerD3D10::Release()
{
NS_ASSERTION(NS_IsMainThread(),
"ReadbackManagerD3D10 should only be refcounted on main thread.");
ULONG newRefCnt = --mRefCnt;
if (!newRefCnt) {
mRefCnt++;
delete this;
}
return newRefCnt;
}
void
ReadbackManagerD3D10::ProcessTasks()
{
HANDLE handles[] = { mTaskSemaphore, mShutdownEvent };
while (true) {
DWORD result = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (result != WAIT_OBJECT_0) {
return;
}
::EnterCriticalSection(&mTaskMutex);
ReadbackTask *nextReadbackTask = mPendingReadbackTasks[0].forget();
mPendingReadbackTasks.RemoveElementAt(0);
::LeaveCriticalSection(&mTaskMutex);
// We want to block here until the texture contents are available, the
// easiest thing is to simply map and unmap.
D3D10_MAPPED_TEXTURE2D mappedTex;
nextReadbackTask->mReadbackTexture->Map(0, D3D10_MAP_READ, 0, &mappedTex);
nextReadbackTask->mReadbackTexture->Unmap(0);
// We can only send the update to the sink on the main thread, so post an
// event there to do so. Ownership of the task is passed from
// mPendingReadbackTasks to ReadbackResultWriter here.
nsCOMPtr<nsIThread> thread = do_GetMainThread();
thread->Dispatch(new ReadbackResultWriter(nextReadbackTask),
nsIEventTarget::DISPATCH_NORMAL);
}
}
}
}

View File

@ -0,0 +1,107 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bas Schouten <bschouten@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef GFX_READBACKMANAGERD3D10_H
#define GFX_READBACKMANAGERD3D10_H
#include <windows.h>
#include <d3d10_1.h>
#include "nsTArray.h"
#include "nsAutoPtr.h"
#include "gfxPoint.h"
namespace mozilla {
namespace layers {
DWORD WINAPI StartTaskThread(void *aManager);
struct ReadbackTask;
class ReadbackManagerD3D10 : public IUnknown
{
public:
ReadbackManagerD3D10();
~ReadbackManagerD3D10();
/**
* Tell the readback manager to post a readback task.
*
* @param aTexture D3D10_USAGE_STAGING texture that will contain the data that
* was readback.
* @param aUpdate ReadbackProcessor::Update object. This is a void pointer
* since we cannot forward declare a nested class, and do not
* export ReadbackProcessor.h
* @param aOrigin Origin of the aTexture surface in the ThebesLayer
* coordinate system.
*/
void PostTask(ID3D10Texture2D *aTexture, void *aUpdate, const gfxPoint &aOrigin);
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
void **ppvObject);
virtual ULONG STDMETHODCALLTYPE AddRef(void);
virtual ULONG STDMETHODCALLTYPE Release(void);
private:
friend DWORD WINAPI StartTaskThread(void *aManager);
void ProcessTasks();
// The invariant maintained by |mTaskSemaphore| is that the readback thread
// will awaken from WaitForMultipleObjects() at least once per readback
// task enqueued by the main thread. Since the readback thread processes
// exactly one task per wakeup (with one exception), no tasks are lost. The
// exception is when the readback thread is shut down, which orphans the
// remaining tasks, on purpose.
HANDLE mTaskSemaphore;
// Event signaled when the task thread should shutdown
HANDLE mShutdownEvent;
// Handle to the task thread
HANDLE mTaskThread;
// FiFo list of readback tasks that are to be executed. Access is synchronized
// by mTaskMutex.
CRITICAL_SECTION mTaskMutex;
nsTArray<nsAutoPtr<ReadbackTask>> mPendingReadbackTasks;
ULONG mRefCnt;
};
}
}
#endif /* GFX_READBACKMANAGERD3D10_H */

View File

@ -45,6 +45,8 @@
#include "gfxTeeSurface.h"
#include "gfxUtils.h"
#include "ReadbackLayer.h"
#include "ReadbackProcessor.h"
namespace mozilla {
namespace layers {
@ -168,7 +170,7 @@ ThebesLayerD3D10::RenderLayer()
}
void
ThebesLayerD3D10::Validate()
ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback)
{
if (mVisibleRegion.IsEmpty()) {
return;
@ -191,6 +193,12 @@ ThebesLayerD3D10::Validate()
mTextureOnWhite = nsnull;
}
nsTArray<ReadbackProcessor::Update> readbackUpdates;
nsIntRegion readbackRegion;
if (aReadback && UsedForReadback()) {
aReadback->GetThebesLayerUpdates(this, &readbackUpdates, &readbackRegion);
}
nsIntRect visibleRect = mVisibleRegion.GetBounds();
if (mTexture) {
@ -264,6 +272,23 @@ ThebesLayerD3D10::Validate()
DrawRegion(region, mode);
if (readbackUpdates.Length() > 0) {
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
visibleRect.width, visibleRect.height,
1, 1, 0, D3D10_USAGE_STAGING,
D3D10_CPU_ACCESS_READ);
nsRefPtr<ID3D10Texture2D> readbackTexture;
device()->CreateTexture2D(&desc, NULL, getter_AddRefs(readbackTexture));
device()->CopyResource(readbackTexture, mTexture);
for (int i = 0; i < readbackUpdates.Length(); i++) {
mD3DManager->readbackManager()->PostTask(readbackTexture,
&readbackUpdates[i],
gfxPoint(visibleRect.x, visibleRect.y));
}
}
mValidRegion = mVisibleRegion;
}
}

View File

@ -51,13 +51,15 @@ public:
ThebesLayerD3D10(LayerManagerD3D10 *aManager);
virtual ~ThebesLayerD3D10();
void Validate(ReadbackProcessor *aReadback);
/* ThebesLayer implementation */
void InvalidateRegion(const nsIntRegion& aRegion);
/* LayerD3D10 implementation */
virtual Layer* GetLayer();
virtual void RenderLayer();
virtual void Validate();
virtual void Validate() { Validate(nsnull); }
virtual void LayerManagerDestroyed();
private: