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