xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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                 case D3DFMT_A4L4:
651                     for (int y = 0; y < height; y++)
652                     {
653                         for (int x = 0; x < width; x++)
654                         {
655                             unsigned char r = sourcePixels[x * 4 + 2];
656                             unsigned char a = sourcePixels[x * 4 + 3];
657                             destPixels[x]   = ((a >> 4) << 4) | (r >> 4);
658                         }
659                         sourcePixels += sourceLock.Pitch;
660                         destPixels += destLock.Pitch;
661                     }
662                     break;
663                 default:
664                     UNREACHABLE();
665             }
666             break;
667         case D3DFMT_R5G6B5:
668             switch (getD3DFormat())
669             {
670                 case D3DFMT_X8R8G8B8:
671                     for (int y = 0; y < height; y++)
672                     {
673                         for (int x = 0; x < width; x++)
674                         {
675                             unsigned short rgb  = ((unsigned short *)sourcePixels)[x];
676                             unsigned char red   = static_cast<unsigned char>((rgb & 0xF800) >> 8);
677                             unsigned char green = static_cast<unsigned char>((rgb & 0x07E0) >> 3);
678                             unsigned char blue  = static_cast<unsigned char>((rgb & 0x001F) << 3);
679                             destPixels[x + 0]   = blue | (blue >> 5);
680                             destPixels[x + 1]   = green | (green >> 6);
681                             destPixels[x + 2]   = red | (red >> 5);
682                             destPixels[x + 3]   = 0xFF;
683                         }
684                         sourcePixels += sourceLock.Pitch;
685                         destPixels += destLock.Pitch;
686                     }
687                     break;
688                 case D3DFMT_L8:
689                     for (int y = 0; y < height; y++)
690                     {
691                         for (int x = 0; x < width; x++)
692                         {
693                             unsigned char red = sourcePixels[x * 2 + 1] & 0xF8;
694                             destPixels[x]     = red | (red >> 5);
695                         }
696                         sourcePixels += sourceLock.Pitch;
697                         destPixels += destLock.Pitch;
698                     }
699                     break;
700                 default:
701                     UNREACHABLE();
702             }
703             break;
704         case D3DFMT_A1R5G5B5:
705             switch (getD3DFormat())
706             {
707                 case D3DFMT_X8R8G8B8:
708                     for (int y = 0; y < height; y++)
709                     {
710                         for (int x = 0; x < width; x++)
711                         {
712                             unsigned short argb = ((unsigned short *)sourcePixels)[x];
713                             unsigned char red   = static_cast<unsigned char>((argb & 0x7C00) >> 7);
714                             unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2);
715                             unsigned char blue  = static_cast<unsigned char>((argb & 0x001F) << 3);
716                             destPixels[x + 0]   = blue | (blue >> 5);
717                             destPixels[x + 1]   = green | (green >> 5);
718                             destPixels[x + 2]   = red | (red >> 5);
719                             destPixels[x + 3]   = 0xFF;
720                         }
721                         sourcePixels += sourceLock.Pitch;
722                         destPixels += destLock.Pitch;
723                     }
724                     break;
725                 case D3DFMT_A8R8G8B8:
726                     for (int y = 0; y < height; y++)
727                     {
728                         for (int x = 0; x < width; x++)
729                         {
730                             unsigned short argb = ((unsigned short *)sourcePixels)[x];
731                             unsigned char red   = static_cast<unsigned char>((argb & 0x7C00) >> 7);
732                             unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2);
733                             unsigned char blue  = static_cast<unsigned char>((argb & 0x001F) << 3);
734                             unsigned char alpha = (signed short)argb >> 15;
735                             destPixels[x + 0]   = blue | (blue >> 5);
736                             destPixels[x + 1]   = green | (green >> 5);
737                             destPixels[x + 2]   = red | (red >> 5);
738                             destPixels[x + 3]   = alpha;
739                         }
740                         sourcePixels += sourceLock.Pitch;
741                         destPixels += destLock.Pitch;
742                     }
743                     break;
744                 case D3DFMT_L8:
745                     for (int y = 0; y < height; y++)
746                     {
747                         for (int x = 0; x < width; x++)
748                         {
749                             unsigned char red = sourcePixels[x * 2 + 1] & 0x7C;
750                             destPixels[x]     = (red << 1) | (red >> 4);
751                         }
752                         sourcePixels += sourceLock.Pitch;
753                         destPixels += destLock.Pitch;
754                     }
755                     break;
756                 case D3DFMT_A8L8:
757                     for (int y = 0; y < height; y++)
758                     {
759                         for (int x = 0; x < width; x++)
760                         {
761                             unsigned char red     = sourcePixels[x * 2 + 1] & 0x7C;
762                             destPixels[x * 2 + 0] = (red << 1) | (red >> 4);
763                             destPixels[x * 2 + 1] = (signed char)sourcePixels[x * 2 + 1] >> 7;
764                         }
765                         sourcePixels += sourceLock.Pitch;
766                         destPixels += destLock.Pitch;
767                     }
768                     break;
769                 case D3DFMT_A4L4:
770                     for (int y = 0; y < height; y++)
771                     {
772                         for (int x = 0; x < width; x++)
773                         {
774                             unsigned char r = (sourcePixels[x * 2 + 1] & 0x7C) >> 3;
775                             unsigned char a = (sourcePixels[x * 2 + 1] >> 7) ? 0xF : 0x0;
776                             destPixels[x]   = (a << 4) | (r >> 3);
777                         }
778                         sourcePixels += sourceLock.Pitch;
779                         destPixels += destLock.Pitch;
780                     }
781                     break;
782                 default:
783                     UNREACHABLE();
784             }
785             break;
786         case D3DFMT_A16B16G16R16F:
787             switch (getD3DFormat())
788             {
789                 case D3DFMT_X8R8G8B8:
790                 case D3DFMT_A8R8G8B8:
791                     for (int y = 0; y < height; y++)
792                     {
793                         const uint16_t *sourcePixels16F =
794                             reinterpret_cast<uint16_t *>(sourcePixels);
795                         for (int x = 0; x < width; x++)
796                         {
797                             float r = gl::float16ToFloat32(sourcePixels16F[x * 4 + 0]);
798                             float g = gl::float16ToFloat32(sourcePixels16F[x * 4 + 1]);
799                             float b = gl::float16ToFloat32(sourcePixels16F[x * 4 + 2]);
800                             float a = gl::float16ToFloat32(sourcePixels16F[x * 4 + 3]);
801                             destPixels[x * 4 + 0] = gl::floatToNormalized<uint8_t>(b);
802                             destPixels[x * 4 + 1] = gl::floatToNormalized<uint8_t>(g);
803                             destPixels[x * 4 + 2] = gl::floatToNormalized<uint8_t>(r);
804                             destPixels[x * 4 + 3] = gl::floatToNormalized<uint8_t>(a);
805                         }
806                         sourcePixels += sourceLock.Pitch;
807                         destPixels += destLock.Pitch;
808                     }
809                     break;
810                 case D3DFMT_L8:
811                     for (int y = 0; y < height; y++)
812                     {
813                         const uint16_t *sourcePixels16F =
814                             reinterpret_cast<uint16_t *>(sourcePixels);
815                         for (int x = 0; x < width; x++)
816                         {
817                             float r       = gl::float16ToFloat32(sourcePixels16F[x * 4]);
818                             destPixels[x] = gl::floatToNormalized<uint8_t>(r);
819                         }
820                         sourcePixels += sourceLock.Pitch;
821                         destPixels += destLock.Pitch;
822                     }
823                     break;
824                 case D3DFMT_A8L8:
825                     for (int y = 0; y < height; y++)
826                     {
827                         const uint16_t *sourcePixels16F =
828                             reinterpret_cast<uint16_t *>(sourcePixels);
829                         for (int x = 0; x < width; x++)
830                         {
831                             float r = gl::float16ToFloat32(sourcePixels16F[x * 4 + 0]);
832                             float a = gl::float16ToFloat32(sourcePixels16F[x * 4 + 3]);
833                             destPixels[x * 2 + 0] = gl::floatToNormalized<uint8_t>(r);
834                             destPixels[x * 2 + 1] = gl::floatToNormalized<uint8_t>(a);
835                         }
836                         sourcePixels += sourceLock.Pitch;
837                         destPixels += destLock.Pitch;
838                     }
839                     break;
840                 case D3DFMT_A4L4:
841                     for (int y = 0; y < height; y++)
842                     {
843                         const uint16_t *sourcePixels16F =
844                             reinterpret_cast<uint16_t *>(sourcePixels);
845                         for (int x = 0; x < width; x++)
846                         {
847                             float r       = gl::float16ToFloat32(sourcePixels16F[x * 4 + 0]);
848                             float a       = gl::float16ToFloat32(sourcePixels16F[x * 4 + 3]);
849                             destPixels[x] = gl::floatToNormalized<4, uint8_t>(r) |
850                                             (gl::floatToNormalized<4, uint8_t>(a) << 4);
851                         }
852                         sourcePixels += sourceLock.Pitch;
853                         destPixels += destLock.Pitch;
854                     }
855                     break;
856                 default:
857                     UNREACHABLE();
858             }
859             break;
860         case D3DFMT_A32B32G32R32F:
861             switch (getD3DFormat())
862             {
863                 case D3DFMT_X8R8G8B8:
864                 case D3DFMT_A8R8G8B8:
865                     for (int y = 0; y < height; y++)
866                     {
867                         const float *sourcePixels32F = reinterpret_cast<float *>(sourcePixels);
868                         for (int x = 0; x < width; x++)
869                         {
870                             float r               = sourcePixels32F[x * 4 + 0];
871                             float g               = sourcePixels32F[x * 4 + 1];
872                             float b               = sourcePixels32F[x * 4 + 2];
873                             float a               = sourcePixels32F[x * 4 + 3];
874                             destPixels[x * 4 + 0] = gl::floatToNormalized<uint8_t>(b);
875                             destPixels[x * 4 + 1] = gl::floatToNormalized<uint8_t>(g);
876                             destPixels[x * 4 + 2] = gl::floatToNormalized<uint8_t>(r);
877                             destPixels[x * 4 + 3] = gl::floatToNormalized<uint8_t>(a);
878                         }
879                         sourcePixels += sourceLock.Pitch;
880                         destPixels += destLock.Pitch;
881                     }
882                     break;
883                 case D3DFMT_L8:
884                     for (int y = 0; y < height; y++)
885                     {
886                         const float *sourcePixels32F = reinterpret_cast<float *>(sourcePixels);
887                         for (int x = 0; x < width; x++)
888                         {
889                             float r       = sourcePixels32F[x * 4];
890                             destPixels[x] = gl::floatToNormalized<uint8_t>(r);
891                         }
892                         sourcePixels += sourceLock.Pitch;
893                         destPixels += destLock.Pitch;
894                     }
895                     break;
896                 case D3DFMT_A8L8:
897                     for (int y = 0; y < height; y++)
898                     {
899                         const float *sourcePixels32F = reinterpret_cast<float *>(sourcePixels);
900                         for (int x = 0; x < width; x++)
901                         {
902                             float r               = sourcePixels32F[x * 4 + 0];
903                             float a               = sourcePixels32F[x * 4 + 3];
904                             destPixels[x * 2 + 0] = gl::floatToNormalized<uint8_t>(r);
905                             destPixels[x * 2 + 1] = gl::floatToNormalized<uint8_t>(a);
906                         }
907                         sourcePixels += sourceLock.Pitch;
908                         destPixels += destLock.Pitch;
909                     }
910                     break;
911                 case D3DFMT_A4L4:
912                     for (int y = 0; y < height; y++)
913                     {
914                         const float *sourcePixels32F = reinterpret_cast<float *>(sourcePixels);
915                         for (int x = 0; x < width; x++)
916                         {
917                             float r       = sourcePixels32F[x * 4 + 0];
918                             float a       = sourcePixels32F[x * 4 + 3];
919                             destPixels[x] = gl::floatToNormalized<4, uint8_t>(r) |
920                                             (gl::floatToNormalized<4, uint8_t>(a) << 4);
921                         }
922                         sourcePixels += sourceLock.Pitch;
923                         destPixels += destLock.Pitch;
924                     }
925                     break;
926                 default:
927                     UNREACHABLE();
928             }
929             break;
930         default:
931             UNREACHABLE();
932     }
933 
934     unlock();
935     renderTargetData->UnlockRect();
936 
937     mDirty = true;
938     return angle::Result::Continue;
939 }
940 
copyFromTexStorage(const gl::Context * context,const gl::ImageIndex & imageIndex,TextureStorage * source)941 angle::Result Image9::copyFromTexStorage(const gl::Context *context,
942                                          const gl::ImageIndex &imageIndex,
943                                          TextureStorage *source)
944 {
945     RenderTargetD3D *renderTarget = nullptr;
946     ANGLE_TRY(source->getRenderTarget(context, imageIndex, 0, &renderTarget));
947 
948     gl::Rectangle sourceArea(0, 0, mWidth, mHeight);
949     return copyFromRTInternal(GetImplAs<Context9>(context), gl::Offset(), sourceArea, renderTarget);
950 }
951 
copyFromFramebuffer(const gl::Context * context,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,const gl::Framebuffer * source)952 angle::Result Image9::copyFromFramebuffer(const gl::Context *context,
953                                           const gl::Offset &destOffset,
954                                           const gl::Rectangle &sourceArea,
955                                           const gl::Framebuffer *source)
956 {
957     const gl::FramebufferAttachment *srcAttachment = source->getReadColorAttachment();
958     ASSERT(srcAttachment);
959 
960     RenderTargetD3D *renderTarget = nullptr;
961     ANGLE_TRY(srcAttachment->getRenderTarget(context, 0, &renderTarget));
962     ASSERT(renderTarget);
963     return copyFromRTInternal(GetImplAs<Context9>(context), destOffset, sourceArea, renderTarget);
964 }
965 
966 }  // namespace rx
967