blob: 9fe315bd39a92110e359ca36525b1936fd92e89a [file] [log] [blame]
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +00001//
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// Image.cpp: Implements the gl::Image class, which acts as the interface to
8// the actual underlying surfaces of a Texture.
9
10#include "libGLESv2/renderer/Image.h"
11
12#include "libEGL/Display.h"
13
14#include "libGLESv2/main.h"
15#include "libGLESv2/mathutil.h"
16#include "libGLESv2/utilities.h"
17#include "libGLESv2/Texture.h"
daniel@transgaming.com3cef5392012-10-31 19:52:15 +000018#include "libGLESv2/Framebuffer.h"
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +000019
20namespace gl
21{
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +000022
23namespace
24{
25struct L8
26{
27 unsigned char L;
28
29 static void average(L8 *dst, const L8 *src1, const L8 *src2)
30 {
31 dst->L = ((src1->L ^ src2->L) >> 1) + (src1->L & src2->L);
32 }
33};
34
35struct A8L8
36{
37 unsigned char L;
38 unsigned char A;
39
40 static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2)
41 {
42 *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2);
43 }
44};
45
46struct A8R8G8B8
47{
48 unsigned char B;
49 unsigned char G;
50 unsigned char R;
51 unsigned char A;
52
53 static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2)
54 {
55 *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2);
56 }
57};
58
59struct A16B16G16R16F
60{
61 unsigned short R;
62 unsigned short G;
63 unsigned short B;
64 unsigned short A;
65
66 static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2)
67 {
68 dst->R = float32ToFloat16((float16ToFloat32(src1->R) + float16ToFloat32(src2->R)) * 0.5f);
69 dst->G = float32ToFloat16((float16ToFloat32(src1->G) + float16ToFloat32(src2->G)) * 0.5f);
70 dst->B = float32ToFloat16((float16ToFloat32(src1->B) + float16ToFloat32(src2->B)) * 0.5f);
71 dst->A = float32ToFloat16((float16ToFloat32(src1->A) + float16ToFloat32(src2->A)) * 0.5f);
72 }
73};
74
75struct A32B32G32R32F
76{
77 float R;
78 float G;
79 float B;
80 float A;
81
82 static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2)
83 {
84 dst->R = (src1->R + src2->R) * 0.5f;
85 dst->G = (src1->G + src2->G) * 0.5f;
86 dst->B = (src1->B + src2->B) * 0.5f;
87 dst->A = (src1->A + src2->A) * 0.5f;
88 }
89};
90
91template <typename T>
92void GenerateMip(unsigned int sourceWidth, unsigned int sourceHeight,
93 const unsigned char *sourceData, int sourcePitch,
94 unsigned char *destData, int destPitch)
95{
96 unsigned int mipWidth = std::max(1U, sourceWidth >> 1);
97 unsigned int mipHeight = std::max(1U, sourceHeight >> 1);
98
99 if (sourceHeight == 1)
100 {
101 ASSERT(sourceWidth != 1);
102
103 const T *src = (const T*)sourceData;
104 T *dst = (T*)destData;
105
106 for (unsigned int x = 0; x < mipWidth; x++)
107 {
108 T::average(&dst[x], &src[x * 2], &src[x * 2 + 1]);
109 }
110 }
111 else if (sourceWidth == 1)
112 {
113 ASSERT(sourceHeight != 1);
114
115 for (unsigned int y = 0; y < mipHeight; y++)
116 {
117 const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch);
118 const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch);
119 T *dst = (T*)(destData + y * destPitch);
120
121 T::average(dst, src0, src1);
122 }
123 }
124 else
125 {
126 for (unsigned int y = 0; y < mipHeight; y++)
127 {
128 const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch);
129 const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch);
130 T *dst = (T*)(destData + y * destPitch);
131
132 for (unsigned int x = 0; x < mipWidth; x++)
133 {
134 T tmp0;
135 T tmp1;
136
137 T::average(&tmp0, &src0[x * 2], &src0[x * 2 + 1]);
138 T::average(&tmp1, &src1[x * 2], &src1[x * 2 + 1]);
139 T::average(&dst[x], &tmp0, &tmp1);
140 }
141 }
142 }
143}
144
145void GenerateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface)
146{
147 D3DSURFACE_DESC destDesc;
148 HRESULT result = destSurface->GetDesc(&destDesc);
149 ASSERT(SUCCEEDED(result));
150
151 D3DSURFACE_DESC sourceDesc;
152 result = sourceSurface->GetDesc(&sourceDesc);
153 ASSERT(SUCCEEDED(result));
154
155 ASSERT(sourceDesc.Format == destDesc.Format);
156 ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
157 ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height);
158
159 D3DLOCKED_RECT sourceLocked = {0};
160 result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY);
161 ASSERT(SUCCEEDED(result));
162
163 D3DLOCKED_RECT destLocked = {0};
164 result = destSurface->LockRect(&destLocked, NULL, 0);
165 ASSERT(SUCCEEDED(result));
166
167 const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(sourceLocked.pBits);
168 unsigned char *destData = reinterpret_cast<unsigned char*>(destLocked.pBits);
169
170 if (sourceData && destData)
171 {
172 switch (sourceDesc.Format)
173 {
174 case D3DFMT_L8:
175 GenerateMip<L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
176 break;
177 case D3DFMT_A8L8:
178 GenerateMip<A8L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
179 break;
180 case D3DFMT_A8R8G8B8:
181 case D3DFMT_X8R8G8B8:
182 GenerateMip<A8R8G8B8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
183 break;
184 case D3DFMT_A16B16G16R16F:
185 GenerateMip<A16B16G16R16F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
186 break;
187 case D3DFMT_A32B32G32R32F:
188 GenerateMip<A32B32G32R32F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
189 break;
190 default:
191 UNREACHABLE();
192 break;
193 }
194
195 destSurface->UnlockRect();
196 sourceSurface->UnlockRect();
197 }
198}
199}
200
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000201Image::Image()
202{
203 mWidth = 0;
204 mHeight = 0;
205 mInternalFormat = GL_NONE;
206
207 mSurface = NULL;
208
209 mDirty = false;
210
211 mD3DPool = D3DPOOL_SYSTEMMEM;
212 mD3DFormat = D3DFMT_UNKNOWN;
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000213 mActualFormat = GL_NONE;
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000214}
215
216Image::~Image()
217{
218 if (mSurface)
219 {
220 mSurface->Release();
221 }
222}
223
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000224void Image::GenerateMipmap(Image *dest, Image *source)
225{
226 IDirect3DSurface9 *sourceSurface = source->getSurface();
227 if (sourceSurface == NULL)
228 return error(GL_OUT_OF_MEMORY);
229
230 IDirect3DSurface9 *destSurface = dest->getSurface();
231 GenerateMip(destSurface, sourceSurface);
232
233 source->markDirty();
234}
235
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000236void Image::CopyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source)
237{
238 D3DLOCKED_RECT sourceLock = {0};
239 D3DLOCKED_RECT destLock = {0};
240
241 source->LockRect(&sourceLock, NULL, 0);
242 dest->LockRect(&destLock, NULL, 0);
243
244 if (sourceLock.pBits && destLock.pBits)
245 {
246 D3DSURFACE_DESC desc;
247 source->GetDesc(&desc);
248
249 int rows = dx::IsCompressedFormat(desc.Format) ? desc.Height / 4 : desc.Height;
250 int bytes = dx::ComputeRowSize(desc.Format, desc.Width);
251 ASSERT(bytes <= sourceLock.Pitch && bytes <= destLock.Pitch);
252
253 for(int i = 0; i < rows; i++)
254 {
255 memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes);
256 }
257
258 source->UnlockRect();
259 dest->UnlockRect();
260 }
261 else UNREACHABLE();
262}
263
264bool Image::redefine(GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
265{
266 if (mWidth != width ||
267 mHeight != height ||
268 mInternalFormat != internalformat ||
269 forceRelease)
270 {
271 mWidth = width;
272 mHeight = height;
273 mInternalFormat = internalformat;
274 // compute the d3d format that will be used
daniel@transgaming.comdf14c762012-10-31 19:51:48 +0000275 mD3DFormat = TextureStorage::ConvertTextureInternalFormat(internalformat);
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000276 mActualFormat = dx2es::GetEquivalentFormat(mD3DFormat);
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000277
278 if (mSurface)
279 {
280 mSurface->Release();
281 mSurface = NULL;
282 }
283
284 return true;
285 }
286
287 return false;
288}
289
290void Image::createSurface()
291{
292 if(mSurface)
293 {
294 return;
295 }
296
297 IDirect3DTexture9 *newTexture = NULL;
298 IDirect3DSurface9 *newSurface = NULL;
299 const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM;
300 const D3DFORMAT d3dFormat = getD3DFormat();
301 ASSERT(d3dFormat != D3DFMT_INTZ); // We should never get here for depth textures
302
303 if (mWidth != 0 && mHeight != 0)
304 {
305 int levelToFetch = 0;
306 GLsizei requestWidth = mWidth;
307 GLsizei requestHeight = mHeight;
308 MakeValidSize(true, IsCompressed(mInternalFormat), &requestWidth, &requestHeight, &levelToFetch);
309
310 // D3D9_REPLACE
311 IDirect3DDevice9 *device = getDisplay()->getRenderer()->getDevice();
312 HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, d3dFormat,
313 poolToUse, &newTexture, NULL);
314
315 if (FAILED(result))
316 {
317 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
318 ERR("Creating image surface failed.");
319 return error(GL_OUT_OF_MEMORY);
320 }
321
322 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
323 newTexture->Release();
324 }
325
326 mSurface = newSurface;
327 mDirty = false;
328 mD3DPool = poolToUse;
329}
330
331HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
332{
333 createSurface();
334
335 HRESULT result = D3DERR_INVALIDCALL;
336
337 if (mSurface)
338 {
339 result = mSurface->LockRect(lockedRect, rect, 0);
340 ASSERT(SUCCEEDED(result));
341
342 mDirty = true;
343 }
344
345 return result;
346}
347
348void Image::unlock()
349{
350 if (mSurface)
351 {
352 HRESULT result = mSurface->UnlockRect();
353 ASSERT(SUCCEEDED(result));
354 }
355}
356
357bool Image::isRenderableFormat() const
358{
daniel@transgaming.comdf14c762012-10-31 19:51:48 +0000359 return TextureStorage::IsTextureFormatRenderable(getD3DFormat());
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000360}
361
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000362GLenum Image::getActualFormat() const
363{
364 return mActualFormat;
365}
366
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000367D3DFORMAT Image::getD3DFormat() const
368{
369 // this should only happen if the image hasn't been redefined first
370 // which would be a bug by the caller
371 ASSERT(mD3DFormat != D3DFMT_UNKNOWN);
372
373 return mD3DFormat;
374}
375
376IDirect3DSurface9 *Image::getSurface()
377{
378 createSurface();
379
380 return mSurface;
381}
382
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000383void Image::setManagedSurface(TextureStorage2D *storage, int level)
384{
385 setManagedSurface(storage->getSurfaceLevel(level, false));
386}
387
388void Image::setManagedSurface(TextureStorageCubeMap *storage, int face, int level)
389{
390 setManagedSurface(storage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false));
391}
392
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000393void Image::setManagedSurface(IDirect3DSurface9 *surface)
394{
395 D3DSURFACE_DESC desc;
396 surface->GetDesc(&desc);
397 ASSERT(desc.Pool == D3DPOOL_MANAGED);
398
399 if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight)
400 {
401 if (mSurface)
402 {
403 CopyLockableSurfaces(surface, mSurface);
404 mSurface->Release();
405 }
406
407 mSurface = surface;
408 mD3DPool = desc.Pool;
409 }
410}
411
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000412bool Image::updateSurface(TextureStorage2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000413{
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000414 return updateSurface(storage->getSurfaceLevel(level, true), xoffset, yoffset, width, height);
415}
416
417bool Image::updateSurface(TextureStorageCubeMap *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
418{
419 return updateSurface(storage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height);
420}
421
422bool Image::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
423{
424 if (!destSurface)
425 return false;
426
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000427 IDirect3DSurface9 *sourceSurface = getSurface();
428
429 if (sourceSurface && sourceSurface != destSurface)
430 {
431 RECT rect;
432 rect.left = xoffset;
433 rect.top = yoffset;
434 rect.right = xoffset + width;
435 rect.bottom = yoffset + height;
436
437 POINT point = {rect.left, rect.top};
438 IDirect3DDevice9 *device = getDisplay()->getRenderer()->getDevice(); // D3D9_REPLACE
439
440 if (mD3DPool == D3DPOOL_MANAGED)
441 {
442 D3DSURFACE_DESC desc;
443 sourceSurface->GetDesc(&desc);
444
445 IDirect3DSurface9 *surf = 0;
446 HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
447
448 if (SUCCEEDED(result))
449 {
450 CopyLockableSurfaces(surf, sourceSurface);
451 result = device->UpdateSurface(surf, &rect, destSurface, &point);
452 ASSERT(SUCCEEDED(result));
453 surf->Release();
454 }
455 }
456 else
457 {
458 // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
459 HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point);
460 ASSERT(SUCCEEDED(result));
461 }
462 }
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000463
464 destSurface->Release();
465 return true;
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000466}
467
468// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
469// into the target pixel rectangle.
470void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
471 GLint unpackAlignment, const void *input)
472{
473 RECT lockRect =
474 {
475 xoffset, yoffset,
476 xoffset + width, yoffset + height
477 };
478
479 D3DLOCKED_RECT locked;
480 HRESULT result = lock(&locked, &lockRect);
481 if (FAILED(result))
482 {
483 return;
484 }
485
486
487 GLsizei inputPitch = ComputePitch(width, mInternalFormat, unpackAlignment);
488
489 switch (mInternalFormat)
490 {
491 case GL_ALPHA8_EXT:
492 if (supportsSSE2())
493 {
494 loadAlphaDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
495 }
496 else
497 {
498 loadAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
499 }
500 break;
501 case GL_LUMINANCE8_EXT:
502 loadLuminanceData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_L8);
503 break;
504 case GL_ALPHA32F_EXT:
505 loadAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
506 break;
507 case GL_LUMINANCE32F_EXT:
508 loadLuminanceFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
509 break;
510 case GL_ALPHA16F_EXT:
511 loadAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
512 break;
513 case GL_LUMINANCE16F_EXT:
514 loadLuminanceHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
515 break;
516 case GL_LUMINANCE8_ALPHA8_EXT:
517 loadLuminanceAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_A8L8);
518 break;
519 case GL_LUMINANCE_ALPHA32F_EXT:
520 loadLuminanceAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
521 break;
522 case GL_LUMINANCE_ALPHA16F_EXT:
523 loadLuminanceAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
524 break;
525 case GL_RGB8_OES:
526 loadRGBUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
527 break;
528 case GL_RGB565:
529 loadRGB565Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
530 break;
531 case GL_RGBA8_OES:
532 if (supportsSSE2())
533 {
534 loadRGBAUByteDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
535 }
536 else
537 {
538 loadRGBAUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
539 }
540 break;
541 case GL_RGBA4:
542 loadRGBA4444Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
543 break;
544 case GL_RGB5_A1:
545 loadRGBA5551Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
546 break;
547 case GL_BGRA8_EXT:
548 loadBGRAData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
549 break;
550 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
551 case GL_RGB32F_EXT:
552 loadRGBFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
553 break;
554 case GL_RGB16F_EXT:
555 loadRGBHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
556 break;
557 case GL_RGBA32F_EXT:
558 loadRGBAFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
559 break;
560 case GL_RGBA16F_EXT:
561 loadRGBAHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
562 break;
563 default: UNREACHABLE();
564 }
565
566 unlock();
567}
568
569void Image::loadAlphaData(GLsizei width, GLsizei height,
570 int inputPitch, const void *input, size_t outputPitch, void *output) const
571{
572 const unsigned char *source = NULL;
573 unsigned char *dest = NULL;
574
575 for (int y = 0; y < height; y++)
576 {
577 source = static_cast<const unsigned char*>(input) + y * inputPitch;
578 dest = static_cast<unsigned char*>(output) + y * outputPitch;
579 for (int x = 0; x < width; x++)
580 {
581 dest[4 * x + 0] = 0;
582 dest[4 * x + 1] = 0;
583 dest[4 * x + 2] = 0;
584 dest[4 * x + 3] = source[x];
585 }
586 }
587}
588
589void Image::loadAlphaFloatData(GLsizei width, GLsizei height,
590 int inputPitch, const void *input, size_t outputPitch, void *output) const
591{
592 const float *source = NULL;
593 float *dest = NULL;
594
595 for (int y = 0; y < height; y++)
596 {
597 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
598 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
599 for (int x = 0; x < width; x++)
600 {
601 dest[4 * x + 0] = 0;
602 dest[4 * x + 1] = 0;
603 dest[4 * x + 2] = 0;
604 dest[4 * x + 3] = source[x];
605 }
606 }
607}
608
609void Image::loadAlphaHalfFloatData(GLsizei width, GLsizei height,
610 int inputPitch, const void *input, size_t outputPitch, void *output) const
611{
612 const unsigned short *source = NULL;
613 unsigned short *dest = NULL;
614
615 for (int y = 0; y < height; y++)
616 {
617 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
618 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
619 for (int x = 0; x < width; x++)
620 {
621 dest[4 * x + 0] = 0;
622 dest[4 * x + 1] = 0;
623 dest[4 * x + 2] = 0;
624 dest[4 * x + 3] = source[x];
625 }
626 }
627}
628
629void Image::loadLuminanceData(GLsizei width, GLsizei height,
630 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
631{
632 const unsigned char *source = NULL;
633 unsigned char *dest = NULL;
634
635 for (int y = 0; y < height; y++)
636 {
637 source = static_cast<const unsigned char*>(input) + y * inputPitch;
638 dest = static_cast<unsigned char*>(output) + y * outputPitch;
639
640 if (!native) // BGRA8 destination format
641 {
642 for (int x = 0; x < width; x++)
643 {
644 dest[4 * x + 0] = source[x];
645 dest[4 * x + 1] = source[x];
646 dest[4 * x + 2] = source[x];
647 dest[4 * x + 3] = 0xFF;
648 }
649 }
650 else // L8 destination format
651 {
652 memcpy(dest, source, width);
653 }
654 }
655}
656
657void Image::loadLuminanceFloatData(GLsizei width, GLsizei height,
658 int inputPitch, const void *input, size_t outputPitch, void *output) const
659{
660 const float *source = NULL;
661 float *dest = NULL;
662
663 for (int y = 0; y < height; y++)
664 {
665 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
666 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
667 for (int x = 0; x < width; x++)
668 {
669 dest[4 * x + 0] = source[x];
670 dest[4 * x + 1] = source[x];
671 dest[4 * x + 2] = source[x];
672 dest[4 * x + 3] = 1.0f;
673 }
674 }
675}
676
677void Image::loadLuminanceHalfFloatData(GLsizei width, GLsizei height,
678 int inputPitch, const void *input, size_t outputPitch, void *output) const
679{
680 const unsigned short *source = NULL;
681 unsigned short *dest = NULL;
682
683 for (int y = 0; y < height; y++)
684 {
685 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
686 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
687 for (int x = 0; x < width; x++)
688 {
689 dest[4 * x + 0] = source[x];
690 dest[4 * x + 1] = source[x];
691 dest[4 * x + 2] = source[x];
692 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
693 }
694 }
695}
696
697void Image::loadLuminanceAlphaData(GLsizei width, GLsizei height,
698 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
699{
700 const unsigned char *source = NULL;
701 unsigned char *dest = NULL;
702
703 for (int y = 0; y < height; y++)
704 {
705 source = static_cast<const unsigned char*>(input) + y * inputPitch;
706 dest = static_cast<unsigned char*>(output) + y * outputPitch;
707
708 if (!native) // BGRA8 destination format
709 {
710 for (int x = 0; x < width; x++)
711 {
712 dest[4 * x + 0] = source[2*x+0];
713 dest[4 * x + 1] = source[2*x+0];
714 dest[4 * x + 2] = source[2*x+0];
715 dest[4 * x + 3] = source[2*x+1];
716 }
717 }
718 else
719 {
720 memcpy(dest, source, width * 2);
721 }
722 }
723}
724
725void Image::loadLuminanceAlphaFloatData(GLsizei width, GLsizei height,
726 int inputPitch, const void *input, size_t outputPitch, void *output) const
727{
728 const float *source = NULL;
729 float *dest = NULL;
730
731 for (int y = 0; y < height; y++)
732 {
733 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
734 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
735 for (int x = 0; x < width; x++)
736 {
737 dest[4 * x + 0] = source[2*x+0];
738 dest[4 * x + 1] = source[2*x+0];
739 dest[4 * x + 2] = source[2*x+0];
740 dest[4 * x + 3] = source[2*x+1];
741 }
742 }
743}
744
745void Image::loadLuminanceAlphaHalfFloatData(GLsizei width, GLsizei height,
746 int inputPitch, const void *input, size_t outputPitch, void *output) const
747{
748 const unsigned short *source = NULL;
749 unsigned short *dest = NULL;
750
751 for (int y = 0; y < height; y++)
752 {
753 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
754 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
755 for (int x = 0; x < width; x++)
756 {
757 dest[4 * x + 0] = source[2*x+0];
758 dest[4 * x + 1] = source[2*x+0];
759 dest[4 * x + 2] = source[2*x+0];
760 dest[4 * x + 3] = source[2*x+1];
761 }
762 }
763}
764
765void Image::loadRGBUByteData(GLsizei width, GLsizei height,
766 int inputPitch, const void *input, size_t outputPitch, void *output) const
767{
768 const unsigned char *source = NULL;
769 unsigned char *dest = NULL;
770
771 for (int y = 0; y < height; y++)
772 {
773 source = static_cast<const unsigned char*>(input) + y * inputPitch;
774 dest = static_cast<unsigned char*>(output) + y * outputPitch;
775 for (int x = 0; x < width; x++)
776 {
777 dest[4 * x + 0] = source[x * 3 + 2];
778 dest[4 * x + 1] = source[x * 3 + 1];
779 dest[4 * x + 2] = source[x * 3 + 0];
780 dest[4 * x + 3] = 0xFF;
781 }
782 }
783}
784
785void Image::loadRGB565Data(GLsizei width, GLsizei height,
786 int inputPitch, const void *input, size_t outputPitch, void *output) const
787{
788 const unsigned short *source = NULL;
789 unsigned char *dest = NULL;
790
791 for (int y = 0; y < height; y++)
792 {
793 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
794 dest = static_cast<unsigned char*>(output) + y * outputPitch;
795 for (int x = 0; x < width; x++)
796 {
797 unsigned short rgba = source[x];
798 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
799 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
800 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
801 dest[4 * x + 3] = 0xFF;
802 }
803 }
804}
805
806void Image::loadRGBFloatData(GLsizei width, GLsizei height,
807 int inputPitch, const void *input, size_t outputPitch, void *output) const
808{
809 const float *source = NULL;
810 float *dest = NULL;
811
812 for (int y = 0; y < height; y++)
813 {
814 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
815 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
816 for (int x = 0; x < width; x++)
817 {
818 dest[4 * x + 0] = source[x * 3 + 0];
819 dest[4 * x + 1] = source[x * 3 + 1];
820 dest[4 * x + 2] = source[x * 3 + 2];
821 dest[4 * x + 3] = 1.0f;
822 }
823 }
824}
825
826void Image::loadRGBHalfFloatData(GLsizei width, GLsizei height,
827 int inputPitch, const void *input, size_t outputPitch, void *output) const
828{
829 const unsigned short *source = NULL;
830 unsigned short *dest = NULL;
831
832 for (int y = 0; y < height; y++)
833 {
834 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
835 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
836 for (int x = 0; x < width; x++)
837 {
838 dest[4 * x + 0] = source[x * 3 + 0];
839 dest[4 * x + 1] = source[x * 3 + 1];
840 dest[4 * x + 2] = source[x * 3 + 2];
841 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
842 }
843 }
844}
845
846void Image::loadRGBAUByteData(GLsizei width, GLsizei height,
847 int inputPitch, const void *input, size_t outputPitch, void *output) const
848{
849 const unsigned int *source = NULL;
850 unsigned int *dest = NULL;
851 for (int y = 0; y < height; y++)
852 {
853 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
854 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
855
856 for (int x = 0; x < width; x++)
857 {
858 unsigned int rgba = source[x];
859 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
860 }
861 }
862}
863
864void Image::loadRGBA4444Data(GLsizei width, GLsizei height,
865 int inputPitch, const void *input, size_t outputPitch, void *output) const
866{
867 const unsigned short *source = NULL;
868 unsigned char *dest = NULL;
869
870 for (int y = 0; y < height; y++)
871 {
872 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
873 dest = static_cast<unsigned char*>(output) + y * outputPitch;
874 for (int x = 0; x < width; x++)
875 {
876 unsigned short rgba = source[x];
877 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
878 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
879 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
880 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
881 }
882 }
883}
884
885void Image::loadRGBA5551Data(GLsizei width, GLsizei height,
886 int inputPitch, const void *input, size_t outputPitch, void *output) const
887{
888 const unsigned short *source = NULL;
889 unsigned char *dest = NULL;
890
891 for (int y = 0; y < height; y++)
892 {
893 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
894 dest = static_cast<unsigned char*>(output) + y * outputPitch;
895 for (int x = 0; x < width; x++)
896 {
897 unsigned short rgba = source[x];
898 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
899 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
900 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
901 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
902 }
903 }
904}
905
906void Image::loadRGBAFloatData(GLsizei width, GLsizei height,
907 int inputPitch, const void *input, size_t outputPitch, void *output) const
908{
909 const float *source = NULL;
910 float *dest = NULL;
911
912 for (int y = 0; y < height; y++)
913 {
914 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
915 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
916 memcpy(dest, source, width * 16);
917 }
918}
919
920void Image::loadRGBAHalfFloatData(GLsizei width, GLsizei height,
921 int inputPitch, const void *input, size_t outputPitch, void *output) const
922{
923 const unsigned char *source = NULL;
924 unsigned char *dest = NULL;
925
926 for (int y = 0; y < height; y++)
927 {
928 source = static_cast<const unsigned char*>(input) + y * inputPitch;
929 dest = static_cast<unsigned char*>(output) + y * outputPitch;
930 memcpy(dest, source, width * 8);
931 }
932}
933
934void Image::loadBGRAData(GLsizei width, GLsizei height,
935 int inputPitch, const void *input, size_t outputPitch, void *output) const
936{
937 const unsigned char *source = NULL;
938 unsigned char *dest = NULL;
939
940 for (int y = 0; y < height; y++)
941 {
942 source = static_cast<const unsigned char*>(input) + y * inputPitch;
943 dest = static_cast<unsigned char*>(output) + y * outputPitch;
944 memcpy(dest, source, width*4);
945 }
946}
947
948void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
949 const void *input) {
950 ASSERT(xoffset % 4 == 0);
951 ASSERT(yoffset % 4 == 0);
952
953 RECT lockRect = {
954 xoffset, yoffset,
955 xoffset + width, yoffset + height
956 };
957
958 D3DLOCKED_RECT locked;
959 HRESULT result = lock(&locked, &lockRect);
960 if (FAILED(result))
961 {
962 return;
963 }
964
965 GLsizei inputSize = ComputeCompressedSize(width, height, mInternalFormat);
966 GLsizei inputPitch = ComputeCompressedPitch(width, mInternalFormat);
967 int rows = inputSize / inputPitch;
968 for (int i = 0; i < rows; ++i)
969 {
970 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
971 }
972
973 unlock();
974}
975
976// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
daniel@transgaming.com3cef5392012-10-31 19:52:15 +0000977void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000978{
daniel@transgaming.com3cef5392012-10-31 19:52:15 +0000979 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
980
981 if (!renderTarget)
982 {
983 ERR("Failed to retrieve the render target.");
984 return error(GL_OUT_OF_MEMORY);
985 }
986
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000987 IDirect3DDevice9 *device = getDisplay()->getRenderer()->getDevice(); // D3D9_REPLACE
988 IDirect3DSurface9 *renderTargetData = NULL;
989 D3DSURFACE_DESC description;
990 renderTarget->GetDesc(&description);
991
992 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
993
994 if (FAILED(result))
995 {
996 ERR("Could not create matching destination surface.");
daniel@transgaming.com3cef5392012-10-31 19:52:15 +0000997 renderTarget->Release();
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000998 return error(GL_OUT_OF_MEMORY);
999 }
1000
1001 result = device->GetRenderTargetData(renderTarget, renderTargetData);
1002
1003 if (FAILED(result))
1004 {
1005 ERR("GetRenderTargetData unexpectedly failed.");
1006 renderTargetData->Release();
daniel@transgaming.com3cef5392012-10-31 19:52:15 +00001007 renderTarget->Release();
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +00001008 return error(GL_OUT_OF_MEMORY);
1009 }
1010
1011 RECT sourceRect = {x, y, x + width, y + height};
1012 RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
1013
1014 D3DLOCKED_RECT sourceLock = {0};
1015 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
1016
1017 if (FAILED(result))
1018 {
1019 ERR("Failed to lock the source surface (rectangle might be invalid).");
1020 renderTargetData->Release();
daniel@transgaming.com3cef5392012-10-31 19:52:15 +00001021 renderTarget->Release();
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +00001022 return error(GL_OUT_OF_MEMORY);
1023 }
1024
1025 D3DLOCKED_RECT destLock = {0};
1026 result = lock(&destLock, &destRect);
1027
1028 if (FAILED(result))
1029 {
1030 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1031 renderTargetData->UnlockRect();
1032 renderTargetData->Release();
daniel@transgaming.com3cef5392012-10-31 19:52:15 +00001033 renderTarget->Release();
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +00001034 return error(GL_OUT_OF_MEMORY);
1035 }
1036
1037 if (destLock.pBits && sourceLock.pBits)
1038 {
1039 unsigned char *source = (unsigned char*)sourceLock.pBits;
1040 unsigned char *dest = (unsigned char*)destLock.pBits;
1041
1042 switch (description.Format)
1043 {
1044 case D3DFMT_X8R8G8B8:
1045 case D3DFMT_A8R8G8B8:
1046 switch(getD3DFormat())
1047 {
1048 case D3DFMT_X8R8G8B8:
1049 case D3DFMT_A8R8G8B8:
1050 for(int y = 0; y < height; y++)
1051 {
1052 memcpy(dest, source, 4 * width);
1053
1054 source += sourceLock.Pitch;
1055 dest += destLock.Pitch;
1056 }
1057 break;
1058 case D3DFMT_L8:
1059 for(int y = 0; y < height; y++)
1060 {
1061 for(int x = 0; x < width; x++)
1062 {
1063 dest[x] = source[x * 4 + 2];
1064 }
1065
1066 source += sourceLock.Pitch;
1067 dest += destLock.Pitch;
1068 }
1069 break;
1070 case D3DFMT_A8L8:
1071 for(int y = 0; y < height; y++)
1072 {
1073 for(int x = 0; x < width; x++)
1074 {
1075 dest[x * 2 + 0] = source[x * 4 + 2];
1076 dest[x * 2 + 1] = source[x * 4 + 3];
1077 }
1078
1079 source += sourceLock.Pitch;
1080 dest += destLock.Pitch;
1081 }
1082 break;
1083 default:
1084 UNREACHABLE();
1085 }
1086 break;
1087 case D3DFMT_R5G6B5:
1088 switch(getD3DFormat())
1089 {
1090 case D3DFMT_X8R8G8B8:
1091 for(int y = 0; y < height; y++)
1092 {
1093 for(int x = 0; x < width; x++)
1094 {
1095 unsigned short rgb = ((unsigned short*)source)[x];
1096 unsigned char red = (rgb & 0xF800) >> 8;
1097 unsigned char green = (rgb & 0x07E0) >> 3;
1098 unsigned char blue = (rgb & 0x001F) << 3;
1099 dest[x + 0] = blue | (blue >> 5);
1100 dest[x + 1] = green | (green >> 6);
1101 dest[x + 2] = red | (red >> 5);
1102 dest[x + 3] = 0xFF;
1103 }
1104
1105 source += sourceLock.Pitch;
1106 dest += destLock.Pitch;
1107 }
1108 break;
1109 case D3DFMT_L8:
1110 for(int y = 0; y < height; y++)
1111 {
1112 for(int x = 0; x < width; x++)
1113 {
1114 unsigned char red = source[x * 2 + 1] & 0xF8;
1115 dest[x] = red | (red >> 5);
1116 }
1117
1118 source += sourceLock.Pitch;
1119 dest += destLock.Pitch;
1120 }
1121 break;
1122 default:
1123 UNREACHABLE();
1124 }
1125 break;
1126 case D3DFMT_A1R5G5B5:
1127 switch(getD3DFormat())
1128 {
1129 case D3DFMT_X8R8G8B8:
1130 for(int y = 0; y < height; y++)
1131 {
1132 for(int x = 0; x < width; x++)
1133 {
1134 unsigned short argb = ((unsigned short*)source)[x];
1135 unsigned char red = (argb & 0x7C00) >> 7;
1136 unsigned char green = (argb & 0x03E0) >> 2;
1137 unsigned char blue = (argb & 0x001F) << 3;
1138 dest[x + 0] = blue | (blue >> 5);
1139 dest[x + 1] = green | (green >> 5);
1140 dest[x + 2] = red | (red >> 5);
1141 dest[x + 3] = 0xFF;
1142 }
1143
1144 source += sourceLock.Pitch;
1145 dest += destLock.Pitch;
1146 }
1147 break;
1148 case D3DFMT_A8R8G8B8:
1149 for(int y = 0; y < height; y++)
1150 {
1151 for(int x = 0; x < width; x++)
1152 {
1153 unsigned short argb = ((unsigned short*)source)[x];
1154 unsigned char red = (argb & 0x7C00) >> 7;
1155 unsigned char green = (argb & 0x03E0) >> 2;
1156 unsigned char blue = (argb & 0x001F) << 3;
1157 unsigned char alpha = (signed short)argb >> 15;
1158 dest[x + 0] = blue | (blue >> 5);
1159 dest[x + 1] = green | (green >> 5);
1160 dest[x + 2] = red | (red >> 5);
1161 dest[x + 3] = alpha;
1162 }
1163
1164 source += sourceLock.Pitch;
1165 dest += destLock.Pitch;
1166 }
1167 break;
1168 case D3DFMT_L8:
1169 for(int y = 0; y < height; y++)
1170 {
1171 for(int x = 0; x < width; x++)
1172 {
1173 unsigned char red = source[x * 2 + 1] & 0x7C;
1174 dest[x] = (red << 1) | (red >> 4);
1175 }
1176
1177 source += sourceLock.Pitch;
1178 dest += destLock.Pitch;
1179 }
1180 break;
1181 case D3DFMT_A8L8:
1182 for(int y = 0; y < height; y++)
1183 {
1184 for(int x = 0; x < width; x++)
1185 {
1186 unsigned char red = source[x * 2 + 1] & 0x7C;
1187 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1188 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1189 }
1190
1191 source += sourceLock.Pitch;
1192 dest += destLock.Pitch;
1193 }
1194 break;
1195 default:
1196 UNREACHABLE();
1197 }
1198 break;
1199 default:
1200 UNREACHABLE();
1201 }
1202 }
1203
1204 unlock();
1205 renderTargetData->UnlockRect();
1206
1207 renderTargetData->Release();
daniel@transgaming.com3cef5392012-10-31 19:52:15 +00001208 renderTarget->Release();
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +00001209
1210 mDirty = true;
1211}
1212
1213}