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