blob: 51593b3fea33286c90660154e370cf3f35a31cbf [file] [log] [blame]
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001//
2// Copyright 2014 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// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
8
Geoff Lang0b7eef72014-06-12 14:10:47 -04009#include "libGLESv2/renderer/d3d/TextureD3D.h"
10#include "libGLESv2/renderer/d3d/TextureStorage.h"
11#include "libGLESv2/renderer/d3d/ImageD3D.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070012#include "libGLESv2/Buffer.h"
13#include "libGLESv2/Framebuffer.h"
Brandon Jonescef06ff2014-08-05 13:27:48 -070014#include "libGLESv2/Texture.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070015#include "libGLESv2/main.h"
16#include "libGLESv2/formatutils.h"
17#include "libGLESv2/renderer/BufferImpl.h"
18#include "libGLESv2/renderer/RenderTarget.h"
19#include "libGLESv2/renderer/Renderer.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020
21#include "libEGL/Surface.h"
22
23#include "common/mathutil.h"
24#include "common/utilities.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070025
26namespace rx
27{
28
Jamie Madillc751d1e2014-10-21 17:46:29 -040029namespace
30{
31
32gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const void *pixels, const uint8_t **pointerOut)
33{
34 if (unpack.pixelBuffer.id() != 0)
35 {
36 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
37 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
38 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
39
40 // TODO: this is the only place outside of renderer that asks for a buffers raw data.
41 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
42 const uint8_t *bufferData = NULL;
43 gl::Error error = pixelBuffer->getImplementation()->getData(&bufferData);
44 if (error.isError())
45 {
46 return error;
47 }
48
49 *pointerOut = bufferData + offset;
50 }
51 else
52 {
53 *pointerOut = static_cast<const uint8_t *>(pixels);
54 }
55
56 return gl::Error(GL_NO_ERROR);
57}
58
Brandon Jonesf47bebc2014-07-09 14:28:42 -070059bool IsRenderTargetUsage(GLenum usage)
60{
61 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
62}
63
Jamie Madillc751d1e2014-10-21 17:46:29 -040064}
65
Brandon Jones78b1acd2014-07-15 15:33:07 -070066TextureD3D::TextureD3D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070067 : mRenderer(renderer),
68 mUsage(GL_NONE),
69 mDirtyImages(true),
Jamie Madill98553e32014-09-30 16:33:50 -040070 mImmutable(false),
71 mTexStorage(NULL)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070072{
73}
74
75TextureD3D::~TextureD3D()
76{
77}
78
Brandon Jones6053a522014-07-25 16:22:09 -070079TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
80{
81 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
82 return static_cast<TextureD3D*>(texture);
83}
84
Jamie Madill2f06dbf2014-09-18 15:08:50 -040085TextureStorage *TextureD3D::getNativeTexture()
Brandon Jones6053a522014-07-25 16:22:09 -070086{
87 // ensure the underlying texture is created
88 initializeStorage(false);
89
Jamie Madill98553e32014-09-30 16:33:50 -040090 if (mTexStorage)
Brandon Jones6053a522014-07-25 16:22:09 -070091 {
92 updateStorage();
93 }
94
Jamie Madill98553e32014-09-30 16:33:50 -040095 return mTexStorage;
Brandon Jones6053a522014-07-25 16:22:09 -070096}
97
Brandon Jonesf47bebc2014-07-09 14:28:42 -070098GLint TextureD3D::getBaseLevelWidth() const
99{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700100 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700101 return (baseImage ? baseImage->getWidth() : 0);
102}
103
104GLint TextureD3D::getBaseLevelHeight() const
105{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700106 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700107 return (baseImage ? baseImage->getHeight() : 0);
108}
109
110GLint TextureD3D::getBaseLevelDepth() const
111{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700112 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700113 return (baseImage ? baseImage->getDepth() : 0);
114}
115
116// Note: "base level image" is loosely defined to be any image from the base level,
117// where in the base of 2D array textures and cube maps there are several. Don't use
118// the base level image for anything except querying texture format and size.
119GLenum TextureD3D::getBaseLevelInternalFormat() const
120{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700121 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700122 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
123}
124
Jamie Madillec6de4e2014-10-20 10:59:56 -0400125bool TextureD3D::shouldUseSetData(const Image *image) const
126{
127 if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload)
128 {
129 return false;
130 }
131
132 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
133
134 // We can only handle full updates for depth-stencil textures, so to avoid complications
135 // disable them entirely.
136 if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0)
137 {
138 return false;
139 }
140
141 // TODO(jmadill): Handle compressed internal formats
142 return (mTexStorage && !internalFormat.compressed);
143}
144
Jamie Madillba6bc952014-10-06 10:56:22 -0400145gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700146{
Jamie Madillba6bc952014-10-06 10:56:22 -0400147 Image *image = getImage(index);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400148 ASSERT(image);
Jamie Madillba6bc952014-10-06 10:56:22 -0400149
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700150 // No-op
151 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
152 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400153 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700154 }
155
156 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
157 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
Jamie Madill9aca0592014-10-06 16:26:59 -0400158 const uint8_t *pixelData = NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -0400159 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
160 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700161 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400162 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700163 }
164
165 if (pixelData != NULL)
166 {
Jamie Madill9aca0592014-10-06 16:26:59 -0400167 gl::Error error(GL_NO_ERROR);
168
Jamie Madillec6de4e2014-10-20 10:59:56 -0400169 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400170 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400171 error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400172 }
173 else
174 {
175 error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
176 }
177
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400178 if (error.isError())
179 {
180 return error;
181 }
182
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700183 mDirtyImages = true;
184 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400185
186 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700187}
188
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400189gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
190 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700191{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700192 // CPU readback & copy where direct GPU copy is not supported
Jamie Madillc751d1e2014-10-21 17:46:29 -0400193 const uint8_t *pixelData = NULL;
194 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
195 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700196 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400197 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700198 }
199
200 if (pixelData != NULL)
201 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400202 Image *image = getImage(index);
203 ASSERT(image);
204
Jamie Madill9aca0592014-10-06 16:26:59 -0400205 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400206 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400207 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400208 return mTexStorage->setData(index, image, &region, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400209 }
210
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400211 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
212 type, pixelData);
213 if (error.isError())
214 {
215 return error;
216 }
217
Jamie Madille6b6da02014-10-02 11:03:14 -0400218 error = commitRegion(index, region);
219 if (error.isError())
220 {
221 return error;
222 }
223
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700224 mDirtyImages = true;
225 }
226
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400227 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700228}
229
Jamie Madillc751d1e2014-10-21 17:46:29 -0400230gl::Error TextureD3D::setCompressedImage(const gl::PixelUnpackState &unpack, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700231{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400232 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
233 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
234 const uint8_t *pixelData = NULL;
235 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
236 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700237 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400238 return error;
239 }
240
241 if (pixelData != NULL)
242 {
243 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400244 if (error.isError())
245 {
246 return error;
247 }
248
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700249 mDirtyImages = true;
250 }
Geoff Langb5348332014-09-02 13:16:34 -0400251
252 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700253}
254
Geoff Langb5348332014-09-02 13:16:34 -0400255gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400256 GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700257{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400258 const uint8_t *pixelData = NULL;
259 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
260 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700261 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400262 return error;
263 }
264
265 if (pixelData != NULL)
266 {
267 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400268 if (error.isError())
269 {
270 return error;
271 }
272
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700273 mDirtyImages = true;
274 }
275
Geoff Langb5348332014-09-02 13:16:34 -0400276 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700277}
278
279bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
280{
281 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
282}
283
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400284gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
285 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700286{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400287 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700288 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
289 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400290 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700291 }
292
293 // In order to perform the fast copy through the shader, we must have the right format, and be able
294 // to create a render target.
295 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
296
Jacek Cabana5521de2014-10-01 17:23:46 +0200297 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700298
Geoff Langae5122c2014-08-27 14:08:43 -0400299 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
300 if (error.isError())
301 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400302 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400303 }
304
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400305 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700306}
307
308GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
309{
310 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
311 {
312 // Maximum number of levels
313 return gl::log2(std::max(std::max(width, height), depth)) + 1;
314 }
315 else
316 {
317 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
318 return 1;
319 }
320}
321
322int TextureD3D::mipLevels() const
323{
324 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
325}
326
Jamie Madill98553e32014-09-30 16:33:50 -0400327TextureStorage *TextureD3D::getStorage()
328{
Jamie Madilldd3bf522014-10-20 17:04:35 -0400329 ASSERT(mTexStorage);
Jamie Madill98553e32014-09-30 16:33:50 -0400330 return mTexStorage;
331}
332
Jamie Madill3269bcb2014-09-30 16:33:52 -0400333Image *TextureD3D::getBaseLevelImage() const
334{
335 return getImage(getImageIndex(0, 0));
336}
337
Jamie Madill4aa79e12014-09-29 10:46:14 -0400338void TextureD3D::generateMipmaps()
339{
Jamie Madill9aca0592014-10-06 16:26:59 -0400340 GLint mipCount = mipLevels();
341
342 if (mipCount == 1)
343 {
344 return; // no-op
345 }
346
347 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400348 initMipmapsImages();
349
350 // We know that all layers have the same dimension, for the texture to be complete
351 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400352
Jamie Madill9aca0592014-10-06 16:26:59 -0400353 // When making mipmaps with the setData workaround enabled, the texture storage has
354 // the image data already. For non-render-target storage, we have to pull it out into
355 // an image layer.
356 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
357 {
358 if (!mTexStorage->isRenderTarget())
359 {
360 // Copy from the storage mip 0 to Image mip 0
361 for (GLint layer = 0; layer < layerCount; ++layer)
362 {
363 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400364
Jamie Madill9aca0592014-10-06 16:26:59 -0400365 Image *image = getImage(srcIndex);
366 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
367 image->copy(0, 0, 0, area, srcIndex, mTexStorage);
368 }
369 }
370 else
371 {
372 updateStorage();
373 }
374 }
375
376 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400377
378 for (GLint layer = 0; layer < layerCount; ++layer)
379 {
380 for (GLint mip = 1; mip < mipCount; ++mip)
381 {
382 ASSERT(getLayerCount(mip) == layerCount);
383
384 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
385 gl::ImageIndex destIndex = getImageIndex(mip, layer);
386
387 if (renderableStorage)
388 {
389 // GPU-side mipmapping
Jamie Madill9aca0592014-10-06 16:26:59 -0400390 mTexStorage->generateMipmap(sourceIndex, destIndex);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400391 }
392 else
393 {
394 // CPU-side mipmapping
395 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
396 }
397 }
398 }
399}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700400
Jamie Madill135570a2014-09-30 16:33:51 -0400401bool TextureD3D::isBaseImageZeroSize() const
402{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400403 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400404
405 if (!baseImage || baseImage->getWidth() <= 0)
406 {
407 return true;
408 }
409
410 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
411 {
412 return true;
413 }
414
415 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
416 {
417 return true;
418 }
419
420 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
421 {
422 return true;
423 }
424
425 return false;
426}
427
Geoff Langef7b0162014-09-04 13:29:23 -0400428gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400429{
Geoff Langef7b0162014-09-04 13:29:23 -0400430 gl::Error error = initializeStorage(true);
431 if (error.isError())
432 {
433 return error;
434 }
Jamie Madill135570a2014-09-30 16:33:51 -0400435
436 if (!isBaseImageZeroSize())
437 {
438 ASSERT(mTexStorage);
439 if (!mTexStorage->isRenderTarget())
440 {
Geoff Langef7b0162014-09-04 13:29:23 -0400441 TextureStorage *newRenderTargetStorage = NULL;
442 error = createCompleteStorage(true, &newRenderTargetStorage);
443 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400444 {
Geoff Langef7b0162014-09-04 13:29:23 -0400445 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400446 }
447
Geoff Langef7b0162014-09-04 13:29:23 -0400448 error = mTexStorage->copyToStorage(newRenderTargetStorage);
449 if (error.isError())
450 {
451 SafeDelete(newRenderTargetStorage);
452 return error;
453 }
454
455 error = setCompleteTexStorage(newRenderTargetStorage);
456 if (error.isError())
457 {
458 SafeDelete(newRenderTargetStorage);
459 return error;
460 }
Jamie Madill135570a2014-09-30 16:33:51 -0400461 }
462 }
463
Geoff Langef7b0162014-09-04 13:29:23 -0400464 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400465}
466
Jamie Madille76bdda2014-10-20 17:13:52 -0400467bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
468{
469 rx::Image *image = getImage(index);
470 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
471 return (image->isRenderableFormat() && levelsComplete);
472}
473
Jamie Madill710e5772014-10-20 17:13:53 -0400474gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
475{
476 if (mTexStorage)
477 {
478 ASSERT(isValidIndex(index));
479 Image *image = getImage(index);
480 ImageD3D *imageD3D = ImageD3D::makeImageD3D(image);
481 gl::Error error = imageD3D->copyToStorage(mTexStorage, index, region);
482 if (error.isError())
483 {
484 return error;
485 }
486
487 image->markClean();
488 }
489
490 return gl::Error(GL_NO_ERROR);
491}
492
Brandon Jones78b1acd2014-07-15 15:33:07 -0700493TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400494 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700495{
496 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
497 {
498 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
499 }
500}
501
502TextureD3D_2D::~TextureD3D_2D()
503{
Austin Kinross69822602014-08-12 15:51:37 -0700504 // Delete the Images before the TextureStorage.
505 // Images might be relying on the TextureStorage for some of their data.
506 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700507 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
508 {
509 delete mImageArray[i];
510 }
Austin Kinross69822602014-08-12 15:51:37 -0700511
512 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700513}
514
Brandon Jonescef06ff2014-08-05 13:27:48 -0700515Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700516{
517 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700518 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700519 return mImageArray[level];
520}
521
Jamie Madillfeda4d22014-09-17 13:03:29 -0400522Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
523{
524 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400525 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400526 ASSERT(index.type == GL_TEXTURE_2D);
527 return mImageArray[index.mipIndex];
528}
529
Brandon Jonescef06ff2014-08-05 13:27:48 -0700530GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700531{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700532 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
533 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700534}
535
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700536GLsizei TextureD3D_2D::getWidth(GLint level) const
537{
538 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
539 return mImageArray[level]->getWidth();
540 else
541 return 0;
542}
543
544GLsizei TextureD3D_2D::getHeight(GLint level) const
545{
546 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
547 return mImageArray[level]->getHeight();
548 else
549 return 0;
550}
551
552GLenum TextureD3D_2D::getInternalFormat(GLint level) const
553{
554 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
555 return mImageArray[level]->getInternalFormat();
556 else
557 return GL_NONE;
558}
559
560GLenum TextureD3D_2D::getActualFormat(GLint level) const
561{
562 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
563 return mImageArray[level]->getActualFormat();
564 else
565 return GL_NONE;
566}
567
568bool TextureD3D_2D::isDepth(GLint level) const
569{
Geoff Lang5d601382014-07-22 15:14:06 -0400570 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700571}
572
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400573gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
574 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
575 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700576{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700577 ASSERT(target == GL_TEXTURE_2D && depth == 1);
578
Geoff Lang5d601382014-07-22 15:14:06 -0400579 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
580
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700581 bool fastUnpacked = false;
582
Brandon Jonescef06ff2014-08-05 13:27:48 -0700583 redefineImage(level, sizedInternalFormat, width, height);
584
Jamie Madillba6bc952014-10-06 10:56:22 -0400585 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
586
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700587 // Attempt a fast gpu copy of the pixel data to the surface
588 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
589 {
590 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400591 RenderTarget *destRenderTarget = NULL;
592 gl::Error error = getRenderTarget(index, &destRenderTarget);
593 if (error.isError())
594 {
595 return error;
596 }
597
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700598 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
599
Geoff Lang64f23f62014-09-10 14:40:12 -0400600 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
601 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700602 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400603 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700604 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400605
606 // Ensure we don't overwrite our newly initialized data
607 mImageArray[level]->markClean();
608
609 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700610 }
611
612 if (!fastUnpacked)
613 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400614 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400615 if (error.isError())
616 {
617 return error;
618 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700619 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400620
621 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700622}
623
Geoff Langb5348332014-09-02 13:16:34 -0400624gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
625 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400626 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700627{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700628 ASSERT(target == GL_TEXTURE_2D && depth == 1);
629
630 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
631 redefineImage(level, format, width, height);
632
Jamie Madillc751d1e2014-10-21 17:46:29 -0400633 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700634}
635
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400636gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
637 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
638 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700639{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700640 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
641
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700642 bool fastUnpacked = false;
643
Jamie Madillac7579c2014-09-17 16:59:33 -0400644 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400645 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700646 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
647 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400648 RenderTarget *renderTarget = NULL;
649 gl::Error error = getRenderTarget(index, &renderTarget);
650 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700651 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400652 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700653 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400654
655 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
656 if (error.isError())
657 {
658 return error;
659 }
660
661 // Ensure we don't overwrite our newly initialized data
662 mImageArray[level]->markClean();
663
664 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700665 }
666
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400667 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700668 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400669 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
670 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700671 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400672
673 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700674}
675
Geoff Langb5348332014-09-02 13:16:34 -0400676gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
677 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400678 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700679{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700680 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
681
Jamie Madillc751d1e2014-10-21 17:46:29 -0400682 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[level]);
Geoff Langb5348332014-09-02 13:16:34 -0400683 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700684 {
Geoff Langb5348332014-09-02 13:16:34 -0400685 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700686 }
Geoff Langb5348332014-09-02 13:16:34 -0400687
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400688 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
689 gl::Box region(xoffset, yoffset, 0, width, height, 1);
690 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700691}
692
Geoff Langef7b0162014-09-04 13:29:23 -0400693gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
694 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700695{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700696 ASSERT(target == GL_TEXTURE_2D);
697
698 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
699 redefineImage(level, sizedInternalFormat, width, height);
700
Jamie Madill82bf0c52014-10-03 11:50:53 -0400701 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400702 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400703
Jamie Madille76bdda2014-10-20 17:13:52 -0400704 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700705 {
Geoff Langef7b0162014-09-04 13:29:23 -0400706 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
707 if (error.isError())
708 {
709 return error;
710 }
711
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700712 mDirtyImages = true;
713 }
714 else
715 {
Geoff Langef7b0162014-09-04 13:29:23 -0400716 gl::Error error = ensureRenderTarget();
717 if (error.isError())
718 {
719 return error;
720 }
721
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700722 mImageArray[level]->markClean();
723
724 if (width != 0 && height != 0 && isValidLevel(level))
725 {
Geoff Langef7b0162014-09-04 13:29:23 -0400726 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
727 if (error.isError())
728 {
729 return error;
730 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700731 }
732 }
Geoff Langef7b0162014-09-04 13:29:23 -0400733
734 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700735}
736
Geoff Langef7b0162014-09-04 13:29:23 -0400737gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
738 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700739{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700740 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
741
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700742 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
743 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700744
Jamie Madill82bf0c52014-10-03 11:50:53 -0400745 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400746 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400747
Jamie Madille76bdda2014-10-20 17:13:52 -0400748 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700749 {
Geoff Langef7b0162014-09-04 13:29:23 -0400750 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
751 if (error.isError())
752 {
753 return error;
754 }
755
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700756 mDirtyImages = true;
757 }
758 else
759 {
Geoff Langef7b0162014-09-04 13:29:23 -0400760 gl::Error error = ensureRenderTarget();
761 if (error.isError())
762 {
763 return error;
764 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700765
766 if (isValidLevel(level))
767 {
Geoff Langef7b0162014-09-04 13:29:23 -0400768 error = updateStorageLevel(level);
769 if (error.isError())
770 {
771 return error;
772 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700773
Geoff Langef7b0162014-09-04 13:29:23 -0400774 error = mRenderer->copyImage2D(source, sourceRect,
775 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
776 xoffset, yoffset, mTexStorage, level);
777 if (error.isError())
778 {
779 return error;
780 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700781 }
782 }
Geoff Langef7b0162014-09-04 13:29:23 -0400783
784 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700785}
786
Geoff Lang1f8532b2014-09-05 09:46:13 -0400787gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700788{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700789 ASSERT(target == GL_TEXTURE_2D && depth == 1);
790
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700791 for (int level = 0; level < levels; level++)
792 {
793 GLsizei levelWidth = std::max(1, width >> level);
794 GLsizei levelHeight = std::max(1, height >> level);
795 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
796 }
797
798 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
799 {
800 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
801 }
802
Geoff Lang1f8532b2014-09-05 09:46:13 -0400803 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400804 bool renderTarget = IsRenderTargetUsage(mUsage);
805 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400806
807 gl::Error error = setCompleteTexStorage(storage);
808 if (error.isError())
809 {
810 SafeDelete(storage);
811 return error;
812 }
813
814 mImmutable = true;
815
816 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700817}
818
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700819void TextureD3D_2D::bindTexImage(egl::Surface *surface)
820{
821 GLenum internalformat = surface->getFormat();
822
823 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
824
825 if (mTexStorage)
826 {
827 SafeDelete(mTexStorage);
828 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400829
830 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700831
832 mDirtyImages = true;
833}
834
835void TextureD3D_2D::releaseTexImage()
836{
837 if (mTexStorage)
838 {
839 SafeDelete(mTexStorage);
840 }
841
842 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
843 {
844 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
845 }
846}
847
Jamie Madill4aa79e12014-09-29 10:46:14 -0400848void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700849{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700850 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700851 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700852 for (int level = 1; level < levelCount; level++)
853 {
854 redefineImage(level, getBaseLevelInternalFormat(),
855 std::max(getBaseLevelWidth() >> level, 1),
856 std::max(getBaseLevelHeight() >> level, 1));
857 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700858}
859
Jamie Madillac7579c2014-09-17 16:59:33 -0400860unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700861{
Jamie Madillac7579c2014-09-17 16:59:33 -0400862 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400863 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700864}
865
Geoff Lang64f23f62014-09-10 14:40:12 -0400866gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700867{
Jamie Madillac7579c2014-09-17 16:59:33 -0400868 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700869
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700870 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400871 gl::Error error = ensureRenderTarget();
872 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700873 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400874 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700875 }
876
Geoff Langef7b0162014-09-04 13:29:23 -0400877 error = updateStorageLevel(index.mipIndex);
878 if (error.isError())
879 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400880 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400881 }
882
Geoff Lang64f23f62014-09-10 14:40:12 -0400883 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700884}
885
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700886bool TextureD3D_2D::isValidLevel(int level) const
887{
888 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
889}
890
891bool TextureD3D_2D::isLevelComplete(int level) const
892{
893 if (isImmutable())
894 {
895 return true;
896 }
897
Brandon Jones78b1acd2014-07-15 15:33:07 -0700898 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700899
900 GLsizei width = baseImage->getWidth();
901 GLsizei height = baseImage->getHeight();
902
903 if (width <= 0 || height <= 0)
904 {
905 return false;
906 }
907
908 // The base image level is complete if the width and height are positive
909 if (level == 0)
910 {
911 return true;
912 }
913
914 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700915 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700916
917 if (image->getInternalFormat() != baseImage->getInternalFormat())
918 {
919 return false;
920 }
921
922 if (image->getWidth() != std::max(1, width >> level))
923 {
924 return false;
925 }
926
927 if (image->getHeight() != std::max(1, height >> level))
928 {
929 return false;
930 }
931
932 return true;
933}
934
Jamie Madille76bdda2014-10-20 17:13:52 -0400935bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
936{
937 return isLevelComplete(index.mipIndex);
938}
939
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700940// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400941gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700942{
943 // Only initialize the first time this texture is used as a render target or shader resource
944 if (mTexStorage)
945 {
Geoff Langef7b0162014-09-04 13:29:23 -0400946 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700947 }
948
949 // do not attempt to create storage for nonexistant data
950 if (!isLevelComplete(0))
951 {
Geoff Langef7b0162014-09-04 13:29:23 -0400952 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700953 }
954
955 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
956
Geoff Langef7b0162014-09-04 13:29:23 -0400957 TextureStorage *storage = NULL;
958 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
959 if (error.isError())
960 {
961 return error;
962 }
963
964 error = setCompleteTexStorage(storage);
965 if (error.isError())
966 {
967 SafeDelete(storage);
968 return error;
969 }
970
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700971 ASSERT(mTexStorage);
972
973 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400974 error = updateStorage();
975 if (error.isError())
976 {
977 return error;
978 }
979
980 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700981}
982
Geoff Langef7b0162014-09-04 13:29:23 -0400983gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700984{
985 GLsizei width = getBaseLevelWidth();
986 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400987 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700988
989 ASSERT(width > 0 && height > 0);
990
991 // use existing storage level count, when previously specified by TexStorage*D
992 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
993
Geoff Langef7b0162014-09-04 13:29:23 -0400994 // TODO(geofflang): Determine if the texture creation succeeded
995 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
996
997 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700998}
999
Geoff Langef7b0162014-09-04 13:29:23 -04001000gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001001{
Geoff Langef7b0162014-09-04 13:29:23 -04001002 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001003 {
Geoff Langef7b0162014-09-04 13:29:23 -04001004 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001005 {
Geoff Langef7b0162014-09-04 13:29:23 -04001006 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
1007 if (error.isError())
1008 {
1009 return error;
1010 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001011 }
1012 }
1013
Geoff Langef7b0162014-09-04 13:29:23 -04001014 SafeDelete(mTexStorage);
1015 mTexStorage = newCompleteTexStorage;
1016
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001017 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001018
1019 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001020}
1021
Geoff Langef7b0162014-09-04 13:29:23 -04001022gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001023{
1024 ASSERT(mTexStorage != NULL);
1025 GLint storageLevels = mTexStorage->getLevelCount();
1026 for (int level = 0; level < storageLevels; level++)
1027 {
1028 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1029 {
Geoff Langef7b0162014-09-04 13:29:23 -04001030 gl::Error error = updateStorageLevel(level);
1031 if (error.isError())
1032 {
1033 return error;
1034 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001035 }
1036 }
Geoff Langef7b0162014-09-04 13:29:23 -04001037
1038 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001039}
1040
Geoff Langef7b0162014-09-04 13:29:23 -04001041gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001042{
1043 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1044 ASSERT(isLevelComplete(level));
1045
1046 if (mImageArray[level]->isDirty())
1047 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001048 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1049 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001050 gl::Error error = commitRegion(index, region);
1051 if (error.isError())
1052 {
1053 return error;
1054 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001055 }
Geoff Langef7b0162014-09-04 13:29:23 -04001056
1057 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001058}
1059
1060void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1061{
1062 // If there currently is a corresponding storage texture image, it has these parameters
1063 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1064 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1065 const GLenum storageFormat = getBaseLevelInternalFormat();
1066
1067 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
1068
1069 if (mTexStorage)
1070 {
1071 const int storageLevels = mTexStorage->getLevelCount();
1072
1073 if ((level >= storageLevels && storageLevels != 0) ||
1074 width != storageWidth ||
1075 height != storageHeight ||
1076 internalformat != storageFormat) // Discard mismatched storage
1077 {
1078 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1079 {
1080 mImageArray[i]->markDirty();
1081 }
1082
1083 SafeDelete(mTexStorage);
1084 mDirtyImages = true;
1085 }
1086 }
1087}
1088
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001089gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1090{
1091 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1092}
Brandon Jones0511e802014-07-14 16:27:26 -07001093
Jamie Madillcb83dc12014-09-29 10:46:12 -04001094gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1095{
1096 // "layer" does not apply to 2D Textures.
1097 return gl::ImageIndex::Make2D(mip);
1098}
1099
Jamie Madill710e5772014-10-20 17:13:53 -04001100bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1101{
1102 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1103 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1104}
1105
Brandon Jones78b1acd2014-07-15 15:33:07 -07001106TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001107 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001108{
1109 for (int i = 0; i < 6; i++)
1110 {
1111 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1112 {
1113 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1114 }
1115 }
1116}
1117
1118TextureD3D_Cube::~TextureD3D_Cube()
1119{
Austin Kinross69822602014-08-12 15:51:37 -07001120 // Delete the Images before the TextureStorage.
1121 // Images might be relying on the TextureStorage for some of their data.
1122 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones0511e802014-07-14 16:27:26 -07001123 for (int i = 0; i < 6; i++)
1124 {
1125 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1126 {
1127 SafeDelete(mImageArray[i][j]);
1128 }
1129 }
Austin Kinross69822602014-08-12 15:51:37 -07001130
1131 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001132}
1133
Brandon Jonescef06ff2014-08-05 13:27:48 -07001134Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001135{
1136 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001137 ASSERT(layer < 6);
1138 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001139}
1140
Jamie Madillfeda4d22014-09-17 13:03:29 -04001141Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1142{
1143 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1144 ASSERT(index.layerIndex < 6);
1145 return mImageArray[index.layerIndex][index.mipIndex];
1146}
1147
Brandon Jonescef06ff2014-08-05 13:27:48 -07001148GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001149{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001150 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1151 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001152}
1153
Brandon Jonescef06ff2014-08-05 13:27:48 -07001154GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001155{
1156 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001157 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001158 else
1159 return GL_NONE;
1160}
1161
Brandon Jonescef06ff2014-08-05 13:27:48 -07001162bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001163{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001164 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001165}
1166
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001167gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1168 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1169 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001170{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001171 ASSERT(depth == 1);
1172
Geoff Lang5d601382014-07-22 15:14:06 -04001173 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001174 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001175
Jamie Madillba6bc952014-10-06 10:56:22 -04001176 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001177
Jamie Madillba6bc952014-10-06 10:56:22 -04001178 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001179}
1180
Geoff Langb5348332014-09-02 13:16:34 -04001181gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1182 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001183 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001184{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001185 ASSERT(depth == 1);
1186
Brandon Jones0511e802014-07-14 16:27:26 -07001187 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001188 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1189
Brandon Jones0511e802014-07-14 16:27:26 -07001190 redefineImage(faceIndex, level, format, width, height);
1191
Jamie Madillc751d1e2014-10-21 17:46:29 -04001192 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001193}
1194
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001195gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1196 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1197 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001198{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001199 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001200 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001201 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001202}
1203
Geoff Langb5348332014-09-02 13:16:34 -04001204gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1205 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001206 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001207{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001208 ASSERT(depth == 1 && zoffset == 0);
1209
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001210 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001211
Jamie Madillc751d1e2014-10-21 17:46:29 -04001212 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[index.layerIndex][level]);
Geoff Langb5348332014-09-02 13:16:34 -04001213 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001214 {
Geoff Langb5348332014-09-02 13:16:34 -04001215 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001216 }
Geoff Langb5348332014-09-02 13:16:34 -04001217
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001218 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1219 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001220}
1221
Geoff Langef7b0162014-09-04 13:29:23 -04001222gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1223 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001224{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001225 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001226 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1227
Brandon Jones0511e802014-07-14 16:27:26 -07001228 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1229
Jamie Madill82bf0c52014-10-03 11:50:53 -04001230 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001231 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001232
Jamie Madille76bdda2014-10-20 17:13:52 -04001233 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001234 {
Geoff Langef7b0162014-09-04 13:29:23 -04001235 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1236 if (error.isError())
1237 {
1238 return error;
1239 }
1240
Brandon Jones0511e802014-07-14 16:27:26 -07001241 mDirtyImages = true;
1242 }
1243 else
1244 {
Geoff Langef7b0162014-09-04 13:29:23 -04001245 gl::Error error = ensureRenderTarget();
1246 if (error.isError())
1247 {
1248 return error;
1249 }
1250
Brandon Jones0511e802014-07-14 16:27:26 -07001251 mImageArray[faceIndex][level]->markClean();
1252
1253 ASSERT(width == height);
1254
1255 if (width > 0 && isValidFaceLevel(faceIndex, level))
1256 {
Geoff Langef7b0162014-09-04 13:29:23 -04001257 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1258 if (error.isError())
1259 {
1260 return error;
1261 }
Brandon Jones0511e802014-07-14 16:27:26 -07001262 }
1263 }
Geoff Langef7b0162014-09-04 13:29:23 -04001264
1265 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001266}
1267
Geoff Langef7b0162014-09-04 13:29:23 -04001268gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1269 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001270{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001271 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001272
Jamie Madill82bf0c52014-10-03 11:50:53 -04001273 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001274 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001275
Jamie Madille76bdda2014-10-20 17:13:52 -04001276 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001277 {
Geoff Langef7b0162014-09-04 13:29:23 -04001278 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1279 if (error.isError())
1280 {
1281 return error;
1282 }
1283
Brandon Jones0511e802014-07-14 16:27:26 -07001284 mDirtyImages = true;
1285 }
1286 else
1287 {
Geoff Langef7b0162014-09-04 13:29:23 -04001288 gl::Error error = ensureRenderTarget();
1289 if (error.isError())
1290 {
1291 return error;
1292 }
Brandon Jones0511e802014-07-14 16:27:26 -07001293
1294 if (isValidFaceLevel(faceIndex, level))
1295 {
Geoff Langef7b0162014-09-04 13:29:23 -04001296 error = updateStorageFaceLevel(faceIndex, level);
1297 if (error.isError())
1298 {
1299 return error;
1300 }
Brandon Jones0511e802014-07-14 16:27:26 -07001301
Geoff Langef7b0162014-09-04 13:29:23 -04001302 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1303 xoffset, yoffset, mTexStorage, target, level);
1304 if (error.isError())
1305 {
1306 return error;
1307 }
Brandon Jones0511e802014-07-14 16:27:26 -07001308 }
1309 }
Geoff Langef7b0162014-09-04 13:29:23 -04001310
1311 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001312}
1313
Geoff Lang1f8532b2014-09-05 09:46:13 -04001314gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001315{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001316 ASSERT(width == height);
1317 ASSERT(depth == 1);
1318
Brandon Jones0511e802014-07-14 16:27:26 -07001319 for (int level = 0; level < levels; level++)
1320 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001321 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001322 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1323 {
1324 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1325 }
1326 }
1327
1328 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1329 {
1330 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1331 {
1332 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1333 }
1334 }
1335
Geoff Lang1f8532b2014-09-05 09:46:13 -04001336 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001337 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001338 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001339
1340 gl::Error error = setCompleteTexStorage(storage);
1341 if (error.isError())
1342 {
1343 SafeDelete(storage);
1344 return error;
1345 }
1346
1347 mImmutable = true;
1348
1349 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001350}
1351
Brandon Jones0511e802014-07-14 16:27:26 -07001352// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1353bool TextureD3D_Cube::isCubeComplete() const
1354{
1355 int baseWidth = getBaseLevelWidth();
1356 int baseHeight = getBaseLevelHeight();
1357 GLenum baseFormat = getBaseLevelInternalFormat();
1358
1359 if (baseWidth <= 0 || baseWidth != baseHeight)
1360 {
1361 return false;
1362 }
1363
1364 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1365 {
1366 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1367
1368 if (faceBaseImage.getWidth() != baseWidth ||
1369 faceBaseImage.getHeight() != baseHeight ||
1370 faceBaseImage.getInternalFormat() != baseFormat )
1371 {
1372 return false;
1373 }
1374 }
1375
1376 return true;
1377}
1378
Brandon Jones6053a522014-07-25 16:22:09 -07001379void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1380{
1381 UNREACHABLE();
1382}
1383
1384void TextureD3D_Cube::releaseTexImage()
1385{
1386 UNREACHABLE();
1387}
1388
1389
Jamie Madill4aa79e12014-09-29 10:46:14 -04001390void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001391{
1392 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1393 int levelCount = mipLevels();
1394 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1395 {
1396 for (int level = 1; level < levelCount; level++)
1397 {
1398 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1399 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1400 }
1401 }
Brandon Jones0511e802014-07-14 16:27:26 -07001402}
1403
Jamie Madillac7579c2014-09-17 16:59:33 -04001404unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001405{
Geoff Langef7b0162014-09-04 13:29:23 -04001406 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001407}
1408
Geoff Lang64f23f62014-09-10 14:40:12 -04001409gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001410{
Jamie Madillac7579c2014-09-17 16:59:33 -04001411 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001412
1413 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001414 gl::Error error = ensureRenderTarget();
1415 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001416 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001417 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001418 }
1419
Geoff Langef7b0162014-09-04 13:29:23 -04001420 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1421 if (error.isError())
1422 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001423 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001424 }
1425
Geoff Lang64f23f62014-09-10 14:40:12 -04001426 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001427}
1428
Geoff Langef7b0162014-09-04 13:29:23 -04001429gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001430{
1431 // Only initialize the first time this texture is used as a render target or shader resource
1432 if (mTexStorage)
1433 {
Geoff Langef7b0162014-09-04 13:29:23 -04001434 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001435 }
1436
1437 // do not attempt to create storage for nonexistant data
1438 if (!isFaceLevelComplete(0, 0))
1439 {
Geoff Langef7b0162014-09-04 13:29:23 -04001440 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001441 }
1442
1443 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1444
Geoff Langef7b0162014-09-04 13:29:23 -04001445 TextureStorage *storage = NULL;
1446 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1447 if (error.isError())
1448 {
1449 return error;
1450 }
1451
1452 error = setCompleteTexStorage(storage);
1453 if (error.isError())
1454 {
1455 SafeDelete(storage);
1456 return error;
1457 }
1458
Brandon Jones0511e802014-07-14 16:27:26 -07001459 ASSERT(mTexStorage);
1460
1461 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001462 error = updateStorage();
1463 if (error.isError())
1464 {
1465 return error;
1466 }
1467
1468 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001469}
1470
Geoff Langef7b0162014-09-04 13:29:23 -04001471gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001472{
1473 GLsizei size = getBaseLevelWidth();
1474
1475 ASSERT(size > 0);
1476
1477 // use existing storage level count, when previously specified by TexStorage*D
1478 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1479
Geoff Langef7b0162014-09-04 13:29:23 -04001480 // TODO (geofflang): detect if storage creation succeeded
1481 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1482
1483 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001484}
1485
Geoff Langef7b0162014-09-04 13:29:23 -04001486gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001487{
Geoff Langef7b0162014-09-04 13:29:23 -04001488 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001489 {
1490 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1491 {
Geoff Langef7b0162014-09-04 13:29:23 -04001492 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001493 {
Geoff Langef7b0162014-09-04 13:29:23 -04001494 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1495 if (error.isError())
1496 {
1497 return error;
1498 }
Brandon Jones0511e802014-07-14 16:27:26 -07001499 }
1500 }
1501 }
1502
Geoff Langef7b0162014-09-04 13:29:23 -04001503 SafeDelete(mTexStorage);
1504 mTexStorage = newCompleteTexStorage;
1505
Brandon Jones0511e802014-07-14 16:27:26 -07001506 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001507 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001508}
1509
Geoff Langef7b0162014-09-04 13:29:23 -04001510gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001511{
1512 ASSERT(mTexStorage != NULL);
1513 GLint storageLevels = mTexStorage->getLevelCount();
1514 for (int face = 0; face < 6; face++)
1515 {
1516 for (int level = 0; level < storageLevels; level++)
1517 {
1518 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1519 {
Geoff Langef7b0162014-09-04 13:29:23 -04001520 gl::Error error = updateStorageFaceLevel(face, level);
1521 if (error.isError())
1522 {
1523 return error;
1524 }
Brandon Jones0511e802014-07-14 16:27:26 -07001525 }
1526 }
1527 }
Geoff Langef7b0162014-09-04 13:29:23 -04001528
1529 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001530}
1531
Brandon Jones0511e802014-07-14 16:27:26 -07001532bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1533{
1534 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1535}
1536
Brandon Jones0511e802014-07-14 16:27:26 -07001537bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1538{
1539 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1540
1541 if (isImmutable())
1542 {
1543 return true;
1544 }
1545
1546 int baseSize = getBaseLevelWidth();
1547
1548 if (baseSize <= 0)
1549 {
1550 return false;
1551 }
1552
1553 // "isCubeComplete" checks for base level completeness and we must call that
1554 // to determine if any face at level 0 is complete. We omit that check here
1555 // to avoid re-checking cube-completeness for every face at level 0.
1556 if (level == 0)
1557 {
1558 return true;
1559 }
1560
1561 // Check that non-zero levels are consistent with the base level.
1562 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1563
1564 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1565 {
1566 return false;
1567 }
1568
1569 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1570 {
1571 return false;
1572 }
1573
1574 return true;
1575}
1576
Jamie Madille76bdda2014-10-20 17:13:52 -04001577bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1578{
1579 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1580}
1581
Geoff Langef7b0162014-09-04 13:29:23 -04001582gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001583{
1584 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1585 ImageD3D *image = mImageArray[faceIndex][level];
1586
1587 if (image->isDirty())
1588 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001589 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1590 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1591 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001592 gl::Error error = commitRegion(index, region);
1593 if (error.isError())
1594 {
1595 return error;
1596 }
Brandon Jones0511e802014-07-14 16:27:26 -07001597 }
Geoff Langef7b0162014-09-04 13:29:23 -04001598
1599 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001600}
1601
1602void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1603{
1604 // If there currently is a corresponding storage texture image, it has these parameters
1605 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1606 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1607 const GLenum storageFormat = getBaseLevelInternalFormat();
1608
1609 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1610
1611 if (mTexStorage)
1612 {
1613 const int storageLevels = mTexStorage->getLevelCount();
1614
1615 if ((level >= storageLevels && storageLevels != 0) ||
1616 width != storageWidth ||
1617 height != storageHeight ||
1618 internalformat != storageFormat) // Discard mismatched storage
1619 {
1620 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1621 {
1622 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1623 {
1624 mImageArray[faceIndex][level]->markDirty();
1625 }
1626 }
1627
1628 SafeDelete(mTexStorage);
1629
1630 mDirtyImages = true;
1631 }
1632 }
1633}
1634
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001635gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1636{
1637 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1638}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001639
Jamie Madillcb83dc12014-09-29 10:46:12 -04001640gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1641{
1642 // The "layer" of the image index corresponds to the cube face
1643 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1644}
1645
Jamie Madill710e5772014-10-20 17:13:53 -04001646bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1647{
1648 return (mTexStorage && gl::IsCubemapTextureTarget(index.type) &&
1649 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1650}
1651
Brandon Jones78b1acd2014-07-15 15:33:07 -07001652TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001653 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001654{
1655 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1656 {
1657 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1658 }
1659}
1660
1661TextureD3D_3D::~TextureD3D_3D()
1662{
Austin Kinross69822602014-08-12 15:51:37 -07001663 // Delete the Images before the TextureStorage.
1664 // Images might be relying on the TextureStorage for some of their data.
1665 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones78b1acd2014-07-15 15:33:07 -07001666 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1667 {
1668 delete mImageArray[i];
1669 }
Austin Kinross69822602014-08-12 15:51:37 -07001670
1671 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001672}
1673
Brandon Jonescef06ff2014-08-05 13:27:48 -07001674Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001675{
1676 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001677 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001678 return mImageArray[level];
1679}
1680
Jamie Madillfeda4d22014-09-17 13:03:29 -04001681Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1682{
1683 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001684 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001685 ASSERT(index.type == GL_TEXTURE_3D);
1686 return mImageArray[index.mipIndex];
1687}
1688
Brandon Jonescef06ff2014-08-05 13:27:48 -07001689GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001690{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001691 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1692 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001693}
1694
Brandon Jones78b1acd2014-07-15 15:33:07 -07001695GLsizei TextureD3D_3D::getWidth(GLint level) const
1696{
1697 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1698 return mImageArray[level]->getWidth();
1699 else
1700 return 0;
1701}
1702
1703GLsizei TextureD3D_3D::getHeight(GLint level) const
1704{
1705 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1706 return mImageArray[level]->getHeight();
1707 else
1708 return 0;
1709}
1710
1711GLsizei TextureD3D_3D::getDepth(GLint level) const
1712{
1713 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1714 return mImageArray[level]->getDepth();
1715 else
1716 return 0;
1717}
1718
1719GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1720{
1721 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1722 return mImageArray[level]->getInternalFormat();
1723 else
1724 return GL_NONE;
1725}
1726
1727bool TextureD3D_3D::isDepth(GLint level) const
1728{
Geoff Lang5d601382014-07-22 15:14:06 -04001729 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001730}
1731
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001732gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1733 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1734 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001735{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001736 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001737 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1738
Brandon Jones78b1acd2014-07-15 15:33:07 -07001739 redefineImage(level, sizedInternalFormat, width, height, depth);
1740
1741 bool fastUnpacked = false;
1742
Jamie Madillba6bc952014-10-06 10:56:22 -04001743 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1744
Brandon Jones78b1acd2014-07-15 15:33:07 -07001745 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1746 if (isFastUnpackable(unpack, sizedInternalFormat))
1747 {
1748 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001749 RenderTarget *destRenderTarget = NULL;
1750 gl::Error error = getRenderTarget(index, &destRenderTarget);
1751 if (error.isError())
1752 {
1753 return error;
1754 }
1755
Brandon Jones78b1acd2014-07-15 15:33:07 -07001756 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1757
Geoff Lang64f23f62014-09-10 14:40:12 -04001758 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1759 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001760 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001761 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001762 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001763
1764 // Ensure we don't overwrite our newly initialized data
1765 mImageArray[level]->markClean();
1766
1767 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001768 }
1769
1770 if (!fastUnpacked)
1771 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001772 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001773 if (error.isError())
1774 {
1775 return error;
1776 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001777 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001778
1779 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001780}
1781
Geoff Langb5348332014-09-02 13:16:34 -04001782gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1783 GLsizei width, GLsizei height,GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001784 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001785{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001786 ASSERT(target == GL_TEXTURE_3D);
1787
Brandon Jones78b1acd2014-07-15 15:33:07 -07001788 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1789 redefineImage(level, format, width, height, depth);
1790
Jamie Madillc751d1e2014-10-21 17:46:29 -04001791 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001792}
1793
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001794gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1795 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1796 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001797{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001798 ASSERT(target == GL_TEXTURE_3D);
1799
Brandon Jones78b1acd2014-07-15 15:33:07 -07001800 bool fastUnpacked = false;
1801
Jamie Madillac7579c2014-09-17 16:59:33 -04001802 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1803
Brandon Jones78b1acd2014-07-15 15:33:07 -07001804 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1805 if (isFastUnpackable(unpack, getInternalFormat(level)))
1806 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001807 RenderTarget *destRenderTarget = NULL;
1808 gl::Error error = getRenderTarget(index, &destRenderTarget);
1809 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001810 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001811 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001812 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001813
1814 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1815 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1816 if (error.isError())
1817 {
1818 return error;
1819 }
1820
1821 // Ensure we don't overwrite our newly initialized data
1822 mImageArray[level]->markClean();
1823
1824 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001825 }
1826
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001827 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001828 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001829 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1830 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001831 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001832
1833 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001834}
1835
Geoff Langb5348332014-09-02 13:16:34 -04001836gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1837 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001838 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001839{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001840 ASSERT(target == GL_TEXTURE_3D);
1841
Geoff Langb5348332014-09-02 13:16:34 -04001842 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001843 format, imageSize, unpack, pixels, mImageArray[level]);
Geoff Langb5348332014-09-02 13:16:34 -04001844 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001845 {
Geoff Langb5348332014-09-02 13:16:34 -04001846 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001847 }
Geoff Langb5348332014-09-02 13:16:34 -04001848
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001849 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1850 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1851 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001852}
1853
Geoff Langef7b0162014-09-04 13:29:23 -04001854gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1855 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001856{
1857 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001858 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001859}
1860
Geoff Langef7b0162014-09-04 13:29:23 -04001861gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1862 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001863{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001864 ASSERT(target == GL_TEXTURE_3D);
1865
Jamie Madill82bf0c52014-10-03 11:50:53 -04001866 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001867 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001868
Jamie Madille76bdda2014-10-20 17:13:52 -04001869 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001870 {
Geoff Langef7b0162014-09-04 13:29:23 -04001871 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1872 if (error.isError())
1873 {
1874 return error;
1875 }
1876
Brandon Jones78b1acd2014-07-15 15:33:07 -07001877 mDirtyImages = true;
1878 }
1879 else
1880 {
Geoff Langef7b0162014-09-04 13:29:23 -04001881 gl::Error error = ensureRenderTarget();
1882 if (error.isError())
1883 {
1884 return error;
1885 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001886
1887 if (isValidLevel(level))
1888 {
Geoff Langef7b0162014-09-04 13:29:23 -04001889 error = updateStorageLevel(level);
1890 if (error.isError())
1891 {
1892 return error;
1893 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001894
Geoff Langef7b0162014-09-04 13:29:23 -04001895 error = mRenderer->copyImage3D(source, sourceRect,
1896 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1897 xoffset, yoffset, zoffset, mTexStorage, level);
1898 if (error.isError())
1899 {
1900 return error;
1901 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001902 }
1903 }
Geoff Langef7b0162014-09-04 13:29:23 -04001904
1905 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001906}
1907
Geoff Lang1f8532b2014-09-05 09:46:13 -04001908gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001909{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001910 ASSERT(target == GL_TEXTURE_3D);
1911
Brandon Jones78b1acd2014-07-15 15:33:07 -07001912 for (int level = 0; level < levels; level++)
1913 {
1914 GLsizei levelWidth = std::max(1, width >> level);
1915 GLsizei levelHeight = std::max(1, height >> level);
1916 GLsizei levelDepth = std::max(1, depth >> level);
1917 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1918 }
1919
1920 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1921 {
1922 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1923 }
1924
Geoff Lang1f8532b2014-09-05 09:46:13 -04001925 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001926 bool renderTarget = IsRenderTargetUsage(mUsage);
1927 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001928
1929 gl::Error error = setCompleteTexStorage(storage);
1930 if (error.isError())
1931 {
1932 SafeDelete(storage);
1933 return error;
1934 }
1935
1936 mImmutable = true;
1937
1938 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001939}
1940
Brandon Jones6053a522014-07-25 16:22:09 -07001941void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001942{
Brandon Jones6053a522014-07-25 16:22:09 -07001943 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001944}
1945
Brandon Jones6053a522014-07-25 16:22:09 -07001946void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001947{
Brandon Jones6053a522014-07-25 16:22:09 -07001948 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001949}
1950
Brandon Jones6053a522014-07-25 16:22:09 -07001951
Jamie Madill4aa79e12014-09-29 10:46:14 -04001952void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001953{
1954 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1955 int levelCount = mipLevels();
1956 for (int level = 1; level < levelCount; level++)
1957 {
1958 redefineImage(level, getBaseLevelInternalFormat(),
1959 std::max(getBaseLevelWidth() >> level, 1),
1960 std::max(getBaseLevelHeight() >> level, 1),
1961 std::max(getBaseLevelDepth() >> level, 1));
1962 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001963}
1964
Jamie Madillac7579c2014-09-17 16:59:33 -04001965unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001966{
Geoff Langef7b0162014-09-04 13:29:23 -04001967 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001968}
1969
Geoff Lang64f23f62014-09-10 14:40:12 -04001970gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001971{
1972 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001973 gl::Error error = ensureRenderTarget();
1974 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001975 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001976 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001977 }
1978
Jamie Madillac7579c2014-09-17 16:59:33 -04001979 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001980 {
Geoff Langef7b0162014-09-04 13:29:23 -04001981 error = updateStorage();
1982 if (error.isError())
1983 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001984 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001985 }
Jamie Madillac7579c2014-09-17 16:59:33 -04001986 }
1987 else
1988 {
Geoff Langef7b0162014-09-04 13:29:23 -04001989 error = updateStorageLevel(index.mipIndex);
1990 if (error.isError())
1991 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001992 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001993 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001994 }
1995
Geoff Lang64f23f62014-09-10 14:40:12 -04001996 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001997}
1998
Geoff Langef7b0162014-09-04 13:29:23 -04001999gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002000{
2001 // Only initialize the first time this texture is used as a render target or shader resource
2002 if (mTexStorage)
2003 {
Geoff Langef7b0162014-09-04 13:29:23 -04002004 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002005 }
2006
2007 // do not attempt to create storage for nonexistant data
2008 if (!isLevelComplete(0))
2009 {
Geoff Langef7b0162014-09-04 13:29:23 -04002010 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002011 }
2012
2013 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2014
Geoff Langef7b0162014-09-04 13:29:23 -04002015 rx::TextureStorage *storage = NULL;
2016 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2017 if (error.isError())
2018 {
2019 return error;
2020 }
2021
2022 error = setCompleteTexStorage(storage);
2023 if (error.isError())
2024 {
2025 SafeDelete(storage);
2026 return error;
2027 }
2028
Brandon Jones78b1acd2014-07-15 15:33:07 -07002029 ASSERT(mTexStorage);
2030
2031 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002032 error = updateStorage();
2033 if (error.isError())
2034 {
2035 return error;
2036 }
2037
2038 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002039}
2040
Geoff Langef7b0162014-09-04 13:29:23 -04002041gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002042{
2043 GLsizei width = getBaseLevelWidth();
2044 GLsizei height = getBaseLevelHeight();
2045 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002046 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002047
2048 ASSERT(width > 0 && height > 0 && depth > 0);
2049
2050 // use existing storage level count, when previously specified by TexStorage*D
2051 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2052
Geoff Langef7b0162014-09-04 13:29:23 -04002053 // TODO: Verify creation of the storage succeeded
2054 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2055
2056 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002057}
2058
Geoff Langef7b0162014-09-04 13:29:23 -04002059gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002060{
2061 SafeDelete(mTexStorage);
2062 mTexStorage = newCompleteTexStorage;
2063 mDirtyImages = true;
2064
2065 // We do not support managed 3D storage, as that is D3D9/ES2-only
2066 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002067
2068 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002069}
2070
Geoff Langef7b0162014-09-04 13:29:23 -04002071gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002072{
2073 ASSERT(mTexStorage != NULL);
2074 GLint storageLevels = mTexStorage->getLevelCount();
2075 for (int level = 0; level < storageLevels; level++)
2076 {
2077 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2078 {
Geoff Langef7b0162014-09-04 13:29:23 -04002079 gl::Error error = updateStorageLevel(level);
2080 if (error.isError())
2081 {
2082 return error;
2083 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002084 }
2085 }
Geoff Langef7b0162014-09-04 13:29:23 -04002086
2087 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002088}
2089
Brandon Jones78b1acd2014-07-15 15:33:07 -07002090bool TextureD3D_3D::isValidLevel(int level) const
2091{
2092 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2093}
2094
2095bool TextureD3D_3D::isLevelComplete(int level) const
2096{
2097 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2098
2099 if (isImmutable())
2100 {
2101 return true;
2102 }
2103
2104 GLsizei width = getBaseLevelWidth();
2105 GLsizei height = getBaseLevelHeight();
2106 GLsizei depth = getBaseLevelDepth();
2107
2108 if (width <= 0 || height <= 0 || depth <= 0)
2109 {
2110 return false;
2111 }
2112
2113 if (level == 0)
2114 {
2115 return true;
2116 }
2117
2118 ImageD3D *levelImage = mImageArray[level];
2119
2120 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2121 {
2122 return false;
2123 }
2124
2125 if (levelImage->getWidth() != std::max(1, width >> level))
2126 {
2127 return false;
2128 }
2129
2130 if (levelImage->getHeight() != std::max(1, height >> level))
2131 {
2132 return false;
2133 }
2134
2135 if (levelImage->getDepth() != std::max(1, depth >> level))
2136 {
2137 return false;
2138 }
2139
2140 return true;
2141}
2142
Jamie Madille76bdda2014-10-20 17:13:52 -04002143bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2144{
2145 return isLevelComplete(index.mipIndex);
2146}
2147
Geoff Langef7b0162014-09-04 13:29:23 -04002148gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002149{
2150 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2151 ASSERT(isLevelComplete(level));
2152
2153 if (mImageArray[level]->isDirty())
2154 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002155 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2156 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002157 gl::Error error = commitRegion(index, region);
2158 if (error.isError())
2159 {
2160 return error;
2161 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002162 }
Geoff Langef7b0162014-09-04 13:29:23 -04002163
2164 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002165}
2166
2167void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2168{
2169 // If there currently is a corresponding storage texture image, it has these parameters
2170 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2171 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2172 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2173 const GLenum storageFormat = getBaseLevelInternalFormat();
2174
2175 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2176
2177 if (mTexStorage)
2178 {
2179 const int storageLevels = mTexStorage->getLevelCount();
2180
2181 if ((level >= storageLevels && storageLevels != 0) ||
2182 width != storageWidth ||
2183 height != storageHeight ||
2184 depth != storageDepth ||
2185 internalformat != storageFormat) // Discard mismatched storage
2186 {
2187 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2188 {
2189 mImageArray[i]->markDirty();
2190 }
2191
2192 SafeDelete(mTexStorage);
2193 mDirtyImages = true;
2194 }
2195 }
2196}
2197
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002198gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2199{
2200 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2201 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2202}
Brandon Jones142ec422014-07-16 10:31:30 -07002203
Jamie Madillcb83dc12014-09-29 10:46:12 -04002204gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2205{
2206 // The "layer" here does not apply to 3D images. We use one Image per mip.
2207 return gl::ImageIndex::Make3D(mip);
2208}
2209
Jamie Madill710e5772014-10-20 17:13:53 -04002210bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2211{
2212 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2213 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2214}
2215
Brandon Jones142ec422014-07-16 10:31:30 -07002216TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002217 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002218{
2219 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2220 {
2221 mLayerCounts[level] = 0;
2222 mImageArray[level] = NULL;
2223 }
2224}
2225
2226TextureD3D_2DArray::~TextureD3D_2DArray()
2227{
Austin Kinross69822602014-08-12 15:51:37 -07002228 // Delete the Images before the TextureStorage.
2229 // Images might be relying on the TextureStorage for some of their data.
2230 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones142ec422014-07-16 10:31:30 -07002231 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002232 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002233}
2234
Brandon Jones142ec422014-07-16 10:31:30 -07002235Image *TextureD3D_2DArray::getImage(int level, int layer) const
2236{
2237 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2238 ASSERT(layer < mLayerCounts[level]);
2239 return mImageArray[level][layer];
2240}
2241
Jamie Madillfeda4d22014-09-17 13:03:29 -04002242Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2243{
2244 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2245 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
2246 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
2247 return mImageArray[index.mipIndex][index.layerIndex];
2248}
2249
Brandon Jones142ec422014-07-16 10:31:30 -07002250GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2251{
2252 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2253 return mLayerCounts[level];
2254}
2255
Brandon Jones142ec422014-07-16 10:31:30 -07002256GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2257{
2258 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2259}
2260
2261GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2262{
2263 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2264}
2265
Brandon Jones142ec422014-07-16 10:31:30 -07002266GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2267{
2268 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2269}
2270
2271bool TextureD3D_2DArray::isDepth(GLint level) const
2272{
Geoff Lang5d601382014-07-22 15:14:06 -04002273 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002274}
2275
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002276gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2277 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2278 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002279{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002280 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2281
Geoff Lang5d601382014-07-22 15:14:06 -04002282 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2283
Brandon Jones142ec422014-07-16 10:31:30 -07002284 redefineImage(level, sizedInternalFormat, width, height, depth);
2285
Geoff Lang5d601382014-07-22 15:14:06 -04002286 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2287 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002288
2289 for (int i = 0; i < depth; i++)
2290 {
2291 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002292 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2293 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002294 if (error.isError())
2295 {
2296 return error;
2297 }
Brandon Jones142ec422014-07-16 10:31:30 -07002298 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002299
2300 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002301}
2302
Geoff Langb5348332014-09-02 13:16:34 -04002303gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2304 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002305 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002306{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002307 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2308
Brandon Jones142ec422014-07-16 10:31:30 -07002309 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2310 redefineImage(level, format, width, height, depth);
2311
Geoff Lang5d601382014-07-22 15:14:06 -04002312 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2313 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002314
2315 for (int i = 0; i < depth; i++)
2316 {
2317 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -04002318 gl::Error error = TextureD3D::setCompressedImage(unpack, imageSize, layerPixels, mImageArray[level][i]);
Geoff Langb5348332014-09-02 13:16:34 -04002319 if (error.isError())
2320 {
2321 return error;
2322 }
Brandon Jones142ec422014-07-16 10:31:30 -07002323 }
Geoff Langb5348332014-09-02 13:16:34 -04002324
2325 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002326}
2327
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002328gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2329 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2330 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002331{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002332 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2333
Geoff Lang5d601382014-07-22 15:14:06 -04002334 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2335 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002336
2337 for (int i = 0; i < depth; i++)
2338 {
2339 int layer = zoffset + i;
2340 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2341
Jamie Madillfeda4d22014-09-17 13:03:29 -04002342 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002343 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2344 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002345 if (error.isError())
2346 {
2347 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002348 }
2349 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002350
2351 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002352}
2353
Geoff Langb5348332014-09-02 13:16:34 -04002354gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2355 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002356 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002357{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002358 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2359
Geoff Lang5d601382014-07-22 15:14:06 -04002360 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2361 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002362
2363 for (int i = 0; i < depth; i++)
2364 {
2365 int layer = zoffset + i;
2366 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2367
Jamie Madillc751d1e2014-10-21 17:46:29 -04002368 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, unpack, layerPixels, mImageArray[level][layer]);
Geoff Langb5348332014-09-02 13:16:34 -04002369 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002370 {
Geoff Langb5348332014-09-02 13:16:34 -04002371 return error;
2372 }
2373
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002374 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2375 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2376 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002377 if (error.isError())
2378 {
2379 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002380 }
2381 }
Geoff Langb5348332014-09-02 13:16:34 -04002382
2383 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002384}
2385
Geoff Langef7b0162014-09-04 13:29:23 -04002386gl::Error TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07002387{
2388 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002389 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002390}
2391
Geoff Langef7b0162014-09-04 13:29:23 -04002392gl::Error TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones142ec422014-07-16 10:31:30 -07002393{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002394 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2395
Jamie Madill82bf0c52014-10-03 11:50:53 -04002396 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04002397 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002398
Jamie Madille76bdda2014-10-20 17:13:52 -04002399 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002400 {
Geoff Langef7b0162014-09-04 13:29:23 -04002401 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2402 if (error.isError())
2403 {
2404 return error;
2405 }
2406
Brandon Jones142ec422014-07-16 10:31:30 -07002407 mDirtyImages = true;
2408 }
2409 else
2410 {
Geoff Langef7b0162014-09-04 13:29:23 -04002411 gl::Error error = ensureRenderTarget();
2412 if (error.isError())
2413 {
2414 return error;
2415 }
Brandon Jones142ec422014-07-16 10:31:30 -07002416
2417 if (isValidLevel(level))
2418 {
Geoff Langef7b0162014-09-04 13:29:23 -04002419 error = updateStorageLevel(level);
2420 if (error.isError())
2421 {
2422 return error;
2423 }
Brandon Jones142ec422014-07-16 10:31:30 -07002424
Geoff Langef7b0162014-09-04 13:29:23 -04002425 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2426 xoffset, yoffset, zoffset, mTexStorage, level);
2427 if (error.isError())
2428 {
2429 return error;
2430 }
Brandon Jones142ec422014-07-16 10:31:30 -07002431 }
2432 }
Geoff Langef7b0162014-09-04 13:29:23 -04002433 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002434}
2435
Geoff Lang1f8532b2014-09-05 09:46:13 -04002436gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002437{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002438 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2439
Brandon Jones142ec422014-07-16 10:31:30 -07002440 deleteImages();
2441
2442 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2443 {
2444 GLsizei levelWidth = std::max(1, width >> level);
2445 GLsizei levelHeight = std::max(1, height >> level);
2446
2447 mLayerCounts[level] = (level < levels ? depth : 0);
2448
2449 if (mLayerCounts[level] > 0)
2450 {
2451 // Create new images for this level
2452 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2453
2454 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2455 {
2456 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2457 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2458 levelHeight, 1, true);
2459 }
2460 }
2461 }
2462
Geoff Lang1f8532b2014-09-05 09:46:13 -04002463 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002464 bool renderTarget = IsRenderTargetUsage(mUsage);
2465 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002466
2467 gl::Error error = setCompleteTexStorage(storage);
2468 if (error.isError())
2469 {
2470 SafeDelete(storage);
2471 return error;
2472 }
2473
2474 mImmutable = true;
2475
2476 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002477}
2478
Brandon Jones6053a522014-07-25 16:22:09 -07002479void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002480{
Brandon Jones6053a522014-07-25 16:22:09 -07002481 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002482}
2483
Brandon Jones6053a522014-07-25 16:22:09 -07002484void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002485{
Brandon Jones6053a522014-07-25 16:22:09 -07002486 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002487}
2488
Brandon Jones6053a522014-07-25 16:22:09 -07002489
Jamie Madill4aa79e12014-09-29 10:46:14 -04002490void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002491{
2492 int baseWidth = getBaseLevelWidth();
2493 int baseHeight = getBaseLevelHeight();
2494 int baseDepth = getBaseLevelDepth();
2495 GLenum baseFormat = getBaseLevelInternalFormat();
2496
2497 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2498 int levelCount = mipLevels();
2499 for (int level = 1; level < levelCount; level++)
2500 {
2501 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2502 }
Brandon Jones142ec422014-07-16 10:31:30 -07002503}
2504
Jamie Madillac7579c2014-09-17 16:59:33 -04002505unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002506{
Geoff Langef7b0162014-09-04 13:29:23 -04002507 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002508}
2509
Geoff Lang64f23f62014-09-10 14:40:12 -04002510gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002511{
2512 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002513 gl::Error error = ensureRenderTarget();
2514 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002515 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002516 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002517 }
2518
Geoff Langef7b0162014-09-04 13:29:23 -04002519 error = updateStorageLevel(index.mipIndex);
2520 if (error.isError())
2521 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002522 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002523 }
2524
Geoff Lang64f23f62014-09-10 14:40:12 -04002525 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002526}
2527
Geoff Langef7b0162014-09-04 13:29:23 -04002528gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002529{
2530 // Only initialize the first time this texture is used as a render target or shader resource
2531 if (mTexStorage)
2532 {
Geoff Langef7b0162014-09-04 13:29:23 -04002533 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002534 }
2535
2536 // do not attempt to create storage for nonexistant data
2537 if (!isLevelComplete(0))
2538 {
Geoff Langef7b0162014-09-04 13:29:23 -04002539 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002540 }
2541
2542 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2543
Geoff Langef7b0162014-09-04 13:29:23 -04002544 TextureStorage *storage = NULL;
2545 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2546 if (error.isError())
2547 {
2548 return error;
2549 }
2550
2551 error = setCompleteTexStorage(storage);
2552 if (error.isError())
2553 {
2554 SafeDelete(storage);
2555 return error;
2556 }
2557
Brandon Jones142ec422014-07-16 10:31:30 -07002558 ASSERT(mTexStorage);
2559
2560 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002561 error = updateStorage();
2562 if (error.isError())
2563 {
2564 return error;
2565 }
2566
2567 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002568}
2569
Geoff Langef7b0162014-09-04 13:29:23 -04002570gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002571{
2572 GLsizei width = getBaseLevelWidth();
2573 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002574 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002575 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002576
2577 ASSERT(width > 0 && height > 0 && depth > 0);
2578
2579 // use existing storage level count, when previously specified by TexStorage*D
2580 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2581
Geoff Langef7b0162014-09-04 13:29:23 -04002582 // TODO(geofflang): Verify storage creation succeeds
2583 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2584
2585 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002586}
2587
Geoff Langef7b0162014-09-04 13:29:23 -04002588gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002589{
2590 SafeDelete(mTexStorage);
2591 mTexStorage = newCompleteTexStorage;
2592 mDirtyImages = true;
2593
2594 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2595 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002596
2597 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002598}
2599
Geoff Langef7b0162014-09-04 13:29:23 -04002600gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002601{
2602 ASSERT(mTexStorage != NULL);
2603 GLint storageLevels = mTexStorage->getLevelCount();
2604 for (int level = 0; level < storageLevels; level++)
2605 {
2606 if (isLevelComplete(level))
2607 {
Geoff Langef7b0162014-09-04 13:29:23 -04002608 gl::Error error = updateStorageLevel(level);
2609 if (error.isError())
2610 {
2611 return error;
2612 }
Brandon Jones142ec422014-07-16 10:31:30 -07002613 }
2614 }
Geoff Langef7b0162014-09-04 13:29:23 -04002615
2616 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002617}
2618
Brandon Jones142ec422014-07-16 10:31:30 -07002619bool TextureD3D_2DArray::isValidLevel(int level) const
2620{
2621 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2622}
2623
2624bool TextureD3D_2DArray::isLevelComplete(int level) const
2625{
2626 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2627
2628 if (isImmutable())
2629 {
2630 return true;
2631 }
2632
2633 GLsizei width = getBaseLevelWidth();
2634 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002635 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002636
2637 if (width <= 0 || height <= 0 || layers <= 0)
2638 {
2639 return false;
2640 }
2641
2642 if (level == 0)
2643 {
2644 return true;
2645 }
2646
2647 if (getInternalFormat(level) != getInternalFormat(0))
2648 {
2649 return false;
2650 }
2651
2652 if (getWidth(level) != std::max(1, width >> level))
2653 {
2654 return false;
2655 }
2656
2657 if (getHeight(level) != std::max(1, height >> level))
2658 {
2659 return false;
2660 }
2661
Jamie Madill3269bcb2014-09-30 16:33:52 -04002662 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002663 {
2664 return false;
2665 }
2666
2667 return true;
2668}
2669
Jamie Madille76bdda2014-10-20 17:13:52 -04002670bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2671{
2672 return isLevelComplete(index.mipIndex);
2673}
2674
Geoff Langef7b0162014-09-04 13:29:23 -04002675gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002676{
2677 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2678 ASSERT(isLevelComplete(level));
2679
2680 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2681 {
2682 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2683 if (mImageArray[level][layer]->isDirty())
2684 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002685 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2686 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002687 gl::Error error = commitRegion(index, region);
2688 if (error.isError())
2689 {
2690 return error;
2691 }
Brandon Jones142ec422014-07-16 10:31:30 -07002692 }
2693 }
Geoff Langef7b0162014-09-04 13:29:23 -04002694
2695 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002696}
2697
2698void TextureD3D_2DArray::deleteImages()
2699{
2700 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2701 {
2702 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2703 {
2704 delete mImageArray[level][layer];
2705 }
2706 delete[] mImageArray[level];
2707 mImageArray[level] = NULL;
2708 mLayerCounts[level] = 0;
2709 }
2710}
2711
2712void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2713{
2714 // If there currently is a corresponding storage texture image, it has these parameters
2715 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2716 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002717 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002718 const GLenum storageFormat = getBaseLevelInternalFormat();
2719
2720 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2721 {
2722 delete mImageArray[level][layer];
2723 }
2724 delete[] mImageArray[level];
2725 mImageArray[level] = NULL;
2726 mLayerCounts[level] = depth;
2727
2728 if (depth > 0)
2729 {
2730 mImageArray[level] = new ImageD3D*[depth]();
2731
2732 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2733 {
2734 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2735 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2736 }
2737 }
2738
2739 if (mTexStorage)
2740 {
2741 const int storageLevels = mTexStorage->getLevelCount();
2742
2743 if ((level >= storageLevels && storageLevels != 0) ||
2744 width != storageWidth ||
2745 height != storageHeight ||
2746 depth != storageDepth ||
2747 internalformat != storageFormat) // Discard mismatched storage
2748 {
2749 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2750 {
2751 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2752 {
2753 mImageArray[level][layer]->markDirty();
2754 }
2755 }
2756
2757 delete mTexStorage;
2758 mTexStorage = NULL;
2759 mDirtyImages = true;
2760 }
2761 }
2762}
2763
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002764gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2765{
2766 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2767}
2768
Jamie Madillcb83dc12014-09-29 10:46:12 -04002769gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2770{
2771 return gl::ImageIndex::Make2DArray(mip, layer);
2772}
2773
Jamie Madill710e5772014-10-20 17:13:53 -04002774bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2775{
2776 // Check for having a storage and the right type of index
2777 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2778 {
2779 return false;
2780 }
2781
2782 // Check the mip index
2783 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2784 {
2785 return false;
2786 }
2787
2788 // Check the layer index
2789 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2790}
2791
Brandon Jones78b1acd2014-07-15 15:33:07 -07002792}