1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "SourceSurfaceD2D1.h"
7 #include "DrawTargetD2D1.h"
8 #include "Tools.h"
9 
10 namespace mozilla {
11 namespace gfx {
12 
SourceSurfaceD2D1(ID2D1Image * aImage,ID2D1DeviceContext * aDC,SurfaceFormat aFormat,const IntSize & aSize,DrawTargetD2D1 * aDT)13 SourceSurfaceD2D1::SourceSurfaceD2D1(ID2D1Image *aImage, ID2D1DeviceContext *aDC,
14                                      SurfaceFormat aFormat, const IntSize &aSize,
15                                      DrawTargetD2D1 *aDT)
16   : mImage(aImage)
17   , mDC(aDC)
18   , mDevice(Factory::GetD2D1Device())
19   , mDrawTarget(aDT)
20 {
21   aImage->QueryInterface((ID2D1Bitmap1**)getter_AddRefs(mRealizedBitmap));
22 
23   mFormat = aFormat;
24   mSize = aSize;
25 }
26 
~SourceSurfaceD2D1()27 SourceSurfaceD2D1::~SourceSurfaceD2D1()
28 {
29 }
30 
31 bool
IsValid() const32 SourceSurfaceD2D1::IsValid() const
33 {
34   return mDevice == Factory::GetD2D1Device();
35 }
36 
37 already_AddRefed<DataSourceSurface>
GetDataSurface()38 SourceSurfaceD2D1::GetDataSurface()
39 {
40   HRESULT hr;
41 
42   if (!EnsureRealizedBitmap()) {
43     gfxCriticalError() << "Failed to realize a bitmap, device " << hexa(mDevice);
44     return nullptr;
45   }
46 
47   RefPtr<ID2D1Bitmap1> softwareBitmap;
48   D2D1_BITMAP_PROPERTIES1 props;
49   props.dpiX = 96;
50   props.dpiY = 96;
51   props.pixelFormat = D2DPixelFormat(mFormat);
52   props.colorContext = nullptr;
53   props.bitmapOptions = D2D1_BITMAP_OPTIONS_CANNOT_DRAW |
54                         D2D1_BITMAP_OPTIONS_CPU_READ;
55   hr = mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)getter_AddRefs(softwareBitmap));
56 
57   if (FAILED(hr)) {
58     gfxCriticalError() << "Failed to create software bitmap: " << mSize << " Code: " << hexa(hr);
59     return nullptr;
60   }
61 
62   D2D1_POINT_2U point = D2D1::Point2U(0, 0);
63   D2D1_RECT_U rect = D2D1::RectU(0, 0, mSize.width, mSize.height);
64 
65   hr = softwareBitmap->CopyFromBitmap(&point, mRealizedBitmap, &rect);
66 
67   if (FAILED(hr)) {
68     gfxWarning() << "Failed to readback into software bitmap. Code: " << hexa(hr);
69     return nullptr;
70   }
71 
72   return MakeAndAddRef<DataSourceSurfaceD2D1>(softwareBitmap, mFormat);
73 }
74 
75 bool
EnsureRealizedBitmap()76 SourceSurfaceD2D1::EnsureRealizedBitmap()
77 {
78   if (mRealizedBitmap) {
79     return true;
80   }
81 
82   // Why aren't we using mDevice here or anywhere else?
83   ID2D1Device* device = Factory::GetD2D1Device();
84   if (!device) {
85     return false;
86   }
87 
88   RefPtr<ID2D1DeviceContext> dc;
89   device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, getter_AddRefs(dc));
90 
91   D2D1_BITMAP_PROPERTIES1 props;
92   props.dpiX = 96;
93   props.dpiY = 96;
94   props.pixelFormat = D2DPixelFormat(mFormat);
95   props.colorContext = nullptr;
96   props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
97   dc->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)getter_AddRefs(mRealizedBitmap));
98 
99   dc->SetTarget(mRealizedBitmap);
100 
101   dc->BeginDraw();
102   dc->DrawImage(mImage);
103   dc->EndDraw();
104 
105   return true;
106 }
107 
108 void
DrawTargetWillChange()109 SourceSurfaceD2D1::DrawTargetWillChange()
110 {
111   // At this point in time this should always be true here.
112   MOZ_ASSERT(mRealizedBitmap);
113 
114   RefPtr<ID2D1Bitmap1> oldBitmap = mRealizedBitmap;
115 
116   D2D1_BITMAP_PROPERTIES1 props;
117   props.dpiX = 96;
118   props.dpiY = 96;
119   props.pixelFormat = D2DPixelFormat(mFormat);
120   props.colorContext = nullptr;
121   props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
122   HRESULT hr = mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)getter_AddRefs(mRealizedBitmap));
123 
124   if (FAILED(hr)) {
125     gfxCriticalError() << "Failed to create bitmap to make DrawTarget copy. Size: " << mSize << " Code: " << hexa(hr);
126     MarkIndependent();
127     return;
128   }
129 
130   D2D1_POINT_2U point = D2D1::Point2U(0, 0);
131   D2D1_RECT_U rect = D2D1::RectU(0, 0, mSize.width, mSize.height);
132   mRealizedBitmap->CopyFromBitmap(&point, oldBitmap, &rect);
133   mImage = mRealizedBitmap;
134 
135   DrawTargetD2D1::mVRAMUsageSS += mSize.width * mSize.height * BytesPerPixel(mFormat);
136 
137   // We now no longer depend on the source surface content remaining the same.
138   MarkIndependent();
139 }
140 
141 void
MarkIndependent()142 SourceSurfaceD2D1::MarkIndependent()
143 {
144   if (mDrawTarget) {
145     MOZ_ASSERT(mDrawTarget->mSnapshot == this);
146     mDrawTarget->mSnapshot = nullptr;
147     mDrawTarget = nullptr;
148   }
149 }
150 
DataSourceSurfaceD2D1(ID2D1Bitmap1 * aMappableBitmap,SurfaceFormat aFormat)151 DataSourceSurfaceD2D1::DataSourceSurfaceD2D1(ID2D1Bitmap1 *aMappableBitmap, SurfaceFormat aFormat)
152   : mBitmap(aMappableBitmap)
153   , mFormat(aFormat)
154   , mMapped(false)
155 {
156 }
157 
~DataSourceSurfaceD2D1()158 DataSourceSurfaceD2D1::~DataSourceSurfaceD2D1()
159 {
160   if (mMapped) {
161     mBitmap->Unmap();
162   }
163 }
164 
165 IntSize
GetSize() const166 DataSourceSurfaceD2D1::GetSize() const
167 {
168   D2D1_SIZE_F size = mBitmap->GetSize();
169 
170   return IntSize(int32_t(size.width), int32_t(size.height));
171 }
172 
173 uint8_t*
GetData()174 DataSourceSurfaceD2D1::GetData()
175 {
176   EnsureMapped();
177 
178   return mMap.bits;
179 }
180 
181 bool
Map(MapType aMapType,MappedSurface * aMappedSurface)182 DataSourceSurfaceD2D1::Map(MapType aMapType, MappedSurface *aMappedSurface)
183 {
184   // DataSourceSurfaces used with the new Map API should not be used with GetData!!
185   MOZ_ASSERT(!mMapped);
186   MOZ_ASSERT(!mIsMapped);
187 
188   D2D1_MAP_OPTIONS options;
189   if (aMapType == MapType::READ) {
190     options = D2D1_MAP_OPTIONS_READ;
191   } else {
192     gfxWarning() << "Attempt to map D2D1 DrawTarget for writing.";
193     return false;
194   }
195 
196   D2D1_MAPPED_RECT map;
197   if (FAILED(mBitmap->Map(D2D1_MAP_OPTIONS_READ, &map))) {
198     gfxCriticalError() << "Failed to map bitmap (M).";
199     return false;
200   }
201   aMappedSurface->mData = map.bits;
202   aMappedSurface->mStride = map.pitch;
203 
204   mIsMapped = !!aMappedSurface->mData;
205   return mIsMapped;
206 }
207 
208 void
Unmap()209 DataSourceSurfaceD2D1::Unmap()
210 {
211   MOZ_ASSERT(mIsMapped);
212 
213   mIsMapped = false;
214   mBitmap->Unmap();
215 }
216 
217 int32_t
Stride()218 DataSourceSurfaceD2D1::Stride()
219 {
220   EnsureMapped();
221 
222   return mMap.pitch;
223 }
224 
225 void
EnsureMapped()226 DataSourceSurfaceD2D1::EnsureMapped()
227 {
228   // Do not use GetData() after having used Map!
229   MOZ_ASSERT(!mIsMapped);
230   if (mMapped) {
231     return;
232   }
233   if (FAILED(mBitmap->Map(D2D1_MAP_OPTIONS_READ, &mMap))) {
234     gfxCriticalError() << "Failed to map bitmap (EM).";
235     return;
236   }
237   mMapped = true;
238 }
239 
240 }
241 }
242