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 ®ion)
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