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