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.
7 // Image9.cpp: Implements the rx::Image9 class, which acts as the interface to
8 // the actual underlying surfaces of a Texture.
10 #include "libGLESv2/renderer/d3d/d3d9/Image9.h"
11 #include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h"
12 #include "libGLESv2/renderer/d3d/d3d9/formatutils9.h"
13 #include "libGLESv2/renderer/d3d/d3d9/Renderer9.h"
14 #include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h"
15 #include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h"
16 #include "libGLESv2/main.h"
17 #include "libGLESv2/Framebuffer.h"
18 #include "libGLESv2/FramebufferAttachment.h"
19 #include "libGLESv2/Renderbuffer.h"
30 mD3DPool = D3DPOOL_SYSTEMMEM;
31 mD3DFormat = D3DFMT_UNKNOWN;
36 SafeRelease(mSurface);
39 void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface)
41 D3DSURFACE_DESC destDesc;
42 HRESULT result = destSurface->GetDesc(&destDesc);
43 ASSERT(SUCCEEDED(result));
45 D3DSURFACE_DESC sourceDesc;
46 result = sourceSurface->GetDesc(&sourceDesc);
47 ASSERT(SUCCEEDED(result));
49 ASSERT(sourceDesc.Format == destDesc.Format);
50 ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
51 ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height);
53 const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format);
54 ASSERT(d3dFormatInfo.mipGenerationFunction != NULL);
56 D3DLOCKED_RECT sourceLocked = {0};
57 result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY);
58 ASSERT(SUCCEEDED(result));
60 D3DLOCKED_RECT destLocked = {0};
61 result = destSurface->LockRect(&destLocked, NULL, 0);
62 ASSERT(SUCCEEDED(result));
64 const uint8_t *sourceData = reinterpret_cast<const uint8_t*>(sourceLocked.pBits);
65 uint8_t *destData = reinterpret_cast<uint8_t*>(destLocked.pBits);
67 if (sourceData && destData)
69 d3dFormatInfo.mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0,
70 destData, destLocked.Pitch, 0);
73 destSurface->UnlockRect();
74 sourceSurface->UnlockRect();
77 Image9 *Image9::makeImage9(Image *img)
79 ASSERT(HAS_DYNAMIC_TYPE(rx::Image9*, img));
80 return static_cast<rx::Image9*>(img);
83 void Image9::generateMipmap(Image9 *dest, Image9 *source)
85 IDirect3DSurface9 *sourceSurface = source->getSurface();
86 if (sourceSurface == NULL)
87 return gl::error(GL_OUT_OF_MEMORY);
89 IDirect3DSurface9 *destSurface = dest->getSurface();
90 generateMip(destSurface, sourceSurface);
95 void Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source)
97 D3DLOCKED_RECT sourceLock = {0};
98 D3DLOCKED_RECT destLock = {0};
100 source->LockRect(&sourceLock, NULL, 0);
101 dest->LockRect(&destLock, NULL, 0);
103 if (sourceLock.pBits && destLock.pBits)
105 D3DSURFACE_DESC desc;
106 source->GetDesc(&desc);
108 const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
109 unsigned int rows = desc.Height / d3dFormatInfo.blockHeight;
111 unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight);
112 ASSERT(bytes <= static_cast<unsigned int>(sourceLock.Pitch) &&
113 bytes <= static_cast<unsigned int>(destLock.Pitch));
115 for(unsigned int i = 0; i < rows; i++)
117 memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes);
120 source->UnlockRect();
126 bool Image9::redefine(rx::Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease)
128 // 3D textures are not supported by the D3D9 backend.
131 // Only 2D and cube texture are supported by the D3D9 backend.
132 ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP);
134 if (mWidth != width ||
137 mInternalFormat != internalformat ||
140 mRenderer = Renderer9::makeRenderer9(renderer);
145 mInternalFormat = internalformat;
147 // compute the d3d format that will be used
148 const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(internalformat);
149 const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat);
150 mD3DFormat = d3d9FormatInfo.texFormat;
151 mActualFormat = d3dFormatInfo.internalFormat;
152 mRenderable = (d3d9FormatInfo.renderFormat != D3DFMT_UNKNOWN);
154 SafeRelease(mSurface);
155 mDirty = (d3d9FormatInfo.dataInitializerFunction != NULL);
163 void Image9::createSurface()
170 IDirect3DTexture9 *newTexture = NULL;
171 IDirect3DSurface9 *newSurface = NULL;
172 const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM;
173 const D3DFORMAT d3dFormat = getD3DFormat();
175 if (mWidth != 0 && mHeight != 0)
177 int levelToFetch = 0;
178 GLsizei requestWidth = mWidth;
179 GLsizei requestHeight = mHeight;
180 d3d9::MakeValidSize(true, d3dFormat, &requestWidth, &requestHeight, &levelToFetch);
182 IDirect3DDevice9 *device = mRenderer->getDevice();
184 HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, d3dFormat,
185 poolToUse, &newTexture, NULL);
189 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
190 ERR("Creating image surface failed.");
191 return gl::error(GL_OUT_OF_MEMORY);
194 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
195 SafeRelease(newTexture);
197 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
198 if (d3dFormatInfo.dataInitializerFunction != NULL)
202 entireRect.right = mWidth;
204 entireRect.bottom = mHeight;
206 D3DLOCKED_RECT lockedRect;
207 result = newSurface->LockRect(&lockedRect, &entireRect, 0);
208 ASSERT(SUCCEEDED(result));
210 d3dFormatInfo.dataInitializerFunction(mWidth, mHeight, 1, reinterpret_cast<uint8_t*>(lockedRect.pBits),
211 lockedRect.Pitch, 0);
213 result = newSurface->UnlockRect();
214 ASSERT(SUCCEEDED(result));
218 mSurface = newSurface;
220 mD3DPool = poolToUse;
223 HRESULT Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
227 HRESULT result = D3DERR_INVALIDCALL;
231 result = mSurface->LockRect(lockedRect, rect, 0);
232 ASSERT(SUCCEEDED(result));
240 void Image9::unlock()
244 HRESULT result = mSurface->UnlockRect();
245 UNUSED_ASSERTION_VARIABLE(result);
246 ASSERT(SUCCEEDED(result));
250 D3DFORMAT Image9::getD3DFormat() const
252 // this should only happen if the image hasn't been redefined first
253 // which would be a bug by the caller
254 ASSERT(mD3DFormat != D3DFMT_UNKNOWN);
259 bool Image9::isDirty() const
261 // Make sure to that this image is marked as dirty even if the staging texture hasn't been created yet
262 // if initialization is required before use.
263 return (mSurface || d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) && mDirty;
266 IDirect3DSurface9 *Image9::getSurface()
273 void Image9::setManagedSurface2D(TextureStorage *storage, int level)
275 TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
276 setManagedSurface(storage9->getSurfaceLevel(level, false));
279 void Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level)
281 TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
282 setManagedSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false));
285 void Image9::setManagedSurface(IDirect3DSurface9 *surface)
287 D3DSURFACE_DESC desc;
288 surface->GetDesc(&desc);
289 ASSERT(desc.Pool == D3DPOOL_MANAGED);
291 if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight)
295 copyLockableSurfaces(surface, mSurface);
296 SafeRelease(mSurface);
300 mD3DPool = desc.Pool;
304 bool Image9::copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
306 ASSERT(getSurface() != NULL);
307 TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
308 return copyToSurface(storage9->getSurfaceLevel(level, true), xoffset, yoffset, width, height);
311 bool Image9::copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
313 ASSERT(getSurface() != NULL);
314 TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
315 return copyToSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height);
318 bool Image9::copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
320 // 3D textures are not supported by the D3D9 backend.
325 bool Image9::copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height)
327 // 2D array textures are not supported by the D3D9 backend.
332 bool Image9::copyToSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
334 ASSERT(width > 0 && height > 0);
339 IDirect3DSurface9 *sourceSurface = getSurface();
341 if (sourceSurface && sourceSurface != destSurface)
346 rect.right = xoffset + width;
347 rect.bottom = yoffset + height;
349 POINT point = {rect.left, rect.top};
351 IDirect3DDevice9 *device = mRenderer->getDevice();
353 if (mD3DPool == D3DPOOL_MANAGED)
355 D3DSURFACE_DESC desc;
356 sourceSurface->GetDesc(&desc);
358 IDirect3DSurface9 *surf = 0;
359 HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
361 if (SUCCEEDED(result))
363 copyLockableSurfaces(surf, sourceSurface);
364 result = device->UpdateSurface(surf, &rect, destSurface, &point);
365 ASSERT(SUCCEEDED(result));
371 // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
372 HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point);
373 UNUSED_ASSERTION_VARIABLE(result);
374 ASSERT(SUCCEEDED(result));
378 SafeRelease(destSurface);
382 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
383 // into the target pixel rectangle.
384 void Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
385 GLint unpackAlignment, GLenum type, const void *input)
387 // 3D textures are not supported by the D3D9 backend.
388 ASSERT(zoffset == 0 && depth == 1);
390 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
391 GLsizei inputRowPitch = formatInfo.computeRowPitch(type, width, unpackAlignment);
393 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
394 ASSERT(d3dFormatInfo.loadFunction != NULL);
399 xoffset + width, yoffset + height
402 D3DLOCKED_RECT locked;
403 HRESULT result = lock(&locked, &lockRect);
409 d3dFormatInfo.loadFunction(width, height, depth,
410 reinterpret_cast<const uint8_t*>(input), inputRowPitch, 0,
411 reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0);
416 void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
419 // 3D textures are not supported by the D3D9 backend.
420 ASSERT(zoffset == 0 && depth == 1);
422 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
423 GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, width, 1);
424 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
426 const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
428 ASSERT(xoffset % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockWidth == 0);
429 ASSERT(yoffset % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockHeight == 0);
431 ASSERT(d3d9FormatInfo.loadFunction != NULL);
436 xoffset + width, yoffset + height
439 D3DLOCKED_RECT locked;
440 HRESULT result = lock(&locked, &lockRect);
446 d3d9FormatInfo.loadFunction(width, height, depth,
447 reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch,
448 reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0);
453 // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
454 void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
456 // ES3.0 only behaviour to copy into a 3d texture
457 ASSERT(zoffset == 0);
459 RenderTarget9 *renderTarget = NULL;
460 IDirect3DSurface9 *surface = NULL;
461 gl::FramebufferAttachment *colorbuffer = source->getColorbuffer(0);
465 renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer);
470 surface = renderTarget->getSurface();
475 ERR("Failed to retrieve the render target.");
476 return gl::error(GL_OUT_OF_MEMORY);
479 IDirect3DDevice9 *device = mRenderer->getDevice();
481 IDirect3DSurface9 *renderTargetData = NULL;
482 D3DSURFACE_DESC description;
483 surface->GetDesc(&description);
485 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
489 ERR("Could not create matching destination surface.");
490 SafeRelease(surface);
491 return gl::error(GL_OUT_OF_MEMORY);
494 result = device->GetRenderTargetData(surface, renderTargetData);
498 ERR("GetRenderTargetData unexpectedly failed.");
499 SafeRelease(renderTargetData);
500 SafeRelease(surface);
501 return gl::error(GL_OUT_OF_MEMORY);
504 RECT sourceRect = {x, y, x + width, y + height};
505 RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
507 D3DLOCKED_RECT sourceLock = {0};
508 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
512 ERR("Failed to lock the source surface (rectangle might be invalid).");
513 SafeRelease(renderTargetData);
514 SafeRelease(surface);
515 return gl::error(GL_OUT_OF_MEMORY);
518 D3DLOCKED_RECT destLock = {0};
519 result = lock(&destLock, &destRect);
523 ERR("Failed to lock the destination surface (rectangle might be invalid).");
524 renderTargetData->UnlockRect();
525 SafeRelease(renderTargetData);
526 SafeRelease(surface);
527 return gl::error(GL_OUT_OF_MEMORY);
530 if (destLock.pBits && sourceLock.pBits)
532 unsigned char *source = (unsigned char*)sourceLock.pBits;
533 unsigned char *dest = (unsigned char*)destLock.pBits;
535 switch (description.Format)
537 case D3DFMT_X8R8G8B8:
538 case D3DFMT_A8R8G8B8:
539 switch(getD3DFormat())
541 case D3DFMT_X8R8G8B8:
542 case D3DFMT_A8R8G8B8:
543 for(int y = 0; y < height; y++)
545 memcpy(dest, source, 4 * width);
547 source += sourceLock.Pitch;
548 dest += destLock.Pitch;
552 for(int y = 0; y < height; y++)
554 for(int x = 0; x < width; x++)
556 dest[x] = source[x * 4 + 2];
559 source += sourceLock.Pitch;
560 dest += destLock.Pitch;
564 for(int y = 0; y < height; y++)
566 for(int x = 0; x < width; x++)
568 dest[x * 2 + 0] = source[x * 4 + 2];
569 dest[x * 2 + 1] = source[x * 4 + 3];
572 source += sourceLock.Pitch;
573 dest += destLock.Pitch;
581 switch(getD3DFormat())
583 case D3DFMT_X8R8G8B8:
584 for(int y = 0; y < height; y++)
586 for(int x = 0; x < width; x++)
588 unsigned short rgb = ((unsigned short*)source)[x];
589 unsigned char red = (rgb & 0xF800) >> 8;
590 unsigned char green = (rgb & 0x07E0) >> 3;
591 unsigned char blue = (rgb & 0x001F) << 3;
592 dest[x + 0] = blue | (blue >> 5);
593 dest[x + 1] = green | (green >> 6);
594 dest[x + 2] = red | (red >> 5);
598 source += sourceLock.Pitch;
599 dest += destLock.Pitch;
603 for(int y = 0; y < height; y++)
605 for(int x = 0; x < width; x++)
607 unsigned char red = source[x * 2 + 1] & 0xF8;
608 dest[x] = red | (red >> 5);
611 source += sourceLock.Pitch;
612 dest += destLock.Pitch;
619 case D3DFMT_A1R5G5B5:
620 switch(getD3DFormat())
622 case D3DFMT_X8R8G8B8:
623 for(int y = 0; y < height; y++)
625 for(int x = 0; x < width; x++)
627 unsigned short argb = ((unsigned short*)source)[x];
628 unsigned char red = (argb & 0x7C00) >> 7;
629 unsigned char green = (argb & 0x03E0) >> 2;
630 unsigned char blue = (argb & 0x001F) << 3;
631 dest[x + 0] = blue | (blue >> 5);
632 dest[x + 1] = green | (green >> 5);
633 dest[x + 2] = red | (red >> 5);
637 source += sourceLock.Pitch;
638 dest += destLock.Pitch;
641 case D3DFMT_A8R8G8B8:
642 for(int y = 0; y < height; y++)
644 for(int x = 0; x < width; x++)
646 unsigned short argb = ((unsigned short*)source)[x];
647 unsigned char red = (argb & 0x7C00) >> 7;
648 unsigned char green = (argb & 0x03E0) >> 2;
649 unsigned char blue = (argb & 0x001F) << 3;
650 unsigned char alpha = (signed short)argb >> 15;
651 dest[x + 0] = blue | (blue >> 5);
652 dest[x + 1] = green | (green >> 5);
653 dest[x + 2] = red | (red >> 5);
657 source += sourceLock.Pitch;
658 dest += destLock.Pitch;
662 for(int y = 0; y < height; y++)
664 for(int x = 0; x < width; x++)
666 unsigned char red = source[x * 2 + 1] & 0x7C;
667 dest[x] = (red << 1) | (red >> 4);
670 source += sourceLock.Pitch;
671 dest += destLock.Pitch;
675 for(int y = 0; y < height; y++)
677 for(int x = 0; x < width; x++)
679 unsigned char red = source[x * 2 + 1] & 0x7C;
680 dest[x * 2 + 0] = (red << 1) | (red >> 4);
681 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
684 source += sourceLock.Pitch;
685 dest += destLock.Pitch;
698 renderTargetData->UnlockRect();
700 SafeRelease(renderTargetData);
701 SafeRelease(surface);