Bug 801465; DataSourceSurfaceD2D; r=Bas
authorNicholas Cameron <ncameron@mozilla.com>
Wed, 31 Oct 2012 12:30:25 +1300
changeset 111970 0ab79ed8030221e43a65f342833faf4b31616ec8
parent 111969 27978aa4d430a11e6c5255cf7c3e44ab28d59650
child 111971 58ddfb88815a8008cf2e62eb55eb4d9c8fc3b6af
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersBas
bugs801465
milestone19.0a1
Bug 801465; DataSourceSurfaceD2D; r=Bas
gfx/2d/SourceSurfaceD2D.cpp
gfx/2d/SourceSurfaceD2D.h
--- a/gfx/2d/SourceSurfaceD2D.cpp
+++ b/gfx/2d/SourceSurfaceD2D.cpp
@@ -38,16 +38,20 @@ bool
 SourceSurfaceD2D::IsValid() const
 {
   return mDevice == Factory::GetDirect3D10Device();
 }
 
 TemporaryRef<DataSourceSurface>
 SourceSurfaceD2D::GetDataSurface()
 {
+  RefPtr<DataSourceSurfaceD2D> result = new DataSourceSurfaceD2D(this);
+  if (result->IsValid()) {
+    return result;
+  }
   return nullptr;
 }
 
 bool
 SourceSurfaceD2D::InitFromData(unsigned char *aData,
                                const IntSize &aSize,
                                int32_t aStride,
                                SurfaceFormat aFormat,
@@ -117,10 +121,129 @@ SourceSurfaceD2D::InitFromTexture(ID3D10
 }
 
 uint32_t
 SourceSurfaceD2D::GetByteSize() const
 {
   return mSize.width * mSize.height * BytesPerPixel(mFormat);
 }
 
+DataSourceSurfaceD2D::DataSourceSurfaceD2D(SourceSurfaceD2D* aSourceSurface)
+  : mTexture(nullptr)
+  , mFormat(aSourceSurface->mFormat)
+  , mSize(aSourceSurface->mSize)
+  , mMapped(false)
+{
+  // We allocate ourselves a regular D3D surface (sourceTexture) and paint the
+  // D2D bitmap into it via a DXGI render target. Then we need to copy
+  // sourceTexture into a staging texture (mTexture), which we will lazily map
+  // to get the data.
+
+  CD3D10_TEXTURE2D_DESC desc(DXGIFormat(mFormat), mSize.width, mSize.height);
+  desc.MipLevels = 1;
+  desc.Usage = D3D10_USAGE_DEFAULT;
+  desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
+  RefPtr<ID3D10Texture2D> sourceTexture;
+  HRESULT hr = aSourceSurface->mDevice->CreateTexture2D(&desc, nullptr,
+                                                        byRef(sourceTexture));
+  if (FAILED(hr)) {
+    gfxWarning() << "Failed to create texture. Code: " << hr;
+    return;
+  }
+
+  RefPtr<IDXGISurface> dxgiSurface;
+  hr = sourceTexture->QueryInterface((IDXGISurface**)byRef(dxgiSurface));
+  if (FAILED(hr)) {
+    gfxWarning() << "Failed to create DXGI surface. Code: " << hr;
+    return;
+  }
+
+  D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties(
+            D2D1_RENDER_TARGET_TYPE_DEFAULT,
+            D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
+
+  RefPtr<ID2D1RenderTarget> renderTarget;
+  hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(dxgiSurface,
+                                                               &rtProps,
+                                                               byRef(renderTarget));
+  if (FAILED(hr)) {
+    gfxWarning() << "Failed to create render target. Code: " << hr;
+    return;
+  }
+
+  renderTarget->BeginDraw();
+  renderTarget->DrawBitmap(aSourceSurface->mBitmap,
+                           D2D1::RectF(0, 0, mSize.width, mSize.height));
+  renderTarget->EndDraw();
+
+  desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
+  desc.Usage = D3D10_USAGE_STAGING;
+  desc.BindFlags = 0;
+  hr = aSourceSurface->mDevice->CreateTexture2D(&desc, nullptr, byRef(mTexture));
+  if (FAILED(hr)) {
+    gfxWarning() << "Failed to create staging texture. Code: " << hr;
+    mTexture = nullptr;
+    return;
+  }
+
+  aSourceSurface->mDevice->CopyResource(mTexture, sourceTexture);
+}
+
+DataSourceSurfaceD2D::~DataSourceSurfaceD2D()
+{
+  if (mMapped) {
+    mTexture->Unmap(0);
+  }
+}
+
+unsigned char*
+DataSourceSurfaceD2D::GetData()
+{
+  EnsureMappedTexture();
+  if (!mMapped) {
+    return nullptr;
+  }
+
+  return reinterpret_cast<unsigned char*>(mData.pData);
+}
+
+int32_t
+DataSourceSurfaceD2D::Stride()
+{
+  EnsureMappedTexture();
+  if (!mMapped) {
+    return 0;
+  }
+
+  return mData.RowPitch;
+}
+
+IntSize
+DataSourceSurfaceD2D::GetSize() const
+{
+  return mSize;
+}
+
+SurfaceFormat
+DataSourceSurfaceD2D::GetFormat() const
+{
+  return mFormat;
+}
+
+void
+DataSourceSurfaceD2D::EnsureMappedTexture()
+{
+  if (mMapped ||
+      !mTexture) {
+    return;
+  }
+
+  HRESULT hr = mTexture->Map(0, D3D10_MAP_READ, 0, &mData);
+  if (FAILED(hr)) {
+    gfxWarning() << "Failed to map texture. Code: " << hr;
+    mTexture = nullptr;
+  } else {
+    mMapped = true;
+  }
+}
+
 }
 }
--- a/gfx/2d/SourceSurfaceD2D.h
+++ b/gfx/2d/SourceSurfaceD2D.h
@@ -8,16 +8,18 @@
 
 #include "2D.h"
 #include "HelpersD2D.h"
 #include <vector>
 
 namespace mozilla {
 namespace gfx {
 
+class DataSourceSurfaceD2D;
+
 class SourceSurfaceD2D : public SourceSurface
 {
 public:
   SourceSurfaceD2D();
   ~SourceSurfaceD2D();
 
   virtual SurfaceType GetType() const { return SURFACE_D2D1_BITMAP; }
   virtual IntSize GetSize() const;
@@ -31,25 +33,54 @@ public:
   bool InitFromData(unsigned char *aData,
                     const IntSize &aSize,
                     int32_t aStride,
                     SurfaceFormat aFormat,
                     ID2D1RenderTarget *aRT);
   bool InitFromTexture(ID3D10Texture2D *aTexture,
                        SurfaceFormat aFormat,
                        ID2D1RenderTarget *aRT);
-
 private:
   friend class DrawTargetD2D;
+  friend class DataSourceSurfaceD2D;
 
   uint32_t GetByteSize() const;
 
   RefPtr<ID2D1Bitmap> mBitmap;
   // We need to keep this pointer here to check surface validity.
   RefPtr<ID3D10Device> mDevice;
   SurfaceFormat mFormat;
   IntSize mSize;
 };
 
+
+class DataSourceSurfaceD2D : public DataSourceSurface
+{
+public:
+  DataSourceSurfaceD2D(SourceSurfaceD2D* aSourceSurface);
+  virtual ~DataSourceSurfaceD2D();
+
+  virtual unsigned char* GetData();
+  virtual int32_t Stride();
+  virtual IntSize GetSize() const;
+  virtual SurfaceFormat GetFormat() const;
+
+  bool IsValid()
+  {
+    return mTexture;
+  }
+
+private:
+  void EnsureMappedTexture();
+
+  RefPtr<ID3D10Texture2D> mTexture;
+
+  D3D10_MAPPED_TEXTURE2D mData;
+
+  SurfaceFormat mFormat;
+  IntSize mSize;
+  bool mMapped;
+};
+
 }
 }
 
 #endif /* MOZILLA_GFX_SOURCESURFACED2D_H_ */