1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // Image9.cpp: Implements the rx::Image9 class, which acts as the interface to
8 // the actual underlying surfaces of a Texture.
9
10 #include "libANGLE/renderer/d3d/d3d9/Image9.h"
11
12 #include "common/utilities.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Framebuffer.h"
15 #include "libANGLE/FramebufferAttachment.h"
16 #include "libANGLE/Renderbuffer.h"
17 #include "libANGLE/formatutils.h"
18 #include "libANGLE/renderer/copyvertex.h"
19 #include "libANGLE/renderer/d3d/d3d9/Context9.h"
20 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
21 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
22 #include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
23 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
24 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
25
26 namespace rx
27 {
28
Image9(Renderer9 * renderer)29 Image9::Image9(Renderer9 *renderer)
30 {
31 mSurface = nullptr;
32 mRenderer = nullptr;
33
34 mD3DPool = D3DPOOL_SYSTEMMEM;
35 mD3DFormat = D3DFMT_UNKNOWN;
36
37 mRenderer = renderer;
38 }
39
~Image9()40 Image9::~Image9()
41 {
42 SafeRelease(mSurface);
43 }
44
45 // static
GenerateMip(Context9 * context9,IDirect3DSurface9 * destSurface,IDirect3DSurface9 * sourceSurface)46 angle::Result Image9::GenerateMip(Context9 *context9,
47 IDirect3DSurface9 *destSurface,
48 IDirect3DSurface9 *sourceSurface)
49 {
50 D3DSURFACE_DESC destDesc;
51 HRESULT result = destSurface->GetDesc(&destDesc);
52 ASSERT(SUCCEEDED(result));
53 ANGLE_TRY_HR(context9, result,
54 "Failed to query the source surface description for mipmap generation");
55
56 D3DSURFACE_DESC sourceDesc;
57 result = sourceSurface->GetDesc(&sourceDesc);
58 ASSERT(SUCCEEDED(result));
59 ANGLE_TRY_HR(context9, result,
60 "Failed to query the destination surface description for mipmap generation");
61
62 ASSERT(sourceDesc.Format == destDesc.Format);
63 ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
64 ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height);
65
66 const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format);
67 ASSERT(d3dFormatInfo.info().mipGenerationFunction != nullptr);
68
69 D3DLOCKED_RECT sourceLocked = {};
70 result = sourceSurface->LockRect(&sourceLocked, nullptr, D3DLOCK_READONLY);
71 ASSERT(SUCCEEDED(result));
72 ANGLE_TRY_HR(context9, result, "Failed to lock the source surface for mipmap generation");
73
74 D3DLOCKED_RECT destLocked = {};
75 result = destSurface->LockRect(&destLocked, nullptr, 0);
76 ASSERT(SUCCEEDED(result));
77 ANGLE_TRY_HR(context9, result, "Failed to lock the destination surface for mipmap generation");
78
79 const uint8_t *sourceData = static_cast<const uint8_t *>(sourceLocked.pBits);
80 uint8_t *destData = static_cast<uint8_t *>(destLocked.pBits);
81
82 ASSERT(sourceData && destData);
83
84 d3dFormatInfo.info().mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData,
85 sourceLocked.Pitch, 0, destData, destLocked.Pitch,
86 0);
87
88 destSurface->UnlockRect();
89 sourceSurface->UnlockRect();
90
91 return angle::Result::Continue;
92 }
93
94 // static
GenerateMipmap(Context9 * context9,Image9 * dest,Image9 * source)95 angle::Result Image9::GenerateMipmap(Context9 *context9, Image9 *dest, Image9 *source)
96 {
97 IDirect3DSurface9 *sourceSurface = nullptr;
98 ANGLE_TRY(source->getSurface(context9, &sourceSurface));
99
100 IDirect3DSurface9 *destSurface = nullptr;
101 ANGLE_TRY(dest->getSurface(context9, &destSurface));
102
103 ANGLE_TRY(GenerateMip(context9, destSurface, sourceSurface));
104
105 dest->markDirty();
106
107 return angle::Result::Continue;
108 }
109
110 // static
CopyLockableSurfaces(Context9 * context9,IDirect3DSurface9 * dest,IDirect3DSurface9 * source)111 angle::Result Image9::CopyLockableSurfaces(Context9 *context9,
112 IDirect3DSurface9 *dest,
113 IDirect3DSurface9 *source)
114 {
115 D3DLOCKED_RECT sourceLock = {};
116 D3DLOCKED_RECT destLock = {};
117
118 HRESULT result;
119
120 result = source->LockRect(&sourceLock, nullptr, 0);
121 ANGLE_TRY_HR(context9, result, "Failed to lock source surface for copy");
122
123 result = dest->LockRect(&destLock, nullptr, 0);
124 if (FAILED(result))
125 {
126 source->UnlockRect();
127 }
128 ANGLE_TRY_HR(context9, result, "Failed to lock destination surface for copy");
129
130 ASSERT(sourceLock.pBits && destLock.pBits);
131
132 D3DSURFACE_DESC desc;
133 source->GetDesc(&desc);
134
135 const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
136 unsigned int rows = desc.Height / d3dFormatInfo.blockHeight;
137
138 unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight);
139 ASSERT(bytes <= static_cast<unsigned int>(sourceLock.Pitch) &&
140 bytes <= static_cast<unsigned int>(destLock.Pitch));
141
142 for (unsigned int i = 0; i < rows; i++)
143 {
144 memcpy((char *)destLock.pBits + destLock.Pitch * i,
145 (char *)sourceLock.pBits + sourceLock.Pitch * i, bytes);
146 }
147
148 source->UnlockRect();
149 dest->UnlockRect();
150
151 return angle::Result::Continue;
152 }
153
154 // static
CopyImage(const gl::Context * context,Image9 * dest,Image9 * source,const gl::Rectangle & sourceRect,const gl::Offset & destOffset,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha)155 angle::Result Image9::CopyImage(const gl::Context *context,
156 Image9 *dest,
157 Image9 *source,
158 const gl::Rectangle &sourceRect,
159 const gl::Offset &destOffset,
160 bool unpackFlipY,
161 bool unpackPremultiplyAlpha,
162 bool unpackUnmultiplyAlpha)
163 {
164 Context9 *context9 = GetImplAs<Context9>(context);
165
166 IDirect3DSurface9 *sourceSurface = nullptr;
167 ANGLE_TRY(source->getSurface(context9, &sourceSurface));
168
169 IDirect3DSurface9 *destSurface = nullptr;
170 ANGLE_TRY(dest->getSurface(context9, &destSurface));
171
172 D3DSURFACE_DESC destDesc;
173 HRESULT result = destSurface->GetDesc(&destDesc);
174 ASSERT(SUCCEEDED(result));
175 ANGLE_TRY_HR(context9, result, "Failed to query the source surface description for CopyImage");
176 const d3d9::D3DFormat &destD3DFormatInfo = d3d9::GetD3DFormatInfo(destDesc.Format);
177
178 D3DSURFACE_DESC sourceDesc;
179 result = sourceSurface->GetDesc(&sourceDesc);
180 ASSERT(SUCCEEDED(result));
181 ANGLE_TRY_HR(context9, result,
182 "Failed to query the destination surface description for CopyImage");
183 const d3d9::D3DFormat &sourceD3DFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format);
184
185 D3DLOCKED_RECT sourceLocked = {};
186 result = sourceSurface->LockRect(&sourceLocked, nullptr, D3DLOCK_READONLY);
187 ASSERT(SUCCEEDED(result));
188 ANGLE_TRY_HR(context9, result, "Failed to lock the source surface for CopyImage");
189
190 D3DLOCKED_RECT destLocked = {};
191 result = destSurface->LockRect(&destLocked, nullptr, 0);
192 ASSERT(SUCCEEDED(result));
193 if (FAILED(result))
194 {
195 sourceSurface->UnlockRect();
196 }
197 ANGLE_TRY_HR(context9, result, "Failed to lock the destination surface for CopyImage");
198
199 const uint8_t *sourceData = static_cast<const uint8_t *>(sourceLocked.pBits) +
200 sourceRect.x * sourceD3DFormatInfo.pixelBytes +
201 sourceRect.y * sourceLocked.Pitch;
202 uint8_t *destData = static_cast<uint8_t *>(destLocked.pBits) +
203 destOffset.x * destD3DFormatInfo.pixelBytes +
204 destOffset.y * destLocked.Pitch;
205 ASSERT(sourceData && destData);
206
207 CopyImageCHROMIUM(sourceData, sourceLocked.Pitch, sourceD3DFormatInfo.pixelBytes, 0,
208 sourceD3DFormatInfo.info().pixelReadFunction, destData, destLocked.Pitch,
209 destD3DFormatInfo.pixelBytes, 0, destD3DFormatInfo.info().pixelWriteFunction,
210 gl::GetUnsizedFormat(dest->getInternalFormat()),
211 destD3DFormatInfo.info().componentType, sourceRect.width, sourceRect.height,
212 1, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
213
214 dest->markDirty();
215
216 destSurface->UnlockRect();
217 sourceSurface->UnlockRect();
218
219 return angle::Result::Continue;
220 }
221
redefine(gl::TextureType type,GLenum internalformat,const gl::Extents & size,bool forceRelease)222 bool Image9::redefine(gl::TextureType type,
223 GLenum internalformat,
224 const gl::Extents &size,
225 bool forceRelease)
226 {
227 // 3D textures are not supported by the D3D9 backend.
228 ASSERT(size.depth <= 1);
229
230 // Only 2D and cube texture are supported by the D3D9 backend.
231 ASSERT(type == gl::TextureType::_2D || type == gl::TextureType::CubeMap);
232
233 if (mWidth != size.width || mHeight != size.height || mDepth != size.depth ||
234 mInternalFormat != internalformat || forceRelease)
235 {
236 mWidth = size.width;
237 mHeight = size.height;
238 mDepth = size.depth;
239 mType = type;
240 mInternalFormat = internalformat;
241
242 // compute the d3d format that will be used
243 const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(internalformat);
244 mD3DFormat = d3d9FormatInfo.texFormat;
245 mRenderable = (d3d9FormatInfo.renderFormat != D3DFMT_UNKNOWN);
246
247 SafeRelease(mSurface);
248 mDirty = (d3d9FormatInfo.dataInitializerFunction != nullptr);
249
250 return true;
251 }
252
253 return false;
254 }
255
createSurface(Context9 * context9)256 angle::Result Image9::createSurface(Context9 *context9)
257 {
258 if (mSurface)
259 {
260 return angle::Result::Continue;
261 }
262
263 IDirect3DTexture9 *newTexture = nullptr;
264 IDirect3DSurface9 *newSurface = nullptr;
265 const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM;
266 const D3DFORMAT d3dFormat = getD3DFormat();
267
268 if (mWidth != 0 && mHeight != 0)
269 {
270 int levelToFetch = 0;
271 GLsizei requestWidth = mWidth;
272 GLsizei requestHeight = mHeight;
273 d3d9::MakeValidSize(true, d3dFormat, &requestWidth, &requestHeight, &levelToFetch);
274
275 IDirect3DDevice9 *device = mRenderer->getDevice();
276
277 HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0,
278 d3dFormat, poolToUse, &newTexture, nullptr);
279
280 ANGLE_TRY_HR(context9, result, "Failed to create image surface");
281
282 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
283 SafeRelease(newTexture);
284
285 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
286 if (d3dFormatInfo.dataInitializerFunction != nullptr)
287 {
288 RECT entireRect;
289 entireRect.left = 0;
290 entireRect.right = mWidth;
291 entireRect.top = 0;
292 entireRect.bottom = mHeight;
293
294 D3DLOCKED_RECT lockedRect;
295 result = newSurface->LockRect(&lockedRect, &entireRect, 0);
296 ASSERT(SUCCEEDED(result));
297 ANGLE_TRY_HR(context9, result, "Failed to lock image surface");
298
299 d3dFormatInfo.dataInitializerFunction(
300 mWidth, mHeight, 1, static_cast<uint8_t *>(lockedRect.pBits), lockedRect.Pitch, 0);
301
302 result = newSurface->UnlockRect();
303 ASSERT(SUCCEEDED(result));
304 ANGLE_TRY_HR(context9, result, "Failed to unlock image surface");
305 }
306 }
307
308 mSurface = newSurface;
309 mDirty = false;
310 mD3DPool = poolToUse;
311
312 return angle::Result::Continue;
313 }
314
lock(Context9 * context9,D3DLOCKED_RECT * lockedRect,const RECT & rect)315 angle::Result Image9::lock(Context9 *context9, D3DLOCKED_RECT *lockedRect, const RECT &rect)
316 {
317 ANGLE_TRY(createSurface(context9));
318
319 if (mSurface)
320 {
321 HRESULT result = mSurface->LockRect(lockedRect, &rect, 0);
322 ASSERT(SUCCEEDED(result));
323 ANGLE_TRY_HR(context9, result, "Failed to lock image surface");
324 mDirty = true;
325 }
326
327 return angle::Result::Continue;
328 }
329
unlock()330 void Image9::unlock()
331 {
332 if (mSurface)
333 {
334 HRESULT result = mSurface->UnlockRect();
335 ASSERT(SUCCEEDED(result));
336 }
337 }
338
getD3DFormat() const339 D3DFORMAT Image9::getD3DFormat() const
340 {
341 // this should only happen if the image hasn't been redefined first
342 // which would be a bug by the caller
343 ASSERT(mD3DFormat != D3DFMT_UNKNOWN);
344
345 return mD3DFormat;
346 }
347
isDirty() const348 bool Image9::isDirty() const
349 {
350 // Make sure to that this image is marked as dirty even if the staging texture hasn't been
351 // created yet if initialization is required before use.
352 return (mSurface ||
353 d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != nullptr) &&
354 mDirty;
355 }
356
getSurface(Context9 * context9,IDirect3DSurface9 ** outSurface)357 angle::Result Image9::getSurface(Context9 *context9, IDirect3DSurface9 **outSurface)
358 {
359 ANGLE_TRY(createSurface(context9));
360 *outSurface = mSurface;
361 return angle::Result::Continue;
362 }
363
setManagedSurface2D(const gl::Context * context,TextureStorage * storage,int level)364 angle::Result Image9::setManagedSurface2D(const gl::Context *context,
365 TextureStorage *storage,
366 int level)
367 {
368 IDirect3DSurface9 *surface = nullptr;
369 TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
370 ANGLE_TRY(storage9->getSurfaceLevel(context, gl::TextureTarget::_2D, level, false, &surface));
371 return setManagedSurface(GetImplAs<Context9>(context), surface);
372 }
373
setManagedSurfaceCube(const gl::Context * context,TextureStorage * storage,int face,int level)374 angle::Result Image9::setManagedSurfaceCube(const gl::Context *context,
375 TextureStorage *storage,
376 int face,
377 int level)
378 {
379 IDirect3DSurface9 *surface = nullptr;
380 TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
381 ANGLE_TRY(storage9->getSurfaceLevel(context, gl::CubeFaceIndexToTextureTarget(face), level,
382 false, &surface));
383 return setManagedSurface(GetImplAs<Context9>(context), surface);
384 }
385
setManagedSurface(Context9 * context9,IDirect3DSurface9 * surface)386 angle::Result Image9::setManagedSurface(Context9 *context9, IDirect3DSurface9 *surface)
387 {
388 D3DSURFACE_DESC desc;
389 surface->GetDesc(&desc);
390 ASSERT(desc.Pool == D3DPOOL_MANAGED);
391
392 if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight)
393 {
394 if (mSurface)
395 {
396 angle::Result result = CopyLockableSurfaces(context9, surface, mSurface);
397 SafeRelease(mSurface);
398 ANGLE_TRY(result);
399 }
400
401 mSurface = surface;
402 mD3DPool = desc.Pool;
403 }
404
405 return angle::Result::Continue;
406 }
407
copyToStorage(const gl::Context * context,TextureStorage * storage,const gl::ImageIndex & index,const gl::Box & region)408 angle::Result Image9::copyToStorage(const gl::Context *context,
409 TextureStorage *storage,
410 const gl::ImageIndex &index,
411 const gl::Box ®ion)
412 {
413 ANGLE_TRY(createSurface(GetImplAs<Context9>(context)));
414
415 TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
416 IDirect3DSurface9 *destSurface = nullptr;
417 ANGLE_TRY(storage9->getSurfaceLevel(context, index.getTarget(), index.getLevelIndex(), true,
418 &destSurface));
419
420 angle::Result result = copyToSurface(GetImplAs<Context9>(context), destSurface, region);
421 SafeRelease(destSurface);
422 return result;
423 }
424
copyToSurface(Context9 * context9,IDirect3DSurface9 * destSurface,const gl::Box & area)425 angle::Result Image9::copyToSurface(Context9 *context9,
426 IDirect3DSurface9 *destSurface,
427 const gl::Box &area)
428 {
429 ASSERT(area.width > 0 && area.height > 0 && area.depth == 1);
430 ASSERT(destSurface);
431
432 IDirect3DSurface9 *sourceSurface = nullptr;
433 ANGLE_TRY(getSurface(context9, &sourceSurface));
434
435 ASSERT(sourceSurface && sourceSurface != destSurface);
436
437 RECT rect;
438 rect.left = area.x;
439 rect.top = area.y;
440 rect.right = area.x + area.width;
441 rect.bottom = area.y + area.height;
442
443 POINT point = {rect.left, rect.top};
444
445 IDirect3DDevice9 *device = mRenderer->getDevice();
446
447 if (mD3DPool == D3DPOOL_MANAGED)
448 {
449 D3DSURFACE_DESC desc;
450 sourceSurface->GetDesc(&desc);
451
452 IDirect3DSurface9 *surf = 0;
453 HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
454 D3DPOOL_SYSTEMMEM, &surf, nullptr);
455 ANGLE_TRY_HR(context9, result, "Internal CreateOffscreenPlainSurface call failed");
456
457 auto err = CopyLockableSurfaces(context9, surf, sourceSurface);
458 result = device->UpdateSurface(surf, &rect, destSurface, &point);
459 SafeRelease(surf);
460 ANGLE_TRY(err);
461 ASSERT(SUCCEEDED(result));
462 ANGLE_TRY_HR(context9, result, "Internal UpdateSurface call failed");
463 }
464 else
465 {
466 // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
467 HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point);
468 ASSERT(SUCCEEDED(result));
469 ANGLE_TRY_HR(context9, result, "Internal UpdateSurface call failed");
470 }
471
472 return angle::Result::Continue;
473 }
474
475 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as
476 // format/type at input into the target pixel rectangle.
loadData(const gl::Context * context,const gl::Box & area,const gl::PixelUnpackState & unpack,GLenum type,const void * input,bool applySkipImages)477 angle::Result Image9::loadData(const gl::Context *context,
478 const gl::Box &area,
479 const gl::PixelUnpackState &unpack,
480 GLenum type,
481 const void *input,
482 bool applySkipImages)
483 {
484 // 3D textures are not supported by the D3D9 backend.
485 ASSERT(area.z == 0 && area.depth == 1);
486
487 Context9 *context9 = GetImplAs<Context9>(context);
488
489 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
490 GLuint inputRowPitch = 0;
491 ANGLE_CHECK_GL_MATH(context9, formatInfo.computeRowPitch(type, area.width, unpack.alignment,
492 unpack.rowLength, &inputRowPitch));
493 ASSERT(!applySkipImages);
494 ASSERT(unpack.skipPixels == 0);
495 ASSERT(unpack.skipRows == 0);
496
497 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
498 ASSERT(d3dFormatInfo.loadFunction != nullptr);
499
500 RECT lockRect = {area.x, area.y, area.x + area.width, area.y + area.height};
501
502 D3DLOCKED_RECT locked;
503 ANGLE_TRY(lock(GetImplAs<Context9>(context), &locked, lockRect));
504
505 d3dFormatInfo.loadFunction(area.width, area.height, area.depth,
506 static_cast<const uint8_t *>(input), inputRowPitch, 0,
507 static_cast<uint8_t *>(locked.pBits), locked.Pitch, 0);
508
509 unlock();
510
511 return angle::Result::Continue;
512 }
513
loadCompressedData(const gl::Context * context,const gl::Box & area,const void * input)514 angle::Result Image9::loadCompressedData(const gl::Context *context,
515 const gl::Box &area,
516 const void *input)
517 {
518 // 3D textures are not supported by the D3D9 backend.
519 ASSERT(area.z == 0 && area.depth == 1);
520
521 Context9 *context9 = GetImplAs<Context9>(context);
522
523 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
524 GLuint inputRowPitch = 0;
525 ANGLE_CHECK_GL_MATH(
526 context9, formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0, &inputRowPitch));
527
528 GLuint inputDepthPitch = 0;
529 ANGLE_CHECK_GL_MATH(
530 context9, formatInfo.computeDepthPitch(area.height, 0, inputRowPitch, &inputDepthPitch));
531
532 const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
533
534 ASSERT(area.x % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockWidth == 0);
535 ASSERT(area.y % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockHeight == 0);
536
537 ASSERT(d3d9FormatInfo.loadFunction != nullptr);
538
539 RECT lockRect = {area.x, area.y, area.x + area.width, area.y + area.height};
540
541 D3DLOCKED_RECT locked;
542 ANGLE_TRY(lock(GetImplAs<Context9>(context), &locked, lockRect));
543
544 d3d9FormatInfo.loadFunction(area.width, area.height, area.depth,
545 static_cast<const uint8_t *>(input), inputRowPitch, inputDepthPitch,
546 static_cast<uint8_t *>(locked.pBits), locked.Pitch, 0);
547
548 unlock();
549
550 return angle::Result::Continue;
551 }
552
553 // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete
554 // textures
copyFromRTInternal(Context9 * context9,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,RenderTargetD3D * source)555 angle::Result Image9::copyFromRTInternal(Context9 *context9,
556 const gl::Offset &destOffset,
557 const gl::Rectangle &sourceArea,
558 RenderTargetD3D *source)
559 {
560 ASSERT(source);
561
562 // ES3.0 only behaviour to copy into a 3d texture
563 ASSERT(destOffset.z == 0);
564
565 RenderTarget9 *renderTarget = GetAs<RenderTarget9>(source);
566
567 angle::ComPtr<IDirect3DSurface9> surface = renderTarget->getSurface();
568 ASSERT(surface);
569
570 IDirect3DDevice9 *device = mRenderer->getDevice();
571
572 angle::ComPtr<IDirect3DSurface9> renderTargetData = nullptr;
573 D3DSURFACE_DESC description;
574 surface->GetDesc(&description);
575
576 HRESULT hr = device->CreateOffscreenPlainSurface(description.Width, description.Height,
577 description.Format, D3DPOOL_SYSTEMMEM,
578 &renderTargetData, nullptr);
579
580 ANGLE_TRY_HR(context9, hr, "Could not create matching destination surface");
581
582 hr = device->GetRenderTargetData(surface.Get(), renderTargetData.Get());
583
584 ANGLE_TRY_HR(context9, hr, "GetRenderTargetData unexpectedly failed");
585
586 int width = sourceArea.width;
587 int height = sourceArea.height;
588
589 RECT sourceRect = {sourceArea.x, sourceArea.y, sourceArea.x + width, sourceArea.y + height};
590 RECT destRect = {destOffset.x, destOffset.y, destOffset.x + width, destOffset.y + height};
591
592 D3DLOCKED_RECT sourceLock = {};
593 hr = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
594
595 ANGLE_TRY_HR(context9, hr, "Failed to lock the source surface (rectangle might be invalid)");
596
597 D3DLOCKED_RECT destLock = {};
598 angle::Result result = lock(context9, &destLock, destRect);
599 if (result == angle::Result::Stop)
600 {
601 renderTargetData->UnlockRect();
602 }
603 ANGLE_TRY(result);
604
605 ASSERT(destLock.pBits && sourceLock.pBits);
606
607 unsigned char *sourcePixels = (unsigned char *)sourceLock.pBits;
608 unsigned char *destPixels = (unsigned char *)destLock.pBits;
609
610 switch (description.Format)
611 {
612 case D3DFMT_X8R8G8B8:
613 case D3DFMT_A8R8G8B8:
614 switch (getD3DFormat())
615 {
616 case D3DFMT_X8R8G8B8:
617 case D3DFMT_A8R8G8B8:
618 for (int y = 0; y < height; y++)
619 {
620 memcpy(destPixels, sourcePixels, 4 * width);
621 sourcePixels += sourceLock.Pitch;
622 destPixels += destLock.Pitch;
623 }
624 break;
625 case D3DFMT_L8:
626 for (int y = 0; y < height; y++)
627 {
628 for (int x = 0; x < width; x++)
629 {
630 destPixels[x] = sourcePixels[x * 4 + 2];
631 }
632 sourcePixels += sourceLock.Pitch;
633 destPixels += destLock.Pitch;
634 }
635 break;
636 case D3DFMT_A8L8:
637 for (int y = 0; y < height; y++)
638 {
639 for (int x = 0; x < width; x++)
640 {
641 destPixels[x * 2 + 0] = sourcePixels[x * 4 + 2];
642 destPixels[x * 2 + 1] = sourcePixels[x * 4 + 3];
643 }
644 sourcePixels += sourceLock.Pitch;
645 destPixels += destLock.Pitch;
646 }
647 break;
648 default:
649 UNREACHABLE();
650 }
651 break;
652 case D3DFMT_R5G6B5:
653 switch (getD3DFormat())
654 {
655 case D3DFMT_X8R8G8B8:
656 for (int y = 0; y < height; y++)
657 {
658 for (int x = 0; x < width; x++)
659 {
660 unsigned short rgb = ((unsigned short *)sourcePixels)[x];
661 unsigned char red = static_cast<unsigned char>((rgb & 0xF800) >> 8);
662 unsigned char green = static_cast<unsigned char>((rgb & 0x07E0) >> 3);
663 unsigned char blue = static_cast<unsigned char>((rgb & 0x001F) << 3);
664 destPixels[x + 0] = blue | (blue >> 5);
665 destPixels[x + 1] = green | (green >> 6);
666 destPixels[x + 2] = red | (red >> 5);
667 destPixels[x + 3] = 0xFF;
668 }
669 sourcePixels += sourceLock.Pitch;
670 destPixels += destLock.Pitch;
671 }
672 break;
673 case D3DFMT_L8:
674 for (int y = 0; y < height; y++)
675 {
676 for (int x = 0; x < width; x++)
677 {
678 unsigned char red = sourcePixels[x * 2 + 1] & 0xF8;
679 destPixels[x] = red | (red >> 5);
680 }
681 sourcePixels += sourceLock.Pitch;
682 destPixels += destLock.Pitch;
683 }
684 break;
685 default:
686 UNREACHABLE();
687 }
688 break;
689 case D3DFMT_A1R5G5B5:
690 switch (getD3DFormat())
691 {
692 case D3DFMT_X8R8G8B8:
693 for (int y = 0; y < height; y++)
694 {
695 for (int x = 0; x < width; x++)
696 {
697 unsigned short argb = ((unsigned short *)sourcePixels)[x];
698 unsigned char red = static_cast<unsigned char>((argb & 0x7C00) >> 7);
699 unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2);
700 unsigned char blue = static_cast<unsigned char>((argb & 0x001F) << 3);
701 destPixels[x + 0] = blue | (blue >> 5);
702 destPixels[x + 1] = green | (green >> 5);
703 destPixels[x + 2] = red | (red >> 5);
704 destPixels[x + 3] = 0xFF;
705 }
706 sourcePixels += sourceLock.Pitch;
707 destPixels += destLock.Pitch;
708 }
709 break;
710 case D3DFMT_A8R8G8B8:
711 for (int y = 0; y < height; y++)
712 {
713 for (int x = 0; x < width; x++)
714 {
715 unsigned short argb = ((unsigned short *)sourcePixels)[x];
716 unsigned char red = static_cast<unsigned char>((argb & 0x7C00) >> 7);
717 unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2);
718 unsigned char blue = static_cast<unsigned char>((argb & 0x001F) << 3);
719 unsigned char alpha = (signed short)argb >> 15;
720 destPixels[x + 0] = blue | (blue >> 5);
721 destPixels[x + 1] = green | (green >> 5);
722 destPixels[x + 2] = red | (red >> 5);
723 destPixels[x + 3] = alpha;
724 }
725 sourcePixels += sourceLock.Pitch;
726 destPixels += destLock.Pitch;
727 }
728 break;
729 case D3DFMT_L8:
730 for (int y = 0; y < height; y++)
731 {
732 for (int x = 0; x < width; x++)
733 {
734 unsigned char red = sourcePixels[x * 2 + 1] & 0x7C;
735 destPixels[x] = (red << 1) | (red >> 4);
736 }
737 sourcePixels += sourceLock.Pitch;
738 destPixels += destLock.Pitch;
739 }
740 break;
741 case D3DFMT_A8L8:
742 for (int y = 0; y < height; y++)
743 {
744 for (int x = 0; x < width; x++)
745 {
746 unsigned char red = sourcePixels[x * 2 + 1] & 0x7C;
747 destPixels[x * 2 + 0] = (red << 1) | (red >> 4);
748 destPixels[x * 2 + 1] = (signed char)sourcePixels[x * 2 + 1] >> 7;
749 }
750 sourcePixels += sourceLock.Pitch;
751 destPixels += destLock.Pitch;
752 }
753 break;
754 default:
755 UNREACHABLE();
756 }
757 break;
758 default:
759 UNREACHABLE();
760 }
761
762 unlock();
763 renderTargetData->UnlockRect();
764
765 mDirty = true;
766 return angle::Result::Continue;
767 }
768
copyFromTexStorage(const gl::Context * context,const gl::ImageIndex & imageIndex,TextureStorage * source)769 angle::Result Image9::copyFromTexStorage(const gl::Context *context,
770 const gl::ImageIndex &imageIndex,
771 TextureStorage *source)
772 {
773 RenderTargetD3D *renderTarget = nullptr;
774 ANGLE_TRY(source->getRenderTarget(context, imageIndex, 0, &renderTarget));
775
776 gl::Rectangle sourceArea(0, 0, mWidth, mHeight);
777 return copyFromRTInternal(GetImplAs<Context9>(context), gl::Offset(), sourceArea, renderTarget);
778 }
779
copyFromFramebuffer(const gl::Context * context,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,const gl::Framebuffer * source)780 angle::Result Image9::copyFromFramebuffer(const gl::Context *context,
781 const gl::Offset &destOffset,
782 const gl::Rectangle &sourceArea,
783 const gl::Framebuffer *source)
784 {
785 const gl::FramebufferAttachment *srcAttachment = source->getReadColorAttachment();
786 ASSERT(srcAttachment);
787
788 RenderTargetD3D *renderTarget = nullptr;
789 ANGLE_TRY(srcAttachment->getRenderTarget(context, 0, &renderTarget));
790 ASSERT(renderTarget);
791 return copyFromRTInternal(GetImplAs<Context9>(context), destOffset, sourceArea, renderTarget);
792 }
793
794 } // namespace rx
795