mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 21:05:36 +00:00
Bug 626602, part 6: Implement asynchronous D3D10 readback. r=cjones,jrmuizel
This commit is contained in:
parent
3034c9b8d3
commit
f732d2dcac
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
65
gfx/layers/d3d10/ReadbackLayerD3D10.h
Normal file
65
gfx/layers/d3d10/ReadbackLayerD3D10.h
Normal 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 */
|
250
gfx/layers/d3d10/ReadbackManagerD3D10.cpp
Normal file
250
gfx/layers/d3d10/ReadbackManagerD3D10.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
107
gfx/layers/d3d10/ReadbackManagerD3D10.h
Normal file
107
gfx/layers/d3d10/ReadbackManagerD3D10.h
Normal 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 */
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user