diff options
author | Andrew Knight <andrew.knight@digia.com> | 2014-08-05 12:59:44 +0300 |
---|---|---|
committer | Andrew Knight <andrew.knight@digia.com> | 2014-08-05 16:43:22 +0200 |
commit | a6a12d8c0fc918972c15268f749ecc7c90b95d6c (patch) | |
tree | cb6d986d30ef97e932ab51768854d5d9b46729d3 /src/3rdparty/angle/src/libGLESv2 | |
parent | 14f9c09542bd6cc19430473da9ce4c68f239ec7d (diff) |
ANGLE: upgrade to 2.1~07d49ef5350a
This version of ANGLE provides partial ES3 support, numerous
bug fixes, and several potentially useful vendor extensions.
All patches have been rebased. The following changes are noted:
0000-General-fixes-for-ANGLE-2.1.patch
contains compile fixes for the new ANGLE
0004-Make-it-possible-to-link-ANGLE-statically-for-single.patch
has incorporated patch 0015.
0007-Make-DX9-DX11-mutually-exclusive.patch
has been removed as it was fixed upstream.
0007-Fix-ANGLE-build-with-Microsoft-Visual-Studio-14-CTP.patch
has been moved up to fill the patch number gap.
0010-ANGLE-Enable-D3D11-for-feature-level-9-cards.patch
now contains patch 0014 and 0017.
0013-ANGLE-Allow-for-universal-program-binaries.patch
has been removed as it is no longer relevant.
0014-ANGLE-D3D11-Fix-internal-index-buffer-for-level-9-ha.patch
has been merged with patch 0010.
0015-ANGLE-Don-t-export-DLLMain-functions-for-static-buil.patch
has been merged with patch 0004.
0016-ANGLE-WinRT-Call-Trim-when-application-suspends.patch
has been removed and will be replaced by a follow-up patch using a
different technique.
0017-ANGLE-D3D11-Don-t-use-mipmaps-in-level-9-textures.patch
has been merged with patch 0010.
0018-ANGLE-WinRT-Create-swap-chain-using-physical-resolut.patch
has been removed and will be replaced by a follow-up patch extending
the EGL_ANGLE_window_fixed_size extension.
0019-Fix-ANGLE-build-with-Microsoft-Visual-Studio-14-CTP.patch
is now patch 0007.
[ChangeLog][Third-party libraries] ANGLE has been upgraded to
version 2.1, bringing partial support for OpenGL ES3 over
Direct3D 11, numerous bug fixes, and several new vendor extensions.
Change-Id: I6d95ce1480462d67228d83c1e5c74a1706b5b21c
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2')
212 files changed, 44648 insertions, 22014 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/BinaryStream.h b/src/3rdparty/angle/src/libGLESv2/BinaryStream.h index 21c2f86ce8..1cbfc6751d 100644 --- a/src/3rdparty/angle/src/libGLESv2/BinaryStream.h +++ b/src/3rdparty/angle/src/libGLESv2/BinaryStream.h @@ -10,6 +10,7 @@ #define LIBGLESV2_BINARYSTREAM_H_ #include "common/angleutils.h" +#include "common/mathutil.h" namespace gl { @@ -25,42 +26,49 @@ class BinaryInputStream mLength = length; } - template <typename T> - void read(T *v, size_t num) + // readInt will generate an error for bool types + template <class IntT> + IntT readInt() { - union - { - T dummy; // Compilation error for non-trivial types - } dummy; - (void) dummy; + int value; + read(&value); + return static_cast<IntT>(value); + } - if (mError) - { - return; - } + template <class IntT> + void readInt(IntT *outValue) + { + *outValue = readInt<IntT>(); + } - size_t length = num * sizeof(T); + bool readBool() + { + int value; + read(&value); + return (value > 0); + } - if (mOffset + length > mLength) - { - mError = true; - return; - } + void readBool(bool *outValue) + { + *outValue = readBool(); + } - memcpy(v, mData + mOffset, length); - mOffset += length; + void readBytes(unsigned char outArray[], size_t count) + { + read<unsigned char>(outArray, count); } - template <typename T> - void read(T * v) + std::string readString() { - read(v, 1); + std::string outString; + readString(&outString); + return outString; } - void read(std::string *v) + void readString(std::string *v) { size_t length; - read(&length); + readInt(&length); if (mError) { @@ -109,6 +117,30 @@ class BinaryInputStream size_t mOffset; const char *mData; size_t mLength; + + template <typename T> + void read(T *v, size_t num) + { + META_ASSERT(std::is_fundamental<T>::value); + + size_t length = num * sizeof(T); + + if (mOffset + length > mLength) + { + mError = true; + return; + } + + memcpy(v, mData + mOffset, length); + mOffset += length; + } + + template <typename T> + void read(T *v) + { + read(v, 1); + } + }; class BinaryOutputStream @@ -118,31 +150,24 @@ class BinaryOutputStream { } - template <typename T> - void write(const T *v, size_t num) + // writeInt also handles bool types + template <class IntT> + void writeInt(IntT param) { - union - { - T dummy; // Compilation error for non-trivial types - } dummy; - (void) dummy; - - const char *asBytes = reinterpret_cast<const char*>(v); - mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T)); + ASSERT(rx::IsIntegerCastSafe<int>(param)); + int intValue = static_cast<int>(param); + write(&intValue, 1); } - template <typename T> - void write(const T &v) + void writeString(const std::string &v) { - write(&v, 1); + writeInt(v.length()); + write(v.c_str(), v.length()); } - void write(const std::string &v) + void writeBytes(const unsigned char *bytes, size_t count) { - size_t length = v.length(); - write(length); - - write(v.c_str(), length); + write(bytes, count); } size_t length() const @@ -158,6 +183,15 @@ class BinaryOutputStream private: DISALLOW_COPY_AND_ASSIGN(BinaryOutputStream); std::vector<char> mData; + + template <typename T> + void write(const T *v, size_t num) + { + META_ASSERT(std::is_fundamental<T>::value); + const char *asBytes = reinterpret_cast<const char*>(v); + mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T)); + } + }; } diff --git a/src/3rdparty/angle/src/libGLESv2/Buffer.cpp b/src/3rdparty/angle/src/libGLESv2/Buffer.cpp index c007d5d9e9..a47b8f402f 100644 --- a/src/3rdparty/angle/src/libGLESv2/Buffer.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Buffer.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,117 +10,80 @@ // [OpenGL ES 2.0.24] section 2.9 page 21. #include "libGLESv2/Buffer.h" - -#include "libGLESv2/renderer/VertexBuffer.h" -#include "libGLESv2/renderer/IndexBuffer.h" -#include "libGLESv2/renderer/BufferStorage.h" +#include "libGLESv2/renderer/BufferImpl.h" #include "libGLESv2/renderer/Renderer.h" namespace gl { -Buffer::Buffer(rx::Renderer *renderer, GLuint id) : RefCountObject(id) +Buffer::Buffer(rx::BufferImpl *impl, GLuint id) + : RefCountObject(id), + mBuffer(impl), + mUsage(GL_DYNAMIC_DRAW), + mSize(0), + mAccessFlags(0), + mMapped(GL_FALSE), + mMapPointer(NULL), + mMapOffset(0), + mMapLength(0) { - mRenderer = renderer; - mUsage = GL_DYNAMIC_DRAW; - - mBufferStorage = renderer->createBufferStorage(); - mStaticVertexBuffer = NULL; - mStaticIndexBuffer = NULL; - mUnmodifiedDataUse = 0; } Buffer::~Buffer() { - delete mBufferStorage; - delete mStaticVertexBuffer; - delete mStaticIndexBuffer; + delete mBuffer; } void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage) { - mBufferStorage->clear(); - mIndexRangeCache.clear(); - mBufferStorage->setData(data, size, 0); - mUsage = usage; - - invalidateStaticData(); - - if (usage == GL_STATIC_DRAW) - { - mStaticVertexBuffer = new rx::StaticVertexBufferInterface(mRenderer); - mStaticIndexBuffer = new rx::StaticIndexBufferInterface(mRenderer); - } + mSize = size; + mBuffer->setData(data, size, usage); } void Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset) { - mBufferStorage->setData(data, size, offset); - mIndexRangeCache.invalidateRange(offset, size); - - if ((mStaticVertexBuffer && mStaticVertexBuffer->getBufferSize() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0)) - { - invalidateStaticData(); - } - - mUnmodifiedDataUse = 0; + mBuffer->setSubData(data, size, offset); } -rx::BufferStorage *Buffer::getStorage() const +void Buffer::copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) { - return mBufferStorage; + mBuffer->copySubData(source->getImplementation(), size, sourceOffset, destOffset); } -unsigned int Buffer::size() const +GLvoid *Buffer::mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access) { - return mBufferStorage->getSize(); -} + ASSERT(!mMapped); + ASSERT(offset + length <= mSize); -GLenum Buffer::usage() const -{ - return mUsage; -} + void *dataPointer = mBuffer->map(offset, length, access); -rx::StaticVertexBufferInterface *Buffer::getStaticVertexBuffer() -{ - return mStaticVertexBuffer; -} + mMapped = GL_TRUE; + mMapPointer = static_cast<GLvoid*>(static_cast<GLubyte*>(dataPointer)); + mMapOffset = static_cast<GLint64>(offset); + mMapLength = static_cast<GLint64>(length); + mAccessFlags = static_cast<GLint>(access); -rx::StaticIndexBufferInterface *Buffer::getStaticIndexBuffer() -{ - return mStaticIndexBuffer; + return mMapPointer; } -void Buffer::invalidateStaticData() +void Buffer::unmap() { - delete mStaticVertexBuffer; - mStaticVertexBuffer = NULL; - - delete mStaticIndexBuffer; - mStaticIndexBuffer = NULL; + ASSERT(mMapped); - mUnmodifiedDataUse = 0; -} + mBuffer->unmap(); -// Creates static buffers if sufficient used data has been left unmodified -void Buffer::promoteStaticUsage(int dataSize) -{ - if (!mStaticVertexBuffer && !mStaticIndexBuffer) - { - mUnmodifiedDataUse += dataSize; - - if (mUnmodifiedDataUse > 3 * mBufferStorage->getSize()) - { - mStaticVertexBuffer = new rx::StaticVertexBufferInterface(mRenderer); - mStaticIndexBuffer = new rx::StaticIndexBufferInterface(mRenderer); - } - } + mMapped = GL_FALSE; + mMapPointer = NULL; + mMapOffset = 0; + mMapLength = 0; + mAccessFlags = 0; } -rx::IndexRangeCache *Buffer::getIndexRangeCache() +void Buffer::markTransformFeedbackUsage() { - return &mIndexRangeCache; + // TODO: Only used by the DX11 backend. Refactor to a more appropriate place. + mBuffer->markTransformFeedbackUsage(); } } diff --git a/src/3rdparty/angle/src/libGLESv2/Buffer.h b/src/3rdparty/angle/src/libGLESv2/Buffer.h index 4048f4b906..389c3d4b00 100644 --- a/src/3rdparty/angle/src/libGLESv2/Buffer.h +++ b/src/3rdparty/angle/src/libGLESv2/Buffer.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -13,14 +13,11 @@ #include "common/angleutils.h" #include "common/RefCountObject.h" -#include "libGLESv2/renderer/IndexRangeCache.h" namespace rx { class Renderer; -class BufferStorage; -class StaticIndexBufferInterface; -class StaticVertexBufferInterface; +class BufferImpl; }; namespace gl @@ -29,38 +26,40 @@ namespace gl class Buffer : public RefCountObject { public: - Buffer(rx::Renderer *renderer, GLuint id); + Buffer(rx::BufferImpl *impl, GLuint id); virtual ~Buffer(); void bufferData(const void *data, GLsizeiptr size, GLenum usage); void bufferSubData(const void *data, GLsizeiptr size, GLintptr offset); + void copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + GLvoid *mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access); + void unmap(); - GLenum usage() const; + GLenum getUsage() const { return mUsage; } + GLint getAccessFlags() const { return mAccessFlags; } + GLboolean isMapped() const { return mMapped; } + GLvoid *getMapPointer() const { return mMapPointer; } + GLint64 getMapOffset() const { return mMapOffset; } + GLint64 getMapLength() const { return mMapLength; } + GLint64 getSize() const { return mSize; } - rx::BufferStorage *getStorage() const; - unsigned int size() const; + rx::BufferImpl *getImplementation() const { return mBuffer; } - rx::StaticVertexBufferInterface *getStaticVertexBuffer(); - rx::StaticIndexBufferInterface *getStaticIndexBuffer(); - void invalidateStaticData(); - void promoteStaticUsage(int dataSize); - - rx::IndexRangeCache *getIndexRangeCache(); + void markTransformFeedbackUsage(); private: DISALLOW_COPY_AND_ASSIGN(Buffer); - rx::Renderer *mRenderer; - GLenum mUsage; - - rx::BufferStorage *mBufferStorage; + rx::BufferImpl *mBuffer; - rx::IndexRangeCache mIndexRangeCache; - - rx::StaticVertexBufferInterface *mStaticVertexBuffer; - rx::StaticIndexBufferInterface *mStaticIndexBuffer; - unsigned int mUnmodifiedDataUse; + GLenum mUsage; + GLsizeiptr mSize; + GLint mAccessFlags; + GLboolean mMapped; + GLvoid *mMapPointer; + GLint64 mMapOffset; + GLint64 mMapLength; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/Caps.cpp b/src/3rdparty/angle/src/libGLESv2/Caps.cpp new file mode 100644 index 0000000000..c1c4dc9ee7 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Caps.cpp @@ -0,0 +1,363 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "libGLESv2/Caps.h" +#include "common/debug.h" +#include "common/angleutils.h" + +#include "angle_gl.h" + +#include <algorithm> +#include <sstream> + +namespace gl +{ + +TextureCaps::TextureCaps() + : texturable(false), + filterable(false), + renderable(false), + sampleCounts() +{ +} + +void TextureCapsMap::insert(GLenum internalFormat, const TextureCaps &caps) +{ + mCapsMap.insert(std::make_pair(internalFormat, caps)); +} + +void TextureCapsMap::remove(GLenum internalFormat) +{ + InternalFormatToCapsMap::iterator i = mCapsMap.find(internalFormat); + if (i != mCapsMap.end()) + { + mCapsMap.erase(i); + } +} + +const TextureCaps &TextureCapsMap::get(GLenum internalFormat) const +{ + static TextureCaps defaultUnsupportedTexture; + InternalFormatToCapsMap::const_iterator iter = mCapsMap.find(internalFormat); + return (iter != mCapsMap.end()) ? iter->second : defaultUnsupportedTexture; +} + +TextureCapsMap::const_iterator TextureCapsMap::begin() const +{ + return mCapsMap.begin(); +} + +TextureCapsMap::const_iterator TextureCapsMap::end() const +{ + return mCapsMap.end(); +} + +size_t TextureCapsMap::size() const +{ + return mCapsMap.size(); +} + +Extensions::Extensions() + : elementIndexUint(false), + packedDepthStencil(false), + getProgramBinary(false), + rgb8rgba8(false), + textureFormatBGRA8888(false), + readFormatBGRA(false), + pixelBufferObject(false), + mapBuffer(false), + mapBufferRange(false), + textureHalfFloat(false), + textureHalfFloatLinear(false), + textureFloat(false), + textureFloatLinear(false), + textureRG(false), + textureCompressionDXT1(false), + textureCompressionDXT3(false), + textureCompressionDXT5(false), + depthTextures(false), + textureNPOT(false), + drawBuffers(false), + textureStorage(false), + textureFilterAnisotropic(false), + maxTextureAnisotropy(false), + occlusionQueryBoolean(false), + fence(false), + timerQuery(false), + robustness(false), + blendMinMax(false), + framebufferBlit(false), + framebufferMultisample(false), + instancedArrays(false), + packReverseRowOrder(false), + standardDerivatives(false), + shaderTextureLOD(false), + fragDepth(false), + textureUsage(false), + translatedShaderSource(false), + colorBufferFloat(false) +{ +} + +static void InsertExtensionString(const std::string &extension, bool supported, std::vector<std::string> *extensionVector) +{ + if (supported) + { + extensionVector->push_back(extension); + } +} + +std::vector<std::string> Extensions::getStrings() const +{ + std::vector<std::string> extensionStrings; + + // | Extension name | Supported flag | Output vector | + InsertExtensionString("GL_OES_element_index_uint", elementIndexUint, &extensionStrings); + InsertExtensionString("GL_OES_packed_depth_stencil", packedDepthStencil, &extensionStrings); + InsertExtensionString("GL_OES_get_program_binary", getProgramBinary, &extensionStrings); + InsertExtensionString("GL_OES_rgb8_rgba8", rgb8rgba8, &extensionStrings); + InsertExtensionString("GL_EXT_texture_format_BGRA8888", textureFormatBGRA8888, &extensionStrings); + InsertExtensionString("GL_EXT_read_format_bgra", readFormatBGRA, &extensionStrings); + InsertExtensionString("GL_NV_pixel_buffer_object", pixelBufferObject, &extensionStrings); + InsertExtensionString("GL_OES_mapbuffer", mapBuffer, &extensionStrings); + InsertExtensionString("GL_EXT_map_buffer_range", mapBufferRange, &extensionStrings); + InsertExtensionString("GL_OES_texture_half_float", textureHalfFloat, &extensionStrings); + InsertExtensionString("GL_OES_texture_half_float_linear", textureHalfFloatLinear, &extensionStrings); + InsertExtensionString("GL_OES_texture_float", textureFloat, &extensionStrings); + InsertExtensionString("GL_OES_texture_float_linear", textureFloatLinear, &extensionStrings); + InsertExtensionString("GL_EXT_texture_rg", textureRG, &extensionStrings); + InsertExtensionString("GL_EXT_texture_compression_dxt1", textureCompressionDXT1, &extensionStrings); + InsertExtensionString("GL_ANGLE_texture_compression_dxt3", textureCompressionDXT3, &extensionStrings); + InsertExtensionString("GL_ANGLE_texture_compression_dxt5", textureCompressionDXT5, &extensionStrings); + InsertExtensionString("GL_EXT_sRGB", sRGB, &extensionStrings); + InsertExtensionString("GL_ANGLE_depth_texture", depthTextures, &extensionStrings); + InsertExtensionString("GL_EXT_texture_storage", textureStorage, &extensionStrings); + InsertExtensionString("GL_OES_texture_npot", textureNPOT, &extensionStrings); + InsertExtensionString("GL_EXT_draw_buffers", drawBuffers, &extensionStrings); + InsertExtensionString("GL_EXT_texture_filter_anisotropic", textureFilterAnisotropic, &extensionStrings); + InsertExtensionString("GL_EXT_occlusion_query_boolean", occlusionQueryBoolean, &extensionStrings); + InsertExtensionString("GL_NV_fence", fence, &extensionStrings); + InsertExtensionString("GL_ANGLE_timer_query", timerQuery, &extensionStrings); + InsertExtensionString("GL_EXT_robustness", robustness, &extensionStrings); + InsertExtensionString("GL_EXT_blend_minmax", blendMinMax, &extensionStrings); + InsertExtensionString("GL_ANGLE_framebuffer_blit", framebufferBlit, &extensionStrings); + InsertExtensionString("GL_ANGLE_framebuffer_multisample", framebufferMultisample, &extensionStrings); + InsertExtensionString("GL_ANGLE_instanced_arrays", instancedArrays, &extensionStrings); + InsertExtensionString("GL_ANGLE_pack_reverse_row_order", packReverseRowOrder, &extensionStrings); + InsertExtensionString("GL_OES_standard_derivatives", standardDerivatives, &extensionStrings); + InsertExtensionString("GL_EXT_shader_texture_lod", shaderTextureLOD, &extensionStrings); + InsertExtensionString("GL_EXT_frag_depth", fragDepth, &extensionStrings); + InsertExtensionString("GL_ANGLE_texture_usage", textureUsage, &extensionStrings); + InsertExtensionString("GL_ANGLE_translated_shader_source", translatedShaderSource, &extensionStrings); + InsertExtensionString("GL_EXT_color_buffer_float", colorBufferFloat, &extensionStrings); + + return extensionStrings; +} + +static bool GetFormatSupport(const TextureCapsMap &textureCaps, const std::vector<GLenum> &requiredFormats, + bool requiresFiltering, bool requiresRendering) +{ + for (size_t i = 0; i < requiredFormats.size(); i++) + { + const TextureCaps &cap = textureCaps.get(requiredFormats[i]); + + if (requiresFiltering && !cap.filterable) + { + return false; + } + + if (requiresRendering && !cap.renderable) + { + return false; + } + } + + return true; +} + +// Checks for GL_OES_rgb8_rgba8 support +static bool DetermineRGB8AndRGBA8TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_RGB8); + requiredFormats.push_back(GL_RGBA8); + + return GetFormatSupport(textureCaps, requiredFormats, true, true); +} + +// Checks for GL_EXT_texture_format_BGRA8888 support +static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_BGRA8_EXT); + + return GetFormatSupport(textureCaps, requiredFormats, true, true); +} + +// Checks for GL_OES_texture_half_float support +static bool DetermineHalfFloatTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_RGB16F); + requiredFormats.push_back(GL_RGBA16F); + + return GetFormatSupport(textureCaps, requiredFormats, false, true); +} + +// Checks for GL_OES_texture_half_float_linear support +static bool DetermineHalfFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_RGB16F); + requiredFormats.push_back(GL_RGBA16F); + + return GetFormatSupport(textureCaps, requiredFormats, true, false); +} + +// Checks for GL_OES_texture_float support +static bool DetermineFloatTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_RGB32F); + requiredFormats.push_back(GL_RGBA32F); + + return GetFormatSupport(textureCaps, requiredFormats, false, true); +} + +// Checks for GL_OES_texture_float_linear support +static bool DetermineFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_RGB32F); + requiredFormats.push_back(GL_RGBA32F); + + return GetFormatSupport(textureCaps, requiredFormats, true, false); +} + +// Checks for GL_EXT_texture_rg support +static bool DetermineRGTextureSupport(const TextureCapsMap &textureCaps, bool checkHalfFloatFormats, bool checkFloatFormats) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_R8); + requiredFormats.push_back(GL_RG8); + if (checkHalfFloatFormats) + { + requiredFormats.push_back(GL_R16F); + requiredFormats.push_back(GL_RG16F); + } + if (checkFloatFormats) + { + requiredFormats.push_back(GL_R32F); + requiredFormats.push_back(GL_RG32F); + } + + return GetFormatSupport(textureCaps, requiredFormats, true, false); +} + +// Check for GL_EXT_texture_compression_dxt1 +static bool DetermineDXT1TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_COMPRESSED_RGB_S3TC_DXT1_EXT); + requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + + return GetFormatSupport(textureCaps, requiredFormats, true, false); +} + +// Check for GL_ANGLE_texture_compression_dxt3 +static bool DetermineDXT3TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + + return GetFormatSupport(textureCaps, requiredFormats, true, false); +} + +// Check for GL_ANGLE_texture_compression_dxt5 +static bool DetermineDXT5TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + + return GetFormatSupport(textureCaps, requiredFormats, true, false); +} + +// Check for GL_ANGLE_texture_compression_dxt5 +static bool DetermineSRGBTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFilterFormats; + requiredFilterFormats.push_back(GL_SRGB8); + requiredFilterFormats.push_back(GL_SRGB8_ALPHA8); + + std::vector<GLenum> requiredRenderFormats; + requiredRenderFormats.push_back(GL_SRGB8_ALPHA8); + + return GetFormatSupport(textureCaps, requiredFilterFormats, true, false) && + GetFormatSupport(textureCaps, requiredRenderFormats, false, true); +} + +// Check for GL_ANGLE_depth_texture +static bool DetermineDepthTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_DEPTH_COMPONENT16); + requiredFormats.push_back(GL_DEPTH_COMPONENT32_OES); + requiredFormats.push_back(GL_DEPTH24_STENCIL8_OES); + + return GetFormatSupport(textureCaps, requiredFormats, true, true); +} + +// Check for GL_EXT_color_buffer_float +static bool DetermineColorBufferFloatSupport(const TextureCapsMap &textureCaps) +{ + std::vector<GLenum> requiredFormats; + requiredFormats.push_back(GL_R16F); + requiredFormats.push_back(GL_RG16F); + requiredFormats.push_back(GL_RGBA16F); + requiredFormats.push_back(GL_R32F); + requiredFormats.push_back(GL_RG32F); + requiredFormats.push_back(GL_RGBA32F); + requiredFormats.push_back(GL_R11F_G11F_B10F); + + return GetFormatSupport(textureCaps, requiredFormats, false, true); +} + +void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps) +{ + rgb8rgba8 = DetermineRGB8AndRGBA8TextureSupport(textureCaps); + textureFormatBGRA8888 = DetermineBGRA8TextureSupport(textureCaps); + textureHalfFloat = DetermineHalfFloatTextureSupport(textureCaps); + textureHalfFloatLinear = DetermineHalfFloatTextureFilteringSupport(textureCaps); + textureFloat = DetermineFloatTextureSupport(textureCaps); + textureFloatLinear = DetermineFloatTextureFilteringSupport(textureCaps); + textureRG = DetermineRGTextureSupport(textureCaps, textureHalfFloat, textureFloat); + textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps); + textureCompressionDXT3 = DetermineDXT3TextureSupport(textureCaps); + textureCompressionDXT5 = DetermineDXT5TextureSupport(textureCaps); + sRGB = DetermineSRGBTextureSupport(textureCaps); + depthTextures = DetermineDepthTextureSupport(textureCaps); + colorBufferFloat = DetermineColorBufferFloatSupport(textureCaps); +} + +Caps::Caps() + : maxElementIndex(0), + max3DTextureSize(0), + max2DTextureSize(0), + maxArrayTextureLayers(0), + maxLODBias(0), + maxCubeMapTextureSize(0), + maxRenderbufferSize(0), + maxDrawBuffers(0), + maxColorAttachments(0), + maxViewportWidth(0), + maxViewportHeight(0), + minAliasedPointSize(0), + maxAliasedPointSize(0), + minAliasedLineWidth(0) +{ +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Caps.h b/src/3rdparty/angle/src/libGLESv2/Caps.h new file mode 100644 index 0000000000..a08618ec9c --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Caps.h @@ -0,0 +1,222 @@ +#ifndef LIBGLESV2_CAPS_H +#define LIBGLESV2_CAPS_H + +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "angle_gl.h" + +#include <set> +#include <unordered_map> +#include <vector> +#include <string> + +namespace gl +{ + +struct TextureCaps +{ + TextureCaps(); + + // Supports for basic texturing: glTexImage, glTexSubImage, etc + bool texturable; + + // Support for linear or anisotropic filtering + bool filterable; + + // Support for being used as a framebuffer attachment or renderbuffer format + bool renderable; + + std::set<GLuint> sampleCounts; +}; + +class TextureCapsMap +{ + public: + typedef std::unordered_map<GLenum, TextureCaps>::const_iterator const_iterator; + + void insert(GLenum internalFormat, const TextureCaps &caps); + void remove(GLenum internalFormat); + + const TextureCaps &get(GLenum internalFormat) const; + + const_iterator begin() const; + const_iterator end() const; + + size_t size() const; + + private: + typedef std::unordered_map<GLenum, TextureCaps> InternalFormatToCapsMap; + InternalFormatToCapsMap mCapsMap; +}; + +struct Extensions +{ + Extensions(); + + // Generate a vector of supported extension strings + std::vector<std::string> getStrings() const; + + // Set all texture related extension support based on the supported textures. + // Determines support for: + // GL_OES_rgb8_rgba8 + // GL_EXT_texture_format_BGRA8888 + // GL_OES_texture_half_float, GL_OES_texture_half_float_linear + // GL_OES_texture_float, GL_OES_texture_float_linear + // GL_EXT_texture_rg + // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3, GL_ANGLE_texture_compression_dxt5 + // GL_ANGLE_depth_texture + // GL_EXT_color_buffer_float + void setTextureExtensionSupport(const TextureCapsMap &textureCaps); + + // ES2 Extension support + + // GL_OES_element_index_uint + bool elementIndexUint; + + // GL_OES_packed_depth_stencil + bool packedDepthStencil; + + // GL_OES_get_program_binary + bool getProgramBinary; + + // GL_OES_rgb8_rgba8 + // Implies that TextureCaps for GL_RGB8 and GL_RGBA8 exist + bool rgb8rgba8; + + // GL_EXT_texture_format_BGRA8888 + // Implies that TextureCaps for GL_BGRA8 exist + bool textureFormatBGRA8888; + + // GL_EXT_read_format_bgra + bool readFormatBGRA; + + // GL_NV_pixel_buffer_object + bool pixelBufferObject; + + // GL_OES_mapbuffer and GL_EXT_map_buffer_range + bool mapBuffer; + bool mapBufferRange; + + // GL_OES_texture_half_float and GL_OES_texture_half_float_linear + // Implies that TextureCaps for GL_RGB16F, GL_RGBA16F, GL_ALPHA32F_EXT, GL_LUMINANCE32F_EXT and + // GL_LUMINANCE_ALPHA32F_EXT exist + bool textureHalfFloat; + bool textureHalfFloatLinear; + + // GL_OES_texture_float and GL_OES_texture_float_linear + // Implies that TextureCaps for GL_RGB32F, GL_RGBA32F, GL_ALPHA16F_EXT, GL_LUMINANCE16F_EXT and + // GL_LUMINANCE_ALPHA16F_EXT exist + bool textureFloat; + bool textureFloatLinear; + + // GL_EXT_texture_rg + // Implies that TextureCaps for GL_R8, GL_RG8 (and floating point R/RG texture formats if floating point extensions + // are also present) exist + bool textureRG; + + // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3 and GL_ANGLE_texture_compression_dxt5 + // Implies that TextureCaps for GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT + // GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE and GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE + bool textureCompressionDXT1; + bool textureCompressionDXT3; + bool textureCompressionDXT5; + + // GL_EXT_sRGB + // Implies that TextureCaps for GL_SRGB8_ALPHA8 and GL_SRGB8 exist + // TODO: Don't advertise this extension in ES3 + bool sRGB; + + // GL_ANGLE_depth_texture + bool depthTextures; + + // GL_EXT_texture_storage + bool textureStorage; + + // GL_OES_texture_npot + bool textureNPOT; + + // GL_EXT_draw_buffers + bool drawBuffers; + + // GL_EXT_texture_filter_anisotropic + bool textureFilterAnisotropic; + GLfloat maxTextureAnisotropy; + + // GL_EXT_occlusion_query_boolean + bool occlusionQueryBoolean; + + // GL_NV_fence + bool fence; + + // GL_ANGLE_timer_query + bool timerQuery; + + // GL_EXT_robustness + bool robustness; + + // GL_EXT_blend_minmax + bool blendMinMax; + + // GL_ANGLE_framebuffer_blit + bool framebufferBlit; + + // GL_ANGLE_framebuffer_multisample + bool framebufferMultisample; + + // GL_ANGLE_instanced_arrays + bool instancedArrays; + + // GL_ANGLE_pack_reverse_row_order + bool packReverseRowOrder; + + // GL_OES_standard_derivatives + bool standardDerivatives; + + // GL_EXT_shader_texture_lod + bool shaderTextureLOD; + + // GL_EXT_frag_depth + bool fragDepth; + + // GL_ANGLE_texture_usage + bool textureUsage; + + // GL_ANGLE_translated_shader_source + bool translatedShaderSource; + + // ES3 Extension support + + // GL_EXT_color_buffer_float + bool colorBufferFloat; +}; + +struct Caps +{ + Caps(); + + // Table 6.28, implementation dependent values + GLuint64 maxElementIndex; + GLuint max3DTextureSize; + GLuint max2DTextureSize; + GLuint maxArrayTextureLayers; + GLfloat maxLODBias; + GLuint maxCubeMapTextureSize; + GLuint maxRenderbufferSize; + GLuint maxDrawBuffers; + GLuint maxColorAttachments; + GLuint maxViewportWidth; + GLuint maxViewportHeight; + GLfloat minAliasedPointSize; + GLfloat maxAliasedPointSize; + GLfloat minAliasedLineWidth; + GLfloat maxAliasedLineWidth; + +}; + +} + +#endif // LIBGLESV2_CAPS_H diff --git a/src/3rdparty/angle/src/libGLESv2/Context.cpp b/src/3rdparty/angle/src/libGLESv2/Context.cpp index e651785aed..8201acda10 100644 --- a/src/3rdparty/angle/src/libGLESv2/Context.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Context.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -11,19 +11,25 @@ #include "libGLESv2/Context.h" #include "libGLESv2/main.h" -#include "libGLESv2/utilities.h" +#include "common/utilities.h" +#include "libGLESv2/formatutils.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/Fence.h" #include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/Renderbuffer.h" #include "libGLESv2/Program.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/Query.h" #include "libGLESv2/Texture.h" #include "libGLESv2/ResourceManager.h" -#include "libGLESv2/renderer/IndexDataManager.h" +#include "libGLESv2/renderer/d3d/IndexDataManager.h" #include "libGLESv2/renderer/RenderTarget.h" #include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/VertexArray.h" +#include "libGLESv2/Sampler.h" +#include "libGLESv2/validationES.h" +#include "libGLESv2/TransformFeedback.h" #include "libEGL/Surface.h" @@ -32,95 +38,17 @@ namespace gl { -static const char* makeStaticString(const std::string& str) -{ - static std::set<std::string> strings; - std::set<std::string>::iterator it = strings.find(str); - if (it != strings.end()) - return it->c_str(); - - return strings.insert(str).first->c_str(); -} -Context::Context(const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) : mRenderer(renderer) +Context::Context(int clientVersion, const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) + : mRenderer(renderer) { ASSERT(robustAccess == false); // Unimplemented - mFenceHandleAllocator.setBaseHandle(0); - - setClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - mState.depthClearValue = 1.0f; - mState.stencilClearValue = 0; - - mState.rasterizer.cullFace = false; - mState.rasterizer.cullMode = GL_BACK; - mState.rasterizer.frontFace = GL_CCW; - mState.rasterizer.polygonOffsetFill = false; - mState.rasterizer.polygonOffsetFactor = 0.0f; - mState.rasterizer.polygonOffsetUnits = 0.0f; - mState.rasterizer.pointDrawMode = false; - mState.rasterizer.multiSample = false; - mState.scissorTest = false; - mState.scissor.x = 0; - mState.scissor.y = 0; - mState.scissor.width = 0; - mState.scissor.height = 0; - - mState.blend.blend = false; - mState.blend.sourceBlendRGB = GL_ONE; - mState.blend.sourceBlendAlpha = GL_ONE; - mState.blend.destBlendRGB = GL_ZERO; - mState.blend.destBlendAlpha = GL_ZERO; - mState.blend.blendEquationRGB = GL_FUNC_ADD; - mState.blend.blendEquationAlpha = GL_FUNC_ADD; - mState.blend.sampleAlphaToCoverage = false; - mState.blend.dither = true; - - mState.blendColor.red = 0; - mState.blendColor.green = 0; - mState.blendColor.blue = 0; - mState.blendColor.alpha = 0; - - mState.depthStencil.depthTest = false; - mState.depthStencil.depthFunc = GL_LESS; - mState.depthStencil.depthMask = true; - mState.depthStencil.stencilTest = false; - mState.depthStencil.stencilFunc = GL_ALWAYS; - mState.depthStencil.stencilMask = -1; - mState.depthStencil.stencilWritemask = -1; - mState.depthStencil.stencilBackFunc = GL_ALWAYS; - mState.depthStencil.stencilBackMask = - 1; - mState.depthStencil.stencilBackWritemask = -1; - mState.depthStencil.stencilFail = GL_KEEP; - mState.depthStencil.stencilPassDepthFail = GL_KEEP; - mState.depthStencil.stencilPassDepthPass = GL_KEEP; - mState.depthStencil.stencilBackFail = GL_KEEP; - mState.depthStencil.stencilBackPassDepthFail = GL_KEEP; - mState.depthStencil.stencilBackPassDepthPass = GL_KEEP; - - mState.stencilRef = 0; - mState.stencilBackRef = 0; - - mState.sampleCoverage = false; - mState.sampleCoverageValue = 1.0f; - mState.sampleCoverageInvert = false; - mState.generateMipmapHint = GL_DONT_CARE; - mState.fragmentShaderDerivativeHint = GL_DONT_CARE; - - mState.lineWidth = 1.0f; - - mState.viewport.x = 0; - mState.viewport.y = 0; - mState.viewport.width = 0; - mState.viewport.height = 0; - mState.zNear = 0.0f; - mState.zFar = 1.0f; - - mState.blend.colorMaskRed = true; - mState.blend.colorMaskGreen = true; - mState.blend.colorMaskBlue = true; - mState.blend.colorMaskAlpha = true; + initCaps(clientVersion); + + mClientVersion = clientVersion; + + mFenceNVHandleAllocator.setBaseHandle(0); if (shareContext != NULL) { @@ -138,10 +66,12 @@ Context::Context(const gl::Context *shareContext, rx::Renderer *renderer, bool n // In order that access to these initial textures not be lost, they are treated as texture // objects all of whose names are 0. - mTexture2DZero.set(new Texture2D(mRenderer, 0)); - mTextureCubeMapZero.set(new TextureCubeMap(mRenderer, 0)); + mTexture2DZero.set(new Texture2D(mRenderer->createTexture2D(), 0)); + mTextureCubeMapZero.set(new TextureCubeMap(mRenderer->createTextureCube(), 0)); + mTexture3DZero.set(new Texture3D(mRenderer->createTexture3D(), 0)); + mTexture2DArrayZero.set(new Texture2DArray(mRenderer->createTexture2DArray(), 0)); - mState.activeSampler = 0; + bindVertexArray(0); bindArrayBuffer(0); bindElementArrayBuffer(0); bindTextureCubeMap(0); @@ -150,15 +80,29 @@ Context::Context(const gl::Context *shareContext, rx::Renderer *renderer, bool n bindDrawFramebuffer(0); bindRenderbuffer(0); - mState.currentProgram = 0; - mCurrentProgramBinary.set(NULL); + bindGenericUniformBuffer(0); + for (int i = 0; i < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; i++) + { + bindIndexedUniformBuffer(0, i, 0, -1); + } - mState.packAlignment = 4; - mState.unpackAlignment = 4; - mState.packReverseRowOrder = false; + bindGenericTransformFeedbackBuffer(0); + for (int i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + bindIndexedTransformFeedbackBuffer(0, i, 0, -1); + } - mExtensionString = NULL; - mRendererString = NULL; + bindCopyReadBuffer(0); + bindCopyWriteBuffer(0); + bindPixelPackBuffer(0); + bindPixelUnpackBuffer(0); + + // [OpenGL ES 3.0.2] section 2.14.1 pg 85: + // In the initial state, a default transform feedback object is bound and treated as + // a transform feedback object with a name of zero. That object is bound any time + // BindTransformFeedback is called with id of zero + mTransformFeedbackZero.set(new TransformFeedback(0)); + bindTransformFeedback(0); mInvalidEnum = false; mInvalidValue = false; @@ -172,36 +116,33 @@ Context::Context(const gl::Context *shareContext, rx::Renderer *renderer, bool n mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT); mRobustAccess = robustAccess; - mSupportsBGRATextures = false; - mSupportsDXT1Textures = false; - mSupportsDXT3Textures = false; - mSupportsDXT5Textures = false; - mSupportsEventQueries = false; - mSupportsOcclusionQueries = false; mNumCompressedTextureFormats = 0; + + mState.setContext(this); } Context::~Context() { - if (mState.currentProgram != 0) + GLuint currentProgram = mState.getCurrentProgramId(); + if (currentProgram != 0) { - Program *programObject = mResourceManager->getProgram(mState.currentProgram); + Program *programObject = mResourceManager->getProgram(currentProgram); if (programObject) { programObject->release(); } - mState.currentProgram = 0; + currentProgram = 0; } - mCurrentProgramBinary.set(NULL); + mState.setCurrentProgram(0, NULL); while (!mFramebufferMap.empty()) { deleteFramebuffer(mFramebufferMap.begin()->first); } - while (!mFenceMap.empty()) + while (!mFenceNVMap.empty()) { - deleteFence(mFenceMap.begin()->first); + deleteFenceNV(mFenceNVMap.begin()->first); } while (!mQueryMap.empty()) @@ -209,35 +150,26 @@ Context::~Context() deleteQuery(mQueryMap.begin()->first); } - for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) + while (!mVertexArrayMap.empty()) { - for (int sampler = 0; sampler < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; sampler++) - { - mState.samplerTexture[type][sampler].set(NULL); - } + deleteVertexArray(mVertexArrayMap.begin()->first); } - for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) + mTransformFeedbackZero.set(NULL); + while (!mTransformFeedbackMap.empty()) { - mIncompleteTextures[type].set(NULL); + deleteTransformFeedback(mTransformFeedbackMap.begin()->first); } - for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) - { - mState.vertexAttribute[i].mBoundBuffer.set(NULL); - } - - for (int i = 0; i < QUERY_TYPE_COUNT; i++) + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) { - mState.activeQuery[i].set(NULL); + mIncompleteTextures[type].set(NULL); } - mState.arrayBuffer.set(NULL); - mState.elementArrayBuffer.set(NULL); - mState.renderbuffer.set(NULL); - mTexture2DZero.set(NULL); mTextureCubeMapZero.set(NULL); + mTexture3DZero.set(NULL); + mTexture2DArrayZero.set(NULL); mResourceManager->release(); } @@ -247,61 +179,27 @@ void Context::makeCurrent(egl::Surface *surface) if (!mHasBeenCurrent) { mMajorShaderModel = mRenderer->getMajorShaderModel(); - mMaximumPointSize = mRenderer->getMaxPointSize(); mSupportsVertexTexture = mRenderer->getVertexTextureSupport(); - mSupportsNonPower2Texture = mRenderer->getNonPower2TextureSupport(); - mSupportsInstancing = mRenderer->getInstancingSupport(); - - mMaxViewportDimension = mRenderer->getMaxViewportDimension(); - mMaxTextureDimension = std::min(std::min(mRenderer->getMaxTextureWidth(), mRenderer->getMaxTextureHeight()), - (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE); - mMaxCubeTextureDimension = std::min(mMaxTextureDimension, (int)gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE); - mMaxRenderbufferDimension = mMaxTextureDimension; - mMaxTextureLevel = log2(mMaxTextureDimension) + 1; - mMaxTextureAnisotropy = mRenderer->getTextureMaxAnisotropy(); - TRACE("MaxTextureDimension=%d, MaxCubeTextureDimension=%d, MaxRenderbufferDimension=%d, MaxTextureLevel=%d, MaxTextureAnisotropy=%f", - mMaxTextureDimension, mMaxCubeTextureDimension, mMaxRenderbufferDimension, mMaxTextureLevel, mMaxTextureAnisotropy); - - mSupportsEventQueries = mRenderer->getEventQuerySupport(); - mSupportsOcclusionQueries = mRenderer->getOcclusionQuerySupport(); - mSupportsBGRATextures = mRenderer->getBGRATextureSupport(); - mSupportsDXT1Textures = mRenderer->getDXT1TextureSupport(); - mSupportsDXT3Textures = mRenderer->getDXT3TextureSupport(); - mSupportsDXT5Textures = mRenderer->getDXT5TextureSupport(); - mSupportsFloat32Textures = mRenderer->getFloat32TextureSupport(&mSupportsFloat32LinearFilter, &mSupportsFloat32RenderableTextures); - mSupportsFloat16Textures = mRenderer->getFloat16TextureSupport(&mSupportsFloat16LinearFilter, &mSupportsFloat16RenderableTextures); - mSupportsLuminanceTextures = mRenderer->getLuminanceTextureSupport(); - mSupportsLuminanceAlphaTextures = mRenderer->getLuminanceAlphaTextureSupport(); - mSupportsDepthTextures = mRenderer->getDepthTextureSupport(); - mSupportsTextureFilterAnisotropy = mRenderer->getTextureFilterAnisotropySupport(); - mSupports32bitIndices = mRenderer->get32BitIndexSupport(); mNumCompressedTextureFormats = 0; - if (supportsDXT1Textures()) + if (mExtensions.textureCompressionDXT1) { mNumCompressedTextureFormats += 2; } - if (supportsDXT3Textures()) + if (mExtensions.textureCompressionDXT3) { mNumCompressedTextureFormats += 1; } - if (supportsDXT5Textures()) + if (mExtensions.textureCompressionDXT5) { mNumCompressedTextureFormats += 1; } - initExtensionString(); initRendererString(); + initExtensionStrings(); - mState.viewport.x = 0; - mState.viewport.y = 0; - mState.viewport.width = surface->getWidth(); - mState.viewport.height = surface->getHeight(); - - mState.scissor.x = 0; - mState.scissor.y = 0; - mState.scissor.width = surface->getWidth(); - mState.scissor.height = surface->getHeight(); + mState.setViewportParams(0, 0, surface->getWidth(), surface->getHeight()); + mState.setScissorParams(0, 0, surface->getWidth(), surface->getHeight()); mHasBeenCurrent = true; } @@ -314,6 +212,9 @@ void Context::makeCurrent(egl::Surface *surface) Framebuffer *framebufferZero = new DefaultFramebuffer(mRenderer, colorbufferZero, depthStencilbufferZero); setFramebufferZero(framebufferZero); + + // Store the current client version in the renderer + mRenderer->setCurrentClientVersion(mClientVersion); } // NOTE: this function should not assume that this context is current! @@ -329,608 +230,446 @@ bool Context::isContextLost() return mContextLost; } -void Context::setClearColor(float red, float green, float blue, float alpha) +GLuint Context::createBuffer() { - mState.colorClearValue.red = red; - mState.colorClearValue.green = green; - mState.colorClearValue.blue = blue; - mState.colorClearValue.alpha = alpha; + return mResourceManager->createBuffer(); } -void Context::setClearDepth(float depth) +GLuint Context::createProgram() { - mState.depthClearValue = depth; + return mResourceManager->createProgram(); } -void Context::setClearStencil(int stencil) +GLuint Context::createShader(GLenum type) { - mState.stencilClearValue = stencil; + return mResourceManager->createShader(type); } -void Context::setCullFace(bool enabled) +GLuint Context::createTexture() { - mState.rasterizer.cullFace = enabled; + return mResourceManager->createTexture(); } -bool Context::isCullFaceEnabled() const +GLuint Context::createRenderbuffer() { - return mState.rasterizer.cullFace; + return mResourceManager->createRenderbuffer(); } -void Context::setCullMode(GLenum mode) +GLsync Context::createFenceSync(GLenum condition) { - mState.rasterizer.cullMode = mode; -} + GLuint handle = mResourceManager->createFenceSync(); -void Context::setFrontFace(GLenum front) -{ - mState.rasterizer.frontFace = front; -} + gl::FenceSync *fenceSync = mResourceManager->getFenceSync(handle); + ASSERT(fenceSync); -void Context::setDepthTest(bool enabled) -{ - mState.depthStencil.depthTest = enabled; -} + fenceSync->set(condition); -bool Context::isDepthTestEnabled() const -{ - return mState.depthStencil.depthTest; + return reinterpret_cast<GLsync>(handle); } -void Context::setDepthFunc(GLenum depthFunc) +GLuint Context::createVertexArray() { - mState.depthStencil.depthFunc = depthFunc; -} + GLuint handle = mVertexArrayHandleAllocator.allocate(); -void Context::setDepthRange(float zNear, float zFar) -{ - mState.zNear = zNear; - mState.zFar = zFar; + // Although the spec states VAO state is not initialized until the object is bound, + // we create it immediately. The resulting behaviour is transparent to the application, + // since it's not currently possible to access the state until the object is bound. + VertexArray *vertexArray = new VertexArray(mRenderer->createVertexArray(), handle, MAX_VERTEX_ATTRIBS); + mVertexArrayMap[handle] = vertexArray; + return handle; } -void Context::setBlend(bool enabled) +GLuint Context::createSampler() { - mState.blend.blend = enabled; + return mResourceManager->createSampler(); } -bool Context::isBlendEnabled() const +GLuint Context::createTransformFeedback() { - return mState.blend.blend; + GLuint handle = mTransformFeedbackAllocator.allocate(); + TransformFeedback *transformFeedback = new TransformFeedback(handle); + transformFeedback->addRef(); + mTransformFeedbackMap[handle] = transformFeedback; + return handle; } -void Context::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha) +// Returns an unused framebuffer name +GLuint Context::createFramebuffer() { - mState.blend.sourceBlendRGB = sourceRGB; - mState.blend.destBlendRGB = destRGB; - mState.blend.sourceBlendAlpha = sourceAlpha; - mState.blend.destBlendAlpha = destAlpha; -} + GLuint handle = mFramebufferHandleAllocator.allocate(); -void Context::setBlendColor(float red, float green, float blue, float alpha) -{ - mState.blendColor.red = red; - mState.blendColor.green = green; - mState.blendColor.blue = blue; - mState.blendColor.alpha = alpha; -} + mFramebufferMap[handle] = NULL; -void Context::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation) -{ - mState.blend.blendEquationRGB = rgbEquation; - mState.blend.blendEquationAlpha = alphaEquation; + return handle; } -void Context::setStencilTest(bool enabled) +GLuint Context::createFenceNV() { - mState.depthStencil.stencilTest = enabled; -} + GLuint handle = mFenceNVHandleAllocator.allocate(); -bool Context::isStencilTestEnabled() const -{ - return mState.depthStencil.stencilTest; -} + mFenceNVMap[handle] = new FenceNV(mRenderer); -void Context::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask) -{ - mState.depthStencil.stencilFunc = stencilFunc; - mState.stencilRef = (stencilRef > 0) ? stencilRef : 0; - mState.depthStencil.stencilMask = stencilMask; + return handle; } -void Context::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask) +// Returns an unused query name +GLuint Context::createQuery() { - mState.depthStencil.stencilBackFunc = stencilBackFunc; - mState.stencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0; - mState.depthStencil.stencilBackMask = stencilBackMask; -} + GLuint handle = mQueryHandleAllocator.allocate(); -void Context::setStencilWritemask(GLuint stencilWritemask) -{ - mState.depthStencil.stencilWritemask = stencilWritemask; -} + mQueryMap[handle] = NULL; -void Context::setStencilBackWritemask(GLuint stencilBackWritemask) -{ - mState.depthStencil.stencilBackWritemask = stencilBackWritemask; + return handle; } -void Context::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass) +void Context::deleteBuffer(GLuint buffer) { - mState.depthStencil.stencilFail = stencilFail; - mState.depthStencil.stencilPassDepthFail = stencilPassDepthFail; - mState.depthStencil.stencilPassDepthPass = stencilPassDepthPass; -} + if (mResourceManager->getBuffer(buffer)) + { + detachBuffer(buffer); + } -void Context::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass) -{ - mState.depthStencil.stencilBackFail = stencilBackFail; - mState.depthStencil.stencilBackPassDepthFail = stencilBackPassDepthFail; - mState.depthStencil.stencilBackPassDepthPass = stencilBackPassDepthPass; + mResourceManager->deleteBuffer(buffer); } -void Context::setPolygonOffsetFill(bool enabled) +void Context::deleteShader(GLuint shader) { - mState.rasterizer.polygonOffsetFill = enabled; + mResourceManager->deleteShader(shader); } -bool Context::isPolygonOffsetFillEnabled() const +void Context::deleteProgram(GLuint program) { - return mState.rasterizer.polygonOffsetFill; + mResourceManager->deleteProgram(program); } -void Context::setPolygonOffsetParams(GLfloat factor, GLfloat units) +void Context::deleteTexture(GLuint texture) { - // An application can pass NaN values here, so handle this gracefully - mState.rasterizer.polygonOffsetFactor = factor != factor ? 0.0f : factor; - mState.rasterizer.polygonOffsetUnits = units != units ? 0.0f : units; -} + if (mResourceManager->getTexture(texture)) + { + detachTexture(texture); + } -void Context::setSampleAlphaToCoverage(bool enabled) -{ - mState.blend.sampleAlphaToCoverage = enabled; + mResourceManager->deleteTexture(texture); } -bool Context::isSampleAlphaToCoverageEnabled() const +void Context::deleteRenderbuffer(GLuint renderbuffer) { - return mState.blend.sampleAlphaToCoverage; -} + if (mResourceManager->getRenderbuffer(renderbuffer)) + { + detachRenderbuffer(renderbuffer); + } -void Context::setSampleCoverage(bool enabled) -{ - mState.sampleCoverage = enabled; + mResourceManager->deleteRenderbuffer(renderbuffer); } -bool Context::isSampleCoverageEnabled() const +void Context::deleteFenceSync(GLsync fenceSync) { - return mState.sampleCoverage; + // The spec specifies the underlying Fence object is not deleted until all current + // wait commands finish. However, since the name becomes invalid, we cannot query the fence, + // and since our API is currently designed for being called from a single thread, we can delete + // the fence immediately. + mResourceManager->deleteFenceSync(reinterpret_cast<GLuint>(fenceSync)); } -void Context::setSampleCoverageParams(GLclampf value, bool invert) +void Context::deleteVertexArray(GLuint vertexArray) { - mState.sampleCoverageValue = value; - mState.sampleCoverageInvert = invert; -} + auto vertexArrayObject = mVertexArrayMap.find(vertexArray); -void Context::setScissorTest(bool enabled) -{ - mState.scissorTest = enabled; -} + if (vertexArrayObject != mVertexArrayMap.end()) + { + detachVertexArray(vertexArray); -bool Context::isScissorTestEnabled() const -{ - return mState.scissorTest; + mVertexArrayHandleAllocator.release(vertexArrayObject->first); + delete vertexArrayObject->second; + mVertexArrayMap.erase(vertexArrayObject); + } } -void Context::setDither(bool enabled) +void Context::deleteSampler(GLuint sampler) { - mState.blend.dither = enabled; -} + if (mResourceManager->getSampler(sampler)) + { + detachSampler(sampler); + } -bool Context::isDitherEnabled() const -{ - return mState.blend.dither; + mResourceManager->deleteSampler(sampler); } -void Context::setLineWidth(GLfloat width) +void Context::deleteTransformFeedback(GLuint transformFeedback) { - mState.lineWidth = width; + TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(transformFeedback); + if (iter != mTransformFeedbackMap.end()) + { + detachTransformFeedback(transformFeedback); + mTransformFeedbackAllocator.release(transformFeedback); + iter->second->release(); + mTransformFeedbackMap.erase(iter); + } } -void Context::setGenerateMipmapHint(GLenum hint) +void Context::deleteFramebuffer(GLuint framebuffer) { - mState.generateMipmapHint = hint; -} + FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer); -void Context::setFragmentShaderDerivativeHint(GLenum hint) -{ - mState.fragmentShaderDerivativeHint = hint; - // TODO: Propagate the hint to shader translator so we can write - // ddx, ddx_coarse, or ddx_fine depending on the hint. - // Ignore for now. It is valid for implementations to ignore hint. -} + if (framebufferObject != mFramebufferMap.end()) + { + detachFramebuffer(framebuffer); -void Context::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height) -{ - mState.viewport.x = x; - mState.viewport.y = y; - mState.viewport.width = width; - mState.viewport.height = height; + mFramebufferHandleAllocator.release(framebufferObject->first); + delete framebufferObject->second; + mFramebufferMap.erase(framebufferObject); + } } -void Context::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height) +void Context::deleteFenceNV(GLuint fence) { - mState.scissor.x = x; - mState.scissor.y = y; - mState.scissor.width = width; - mState.scissor.height = height; + FenceNVMap::iterator fenceObject = mFenceNVMap.find(fence); + + if (fenceObject != mFenceNVMap.end()) + { + mFenceNVHandleAllocator.release(fenceObject->first); + delete fenceObject->second; + mFenceNVMap.erase(fenceObject); + } } -void Context::setColorMask(bool red, bool green, bool blue, bool alpha) +void Context::deleteQuery(GLuint query) { - mState.blend.colorMaskRed = red; - mState.blend.colorMaskGreen = green; - mState.blend.colorMaskBlue = blue; - mState.blend.colorMaskAlpha = alpha; + QueryMap::iterator queryObject = mQueryMap.find(query); + if (queryObject != mQueryMap.end()) + { + mQueryHandleAllocator.release(queryObject->first); + if (queryObject->second) + { + queryObject->second->release(); + } + mQueryMap.erase(queryObject); + } } -void Context::setDepthMask(bool mask) +Buffer *Context::getBuffer(GLuint handle) { - mState.depthStencil.depthMask = mask; + return mResourceManager->getBuffer(handle); } -void Context::setActiveSampler(unsigned int active) +Shader *Context::getShader(GLuint handle) const { - mState.activeSampler = active; + return mResourceManager->getShader(handle); } -GLuint Context::getReadFramebufferHandle() const +Program *Context::getProgram(GLuint handle) const { - return mState.readFramebuffer; + return mResourceManager->getProgram(handle); } -GLuint Context::getDrawFramebufferHandle() const +Texture *Context::getTexture(GLuint handle) const { - return mState.drawFramebuffer; + return mResourceManager->getTexture(handle); } -GLuint Context::getRenderbufferHandle() const +Renderbuffer *Context::getRenderbuffer(GLuint handle) { - return mState.renderbuffer.id(); + return mResourceManager->getRenderbuffer(handle); } -GLuint Context::getArrayBufferHandle() const +FenceSync *Context::getFenceSync(GLsync handle) const { - return mState.arrayBuffer.id(); + return mResourceManager->getFenceSync(reinterpret_cast<GLuint>(handle)); } -GLuint Context::getActiveQuery(GLenum target) const +VertexArray *Context::getVertexArray(GLuint handle) const { - Query *queryObject = NULL; - - switch (target) - { - case GL_ANY_SAMPLES_PASSED_EXT: - queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED].get(); - break; - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE].get(); - break; - default: - ASSERT(false); - } + auto vertexArray = mVertexArrayMap.find(handle); - if (queryObject) + if (vertexArray == mVertexArrayMap.end()) { - return queryObject->id(); + return NULL; } else { - return 0; + return vertexArray->second; } } -void Context::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) -{ - mState.vertexAttribute[attribNum].mArrayEnabled = enabled; -} - -const VertexAttribute &Context::getVertexAttribState(unsigned int attribNum) -{ - return mState.vertexAttribute[attribNum]; -} - -void Context::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized, - GLsizei stride, const void *pointer) -{ - mState.vertexAttribute[attribNum].mBoundBuffer.set(boundBuffer); - mState.vertexAttribute[attribNum].mSize = size; - mState.vertexAttribute[attribNum].mType = type; - mState.vertexAttribute[attribNum].mNormalized = normalized; - mState.vertexAttribute[attribNum].mStride = stride; - mState.vertexAttribute[attribNum].mPointer = pointer; -} - -const void *Context::getVertexAttribPointer(unsigned int attribNum) const -{ - return mState.vertexAttribute[attribNum].mPointer; -} - -void Context::setPackAlignment(GLint alignment) +Sampler *Context::getSampler(GLuint handle) const { - mState.packAlignment = alignment; + return mResourceManager->getSampler(handle); } -GLint Context::getPackAlignment() const +TransformFeedback *Context::getTransformFeedback(GLuint handle) const { - return mState.packAlignment; -} - -void Context::setUnpackAlignment(GLint alignment) -{ - mState.unpackAlignment = alignment; -} - -GLint Context::getUnpackAlignment() const -{ - return mState.unpackAlignment; + if (handle == 0) + { + return mTransformFeedbackZero.get(); + } + else + { + TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(handle); + return (iter != mTransformFeedbackMap.end()) ? iter->second : NULL; + } } -void Context::setPackReverseRowOrder(bool reverseRowOrder) +bool Context::isSampler(GLuint samplerName) const { - mState.packReverseRowOrder = reverseRowOrder; + return mResourceManager->isSampler(samplerName); } -bool Context::getPackReverseRowOrder() const +void Context::bindArrayBuffer(unsigned int buffer) { - return mState.packReverseRowOrder; -} + mResourceManager->checkBufferAllocation(buffer); -GLuint Context::createBuffer() -{ - return mResourceManager->createBuffer(); + mState.setArrayBufferBinding(getBuffer(buffer)); } -GLuint Context::createProgram() +void Context::bindElementArrayBuffer(unsigned int buffer) { - return mResourceManager->createProgram(); -} + mResourceManager->checkBufferAllocation(buffer); -GLuint Context::createShader(GLenum type) -{ - return mResourceManager->createShader(type); + mState.getVertexArray()->setElementArrayBuffer(getBuffer(buffer)); } -GLuint Context::createTexture() +void Context::bindTexture2D(GLuint texture) { - return mResourceManager->createTexture(); -} + mResourceManager->checkTextureAllocation(texture, TEXTURE_2D); -GLuint Context::createRenderbuffer() -{ - return mResourceManager->createRenderbuffer(); + mState.setSamplerTexture(TEXTURE_2D, getTexture(texture)); } -// Returns an unused framebuffer name -GLuint Context::createFramebuffer() +void Context::bindTextureCubeMap(GLuint texture) { - GLuint handle = mFramebufferHandleAllocator.allocate(); - - mFramebufferMap[handle] = NULL; + mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE); - return handle; + mState.setSamplerTexture(TEXTURE_CUBE, getTexture(texture)); } -GLuint Context::createFence() +void Context::bindTexture3D(GLuint texture) { - GLuint handle = mFenceHandleAllocator.allocate(); - - mFenceMap[handle] = new Fence(mRenderer); + mResourceManager->checkTextureAllocation(texture, TEXTURE_3D); - return handle; + mState.setSamplerTexture(TEXTURE_3D, getTexture(texture)); } -// Returns an unused query name -GLuint Context::createQuery() +void Context::bindTexture2DArray(GLuint texture) { - GLuint handle = mQueryHandleAllocator.allocate(); - - mQueryMap[handle] = NULL; + mResourceManager->checkTextureAllocation(texture, TEXTURE_2D_ARRAY); - return handle; + mState.setSamplerTexture(TEXTURE_2D_ARRAY, getTexture(texture)); } -void Context::deleteBuffer(GLuint buffer) +void Context::bindReadFramebuffer(GLuint framebuffer) { - if (mResourceManager->getBuffer(buffer)) + if (!getFramebuffer(framebuffer)) { - detachBuffer(buffer); + mFramebufferMap[framebuffer] = new Framebuffer(mRenderer, framebuffer); } - - mResourceManager->deleteBuffer(buffer); -} -void Context::deleteShader(GLuint shader) -{ - mResourceManager->deleteShader(shader); -} - -void Context::deleteProgram(GLuint program) -{ - mResourceManager->deleteProgram(program); + mState.setReadFramebufferBinding(getFramebuffer(framebuffer)); } -void Context::deleteTexture(GLuint texture) +void Context::bindDrawFramebuffer(GLuint framebuffer) { - if (mResourceManager->getTexture(texture)) + if (!getFramebuffer(framebuffer)) { - detachTexture(texture); + mFramebufferMap[framebuffer] = new Framebuffer(mRenderer, framebuffer); } - mResourceManager->deleteTexture(texture); -} - -void Context::deleteRenderbuffer(GLuint renderbuffer) -{ - if (mResourceManager->getRenderbuffer(renderbuffer)) - { - detachRenderbuffer(renderbuffer); - } - - mResourceManager->deleteRenderbuffer(renderbuffer); + mState.setDrawFramebufferBinding(getFramebuffer(framebuffer)); } -void Context::deleteFramebuffer(GLuint framebuffer) +void Context::bindRenderbuffer(GLuint renderbuffer) { - FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer); - - if (framebufferObject != mFramebufferMap.end()) - { - detachFramebuffer(framebuffer); + mResourceManager->checkRenderbufferAllocation(renderbuffer); - mFramebufferHandleAllocator.release(framebufferObject->first); - delete framebufferObject->second; - mFramebufferMap.erase(framebufferObject); - } + mState.setRenderbufferBinding(getRenderbuffer(renderbuffer)); } -void Context::deleteFence(GLuint fence) +void Context::bindVertexArray(GLuint vertexArray) { - FenceMap::iterator fenceObject = mFenceMap.find(fence); - - if (fenceObject != mFenceMap.end()) + if (!getVertexArray(vertexArray)) { - mFenceHandleAllocator.release(fenceObject->first); - delete fenceObject->second; - mFenceMap.erase(fenceObject); + VertexArray *vertexArrayObject = new VertexArray(mRenderer->createVertexArray(), vertexArray, MAX_VERTEX_ATTRIBS); + mVertexArrayMap[vertexArray] = vertexArrayObject; } -} -void Context::deleteQuery(GLuint query) -{ - QueryMap::iterator queryObject = mQueryMap.find(query); - if (queryObject != mQueryMap.end()) - { - mQueryHandleAllocator.release(queryObject->first); - if (queryObject->second) - { - queryObject->second->release(); - } - mQueryMap.erase(queryObject); - } -} - -Buffer *Context::getBuffer(GLuint handle) -{ - return mResourceManager->getBuffer(handle); -} - -Shader *Context::getShader(GLuint handle) -{ - return mResourceManager->getShader(handle); -} - -Program *Context::getProgram(GLuint handle) -{ - return mResourceManager->getProgram(handle); + mState.setVertexArrayBinding(getVertexArray(vertexArray)); } -Texture *Context::getTexture(GLuint handle) +void Context::bindSampler(GLuint textureUnit, GLuint sampler) { - return mResourceManager->getTexture(handle); -} + ASSERT(textureUnit < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS); // TODO: Update for backend-determined array size + mResourceManager->checkSamplerAllocation(sampler); -Renderbuffer *Context::getRenderbuffer(GLuint handle) -{ - return mResourceManager->getRenderbuffer(handle); + mState.setSamplerBinding(textureUnit, getSampler(sampler)); } -Framebuffer *Context::getReadFramebuffer() +void Context::bindGenericUniformBuffer(GLuint buffer) { - return getFramebuffer(mState.readFramebuffer); -} + mResourceManager->checkBufferAllocation(buffer); -Framebuffer *Context::getDrawFramebuffer() -{ - return mBoundDrawFramebuffer; + mState.setGenericUniformBufferBinding(getBuffer(buffer)); } -void Context::bindArrayBuffer(unsigned int buffer) +void Context::bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) { mResourceManager->checkBufferAllocation(buffer); - mState.arrayBuffer.set(getBuffer(buffer)); + mState.setIndexedUniformBufferBinding(index, getBuffer(buffer), offset, size); } -void Context::bindElementArrayBuffer(unsigned int buffer) +void Context::bindGenericTransformFeedbackBuffer(GLuint buffer) { mResourceManager->checkBufferAllocation(buffer); - mState.elementArrayBuffer.set(getBuffer(buffer)); + mState.setGenericTransformFeedbackBufferBinding(getBuffer(buffer)); } -void Context::bindTexture2D(GLuint texture) +void Context::bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) { - mResourceManager->checkTextureAllocation(texture, TEXTURE_2D); + mResourceManager->checkBufferAllocation(buffer); - mState.samplerTexture[TEXTURE_2D][mState.activeSampler].set(getTexture(texture)); + mState.setIndexedTransformFeedbackBufferBinding(index, getBuffer(buffer), offset, size); } -void Context::bindTextureCubeMap(GLuint texture) +void Context::bindCopyReadBuffer(GLuint buffer) { - mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE); + mResourceManager->checkBufferAllocation(buffer); - mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].set(getTexture(texture)); + mState.setCopyReadBufferBinding(getBuffer(buffer)); } -void Context::bindReadFramebuffer(GLuint framebuffer) +void Context::bindCopyWriteBuffer(GLuint buffer) { - if (!getFramebuffer(framebuffer)) - { - mFramebufferMap[framebuffer] = new Framebuffer(mRenderer); - } + mResourceManager->checkBufferAllocation(buffer); - mState.readFramebuffer = framebuffer; + mState.setCopyWriteBufferBinding(getBuffer(buffer)); } -void Context::bindDrawFramebuffer(GLuint framebuffer) +void Context::bindPixelPackBuffer(GLuint buffer) { - if (!getFramebuffer(framebuffer)) - { - mFramebufferMap[framebuffer] = new Framebuffer(mRenderer); - } - - mState.drawFramebuffer = framebuffer; + mResourceManager->checkBufferAllocation(buffer); - mBoundDrawFramebuffer = getFramebuffer(framebuffer); + mState.setPixelPackBufferBinding(getBuffer(buffer)); } -void Context::bindRenderbuffer(GLuint renderbuffer) +void Context::bindPixelUnpackBuffer(GLuint buffer) { - mResourceManager->checkRenderbufferAllocation(renderbuffer); + mResourceManager->checkBufferAllocation(buffer); - mState.renderbuffer.set(getRenderbuffer(renderbuffer)); + mState.setPixelUnpackBufferBinding(getBuffer(buffer)); } void Context::useProgram(GLuint program) { - GLuint priorProgram = mState.currentProgram; - mState.currentProgram = program; // Must switch before trying to delete, otherwise it only gets flagged. + GLuint priorProgramId = mState.getCurrentProgramId(); + Program *priorProgram = mResourceManager->getProgram(priorProgramId); - if (priorProgram != program) + if (priorProgramId != program) { - Program *newProgram = mResourceManager->getProgram(program); - Program *oldProgram = mResourceManager->getProgram(priorProgram); - mCurrentProgramBinary.set(NULL); + mState.setCurrentProgram(program, mResourceManager->getProgram(program)); - if (newProgram) - { - newProgram->addRef(); - mCurrentProgramBinary.set(newProgram->getProgramBinary()); - } - - if (oldProgram) + if (priorProgram) { - oldProgram->release(); + priorProgram->release(); } } } @@ -943,9 +682,9 @@ void Context::linkProgram(GLuint program) // if the current program was relinked successfully we // need to install the new executables - if (linked && program == mState.currentProgram) + if (linked && program == mState.getCurrentProgramId()) { - mCurrentProgramBinary.set(programObject->getProgramBinary()); + mState.setCurrentProgramBinary(programObject->getProgramBinary()); } } @@ -957,68 +696,25 @@ void Context::setProgramBinary(GLuint program, const void *binary, GLint length) // if the current program was reloaded successfully we // need to install the new executables - if (loaded && program == mState.currentProgram) + if (loaded && program == mState.getCurrentProgramId()) { - mCurrentProgramBinary.set(programObject->getProgramBinary()); + mState.setCurrentProgramBinary(programObject->getProgramBinary()); } } -void Context::beginQuery(GLenum target, GLuint query) +void Context::bindTransformFeedback(GLuint transformFeedback) { - // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id> - // of zero, if the active query object name for <target> is non-zero (for the - // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if - // the active query for either target is non-zero), if <id> is the name of an - // existing query object whose type does not match <target>, or if <id> is the - // active query object name for any query type, the error INVALID_OPERATION is - // generated. - - // Ensure no other queries are active - // NOTE: If other queries than occlusion are supported, we will need to check - // separately that: - // a) The query ID passed is not the current active query for any target/type - // b) There are no active queries for the requested target (and in the case - // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, - // no query may be active for either if glBeginQuery targets either. - for (int i = 0; i < QUERY_TYPE_COUNT; i++) - { - if (mState.activeQuery[i].get() != NULL) - { - return gl::error(GL_INVALID_OPERATION); - } - } - - QueryType qType; - switch (target) - { - case GL_ANY_SAMPLES_PASSED_EXT: - qType = QUERY_ANY_SAMPLES_PASSED; - break; - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE; - break; - default: - ASSERT(false); - return; - } + mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback)); +} +void Context::beginQuery(GLenum target, GLuint query) +{ Query *queryObject = getQuery(query, true, target); - - // check that name was obtained with glGenQueries - if (!queryObject) - { - return gl::error(GL_INVALID_OPERATION); - } - - // check for type mismatch - if (queryObject->getType() != target) - { - return gl::error(GL_INVALID_OPERATION); - } + ASSERT(queryObject); // set query as active for specified target - mState.activeQuery[qType].set(queryObject); + mState.setActiveQuery(target, queryObject); // begin query queryObject->begin(); @@ -1026,76 +722,62 @@ void Context::beginQuery(GLenum target, GLuint query) void Context::endQuery(GLenum target) { - QueryType qType; - - switch (target) - { - case GL_ANY_SAMPLES_PASSED_EXT: - qType = QUERY_ANY_SAMPLES_PASSED; - break; - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE; - break; - default: - ASSERT(false); - return; - } - - Query *queryObject = mState.activeQuery[qType].get(); - - if (queryObject == NULL) - { - return gl::error(GL_INVALID_OPERATION); - } + Query *queryObject = mState.getActiveQuery(target); + ASSERT(queryObject); queryObject->end(); - mState.activeQuery[qType].set(NULL); + mState.setActiveQuery(target, NULL); } void Context::setFramebufferZero(Framebuffer *buffer) { - delete mFramebufferMap[0]; - mFramebufferMap[0] = buffer; - if (mState.drawFramebuffer == 0) + // First, check to see if the old default framebuffer + // was set for draw or read framebuffer, and change + // the bindings to point to the new one before deleting it. + if (mState.getDrawFramebuffer()->id() == 0) { - mBoundDrawFramebuffer = buffer; + mState.setDrawFramebufferBinding(buffer); } + + if (mState.getReadFramebuffer()->id() == 0) + { + mState.setReadFramebufferBinding(buffer); + } + + delete mFramebufferMap[0]; + mFramebufferMap[0] = buffer; } void Context::setRenderbufferStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples) { + ASSERT(getTextureCaps().get(internalformat).renderable); + RenderbufferStorage *renderbuffer = NULL; - switch (internalformat) + + if (GetDepthBits(internalformat) > 0 && GetStencilBits(internalformat) > 0) + { + renderbuffer = new gl::DepthStencilbuffer(mRenderer, width, height, samples); + } + else if (GetDepthBits(internalformat) > 0) { - case GL_DEPTH_COMPONENT16: renderbuffer = new gl::Depthbuffer(mRenderer, width, height, samples); - break; - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGB565: - case GL_RGB8_OES: - case GL_RGBA8_OES: - case GL_BGRA8_EXT: - renderbuffer = new gl::Colorbuffer(mRenderer,width, height, internalformat, samples); - break; - case GL_STENCIL_INDEX8: + } + else if (GetStencilBits(internalformat) > 0) + { renderbuffer = new gl::Stencilbuffer(mRenderer, width, height, samples); - break; - case GL_DEPTH24_STENCIL8_OES: - renderbuffer = new gl::DepthStencilbuffer(mRenderer, width, height, samples); - break; - default: - UNREACHABLE(); return; + } + else + { + renderbuffer = new gl::Colorbuffer(mRenderer, width, height, internalformat, samples); } - Renderbuffer *renderbufferObject = mState.renderbuffer.get(); - renderbufferObject->setStorage(renderbuffer); + mState.getCurrentRenderbuffer()->setStorage(renderbuffer); } -Framebuffer *Context::getFramebuffer(unsigned int handle) +Framebuffer *Context::getFramebuffer(unsigned int handle) const { - FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle); + FramebufferMap::const_iterator framebuffer = mFramebufferMap.find(handle); if (framebuffer == mFramebufferMap.end()) { @@ -1107,11 +789,11 @@ Framebuffer *Context::getFramebuffer(unsigned int handle) } } -Fence *Context::getFence(unsigned int handle) +FenceNV *Context::getFenceNV(unsigned int handle) { - FenceMap::iterator fence = mFenceMap.find(handle); + FenceNVMap::iterator fence = mFenceNVMap.find(handle); - if (fence == mFenceMap.end()) + if (fence == mFenceNVMap.end()) { return NULL; } @@ -1140,390 +822,248 @@ Query *Context::getQuery(unsigned int handle, bool create, GLenum type) } } -Buffer *Context::getArrayBuffer() +Texture *Context::getTargetTexture(GLenum target) const { - return mState.arrayBuffer.get(); + if (!ValidTextureTarget(this, target)) + { + return NULL; + } + + switch (target) + { + case GL_TEXTURE_2D: return getTexture2D(); + case GL_TEXTURE_CUBE_MAP: return getTextureCubeMap(); + case GL_TEXTURE_3D: return getTexture3D(); + case GL_TEXTURE_2D_ARRAY: return getTexture2DArray(); + default: return NULL; + } } -Buffer *Context::getElementArrayBuffer() +Texture2D *Context::getTexture2D() const { - return mState.elementArrayBuffer.get(); + return static_cast<Texture2D*>(getSamplerTexture(mState.getActiveSampler(), TEXTURE_2D)); } -ProgramBinary *Context::getCurrentProgramBinary() +TextureCubeMap *Context::getTextureCubeMap() const { - return mCurrentProgramBinary.get(); + return static_cast<TextureCubeMap*>(getSamplerTexture(mState.getActiveSampler(), TEXTURE_CUBE)); } -Texture2D *Context::getTexture2D() +Texture3D *Context::getTexture3D() const { - return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D)); + return static_cast<Texture3D*>(getSamplerTexture(mState.getActiveSampler(), TEXTURE_3D)); } -TextureCubeMap *Context::getTextureCubeMap() +Texture2DArray *Context::getTexture2DArray() const { - return static_cast<TextureCubeMap*>(getSamplerTexture(mState.activeSampler, TEXTURE_CUBE)); + return static_cast<Texture2DArray*>(getSamplerTexture(mState.getActiveSampler(), TEXTURE_2D_ARRAY)); } -Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type) +Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type) const { - GLuint texid = mState.samplerTexture[type][sampler].id(); - - if (texid == 0) // Special case: 0 refers to different initial textures based on the target + if (mState.getSamplerTextureId(sampler, type) == 0) { switch (type) { default: UNREACHABLE(); - case TEXTURE_2D: return mTexture2DZero.get(); - case TEXTURE_CUBE: return mTextureCubeMapZero.get(); + case TEXTURE_2D: return mTexture2DZero.get(); + case TEXTURE_CUBE: return mTextureCubeMapZero.get(); + case TEXTURE_3D: return mTexture3DZero.get(); + case TEXTURE_2D_ARRAY: return mTexture2DArrayZero.get(); } } - - return mState.samplerTexture[type][sampler].get(); + else + { + return mState.getSamplerTexture(sampler, type); + } } -bool Context::getBooleanv(GLenum pname, GLboolean *params) +void Context::getBooleanv(GLenum pname, GLboolean *params) { switch (pname) { case GL_SHADER_COMPILER: *params = GL_TRUE; break; - case GL_SAMPLE_COVERAGE_INVERT: *params = mState.sampleCoverageInvert; break; - case GL_DEPTH_WRITEMASK: *params = mState.depthStencil.depthMask; break; - case GL_COLOR_WRITEMASK: - params[0] = mState.blend.colorMaskRed; - params[1] = mState.blend.colorMaskGreen; - params[2] = mState.blend.colorMaskBlue; - params[3] = mState.blend.colorMaskAlpha; - break; - case GL_CULL_FACE: *params = mState.rasterizer.cullFace; break; - case GL_POLYGON_OFFSET_FILL: *params = mState.rasterizer.polygonOffsetFill; break; - case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.blend.sampleAlphaToCoverage; break; - case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break; - case GL_SCISSOR_TEST: *params = mState.scissorTest; break; - case GL_STENCIL_TEST: *params = mState.depthStencil.stencilTest; break; - case GL_DEPTH_TEST: *params = mState.depthStencil.depthTest; break; - case GL_BLEND: *params = mState.blend.blend; break; - case GL_DITHER: *params = mState.blend.dither; break; case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break; default: - return false; + mState.getBooleanv(pname, params); + break; } - - return true; } -bool Context::getFloatv(GLenum pname, GLfloat *params) +void Context::getFloatv(GLenum pname, GLfloat *params) { - // Please note: DEPTH_CLEAR_VALUE is included in our internal getFloatv implementation - // because it is stored as a float, despite the fact that the GL ES 2.0 spec names - // GetIntegerv as its native query function. As it would require conversion in any - // case, this should make no difference to the calling application. + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. switch (pname) { - case GL_LINE_WIDTH: *params = mState.lineWidth; break; - case GL_SAMPLE_COVERAGE_VALUE: *params = mState.sampleCoverageValue; break; - case GL_DEPTH_CLEAR_VALUE: *params = mState.depthClearValue; break; - case GL_POLYGON_OFFSET_FACTOR: *params = mState.rasterizer.polygonOffsetFactor; break; - case GL_POLYGON_OFFSET_UNITS: *params = mState.rasterizer.polygonOffsetUnits; break; case GL_ALIASED_LINE_WIDTH_RANGE: - params[0] = gl::ALIASED_LINE_WIDTH_RANGE_MIN; - params[1] = gl::ALIASED_LINE_WIDTH_RANGE_MAX; + params[0] = mCaps.minAliasedLineWidth; + params[1] = mCaps.maxAliasedLineWidth; break; case GL_ALIASED_POINT_SIZE_RANGE: - params[0] = gl::ALIASED_POINT_SIZE_RANGE_MIN; - params[1] = getMaximumPointSize(); - break; - case GL_DEPTH_RANGE: - params[0] = mState.zNear; - params[1] = mState.zFar; - break; - case GL_COLOR_CLEAR_VALUE: - params[0] = mState.colorClearValue.red; - params[1] = mState.colorClearValue.green; - params[2] = mState.colorClearValue.blue; - params[3] = mState.colorClearValue.alpha; - break; - case GL_BLEND_COLOR: - params[0] = mState.blendColor.red; - params[1] = mState.blendColor.green; - params[2] = mState.blendColor.blue; - params[3] = mState.blendColor.alpha; + params[0] = mCaps.minAliasedPointSize; + params[1] = mCaps.maxAliasedPointSize; break; case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: - if (!supportsTextureFilterAnisotropy()) - { - return false; - } - *params = mMaxTextureAnisotropy; + ASSERT(mExtensions.textureFilterAnisotropic); + *params = mExtensions.maxTextureAnisotropy; break; default: - return false; + mState.getFloatv(pname, params); + break; } - - return true; } -bool Context::getIntegerv(GLenum pname, GLint *params) +void Context::getIntegerv(GLenum pname, GLint *params) { - if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) - { - unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0_EXT); - - if (colorAttachment >= mRenderer->getMaxRenderTargets()) - { - // return true to stop further operation in the parent call - return gl::error(GL_INVALID_OPERATION, true); - } - - Framebuffer *framebuffer = getDrawFramebuffer(); - - *params = framebuffer->getDrawBufferState(colorAttachment); - return true; - } + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. - // Please note: DEPTH_CLEAR_VALUE is not included in our internal getIntegerv implementation - // because it is stored as a float, despite the fact that the GL ES 2.0 spec names - // GetIntegerv as its native query function. As it would require conversion in any - // case, this should make no difference to the calling application. You may find it in - // Context::getFloatv. switch (pname) { - case GL_MAX_VERTEX_ATTRIBS: *params = gl::MAX_VERTEX_ATTRIBS; break; - case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = mRenderer->getMaxVertexUniformVectors(); break; - case GL_MAX_VARYING_VECTORS: *params = mRenderer->getMaxVaryingVectors(); break; - case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = mRenderer->getMaxCombinedTextureImageUnits(); break; - case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = mRenderer->getMaxVertexTextureImageUnits(); break; - case GL_MAX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_TEXTURE_IMAGE_UNITS; break; - case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = mRenderer->getMaxFragmentUniformVectors(); break; - case GL_MAX_RENDERBUFFER_SIZE: *params = getMaximumRenderbufferDimension(); break; - case GL_MAX_COLOR_ATTACHMENTS_EXT: *params = mRenderer->getMaxRenderTargets(); break; - case GL_MAX_DRAW_BUFFERS_EXT: *params = mRenderer->getMaxRenderTargets(); break; - case GL_NUM_SHADER_BINARY_FORMATS: *params = 0; break; - case GL_SHADER_BINARY_FORMATS: /* no shader binary formats are supported */ break; - case GL_ARRAY_BUFFER_BINDING: *params = mState.arrayBuffer.id(); break; - case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = mState.elementArrayBuffer.id(); break; - //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE - case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mState.drawFramebuffer; break; - case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mState.readFramebuffer; break; - case GL_RENDERBUFFER_BINDING: *params = mState.renderbuffer.id(); break; - case GL_CURRENT_PROGRAM: *params = mState.currentProgram; break; - case GL_PACK_ALIGNMENT: *params = mState.packAlignment; break; - case GL_PACK_REVERSE_ROW_ORDER_ANGLE: *params = mState.packReverseRowOrder; break; - case GL_UNPACK_ALIGNMENT: *params = mState.unpackAlignment; break; - case GL_GENERATE_MIPMAP_HINT: *params = mState.generateMipmapHint; break; - case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mState.fragmentShaderDerivativeHint; break; - case GL_ACTIVE_TEXTURE: *params = (mState.activeSampler + GL_TEXTURE0); break; - case GL_STENCIL_FUNC: *params = mState.depthStencil.stencilFunc; break; - case GL_STENCIL_REF: *params = mState.stencilRef; break; - case GL_STENCIL_VALUE_MASK: *params = mState.depthStencil.stencilMask; break; - case GL_STENCIL_BACK_FUNC: *params = mState.depthStencil.stencilBackFunc; break; - case GL_STENCIL_BACK_REF: *params = mState.stencilBackRef; break; - case GL_STENCIL_BACK_VALUE_MASK: *params = mState.depthStencil.stencilBackMask; break; - case GL_STENCIL_FAIL: *params = mState.depthStencil.stencilFail; break; - case GL_STENCIL_PASS_DEPTH_FAIL: *params = mState.depthStencil.stencilPassDepthFail; break; - case GL_STENCIL_PASS_DEPTH_PASS: *params = mState.depthStencil.stencilPassDepthPass; break; - case GL_STENCIL_BACK_FAIL: *params = mState.depthStencil.stencilBackFail; break; - case GL_STENCIL_BACK_PASS_DEPTH_FAIL: *params = mState.depthStencil.stencilBackPassDepthFail; break; - case GL_STENCIL_BACK_PASS_DEPTH_PASS: *params = mState.depthStencil.stencilBackPassDepthPass; break; - case GL_DEPTH_FUNC: *params = mState.depthStencil.depthFunc; break; - case GL_BLEND_SRC_RGB: *params = mState.blend.sourceBlendRGB; break; - case GL_BLEND_SRC_ALPHA: *params = mState.blend.sourceBlendAlpha; break; - case GL_BLEND_DST_RGB: *params = mState.blend.destBlendRGB; break; - case GL_BLEND_DST_ALPHA: *params = mState.blend.destBlendAlpha; break; - case GL_BLEND_EQUATION_RGB: *params = mState.blend.blendEquationRGB; break; - case GL_BLEND_EQUATION_ALPHA: *params = mState.blend.blendEquationAlpha; break; - case GL_STENCIL_WRITEMASK: *params = mState.depthStencil.stencilWritemask; break; - case GL_STENCIL_BACK_WRITEMASK: *params = mState.depthStencil.stencilBackWritemask; break; - case GL_STENCIL_CLEAR_VALUE: *params = mState.stencilClearValue; break; - case GL_SUBPIXEL_BITS: *params = 4; break; - case GL_MAX_TEXTURE_SIZE: *params = getMaximumTextureDimension(); break; - case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = getMaximumCubeTextureDimension(); break; - case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + case GL_MAX_VERTEX_ATTRIBS: *params = gl::MAX_VERTEX_ATTRIBS; break; + case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = mRenderer->getMaxVertexUniformVectors(); break; + case GL_MAX_VERTEX_UNIFORM_COMPONENTS: *params = mRenderer->getMaxVertexUniformVectors() * 4; break; + case GL_MAX_VARYING_VECTORS: *params = mRenderer->getMaxVaryingVectors(); break; + case GL_MAX_VARYING_COMPONENTS: *params = mRenderer->getMaxVaryingVectors() * 4; break; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = mRenderer->getMaxCombinedTextureImageUnits(); break; + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = mRenderer->getMaxVertexTextureImageUnits(); break; + case GL_MAX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_TEXTURE_IMAGE_UNITS; break; + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = mRenderer->getMaxFragmentUniformVectors(); break; + case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: *params = mRenderer->getMaxFragmentUniformVectors() * 4; break; + case GL_MAX_RENDERBUFFER_SIZE: *params = mCaps.maxRenderbufferSize; break; + case GL_MAX_COLOR_ATTACHMENTS_EXT: *params = mCaps.maxColorAttachments; break; + case GL_MAX_DRAW_BUFFERS_EXT: *params = mCaps.maxDrawBuffers; break; + case GL_NUM_SHADER_BINARY_FORMATS: *params = 0; break; + case GL_SHADER_BINARY_FORMATS: /* no shader binary formats are supported */ break; + //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_SUBPIXEL_BITS: *params = 4; break; + case GL_MAX_TEXTURE_SIZE: *params = mCaps.max2DTextureSize; break; + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = mCaps.maxCubeMapTextureSize; break; + case GL_MAX_3D_TEXTURE_SIZE: *params = mCaps.max3DTextureSize; break; + case GL_MAX_ARRAY_TEXTURE_LAYERS: *params = mCaps.maxArrayTextureLayers; break; + case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: *params = getUniformBufferOffsetAlignment(); break; + case GL_MAX_UNIFORM_BUFFER_BINDINGS: *params = getMaximumCombinedUniformBufferBindings(); break; + case GL_MAX_VERTEX_UNIFORM_BLOCKS: *params = mRenderer->getMaxVertexShaderUniformBuffers(); break; + case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: *params = mRenderer->getMaxFragmentShaderUniformBuffers(); break; + case GL_MAX_COMBINED_UNIFORM_BLOCKS: *params = getMaximumCombinedUniformBufferBindings(); break; + case GL_MAJOR_VERSION: *params = mClientVersion; break; + case GL_MINOR_VERSION: *params = 0; break; + case GL_MAX_ELEMENTS_INDICES: *params = mRenderer->getMaxRecommendedElementsIndices(); break; + case GL_MAX_ELEMENTS_VERTICES: *params = mRenderer->getMaxRecommendedElementsVertices(); break; + case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: *params = mRenderer->getMaxTransformFeedbackInterleavedComponents(); break; + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: *params = mRenderer->getMaxTransformFeedbackBuffers(); break; + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: *params = mRenderer->getMaxTransformFeedbackSeparateComponents(); break; + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: params[0] = mNumCompressedTextureFormats; break; case GL_MAX_SAMPLES_ANGLE: - { - GLsizei maxSamples = getMaxSupportedSamples(); - if (maxSamples != 0) - { - *params = maxSamples; - } - else - { - return false; - } - - break; - } - case GL_SAMPLE_BUFFERS: - case GL_SAMPLES: - { - gl::Framebuffer *framebuffer = getDrawFramebuffer(); - if (framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE) - { - switch (pname) - { - case GL_SAMPLE_BUFFERS: - if (framebuffer->getSamples() != 0) - { - *params = 1; - } - else - { - *params = 0; - } - break; - case GL_SAMPLES: - *params = framebuffer->getSamples(); - break; - } - } - else - { - *params = 0; - } - } + *params = static_cast<GLint>(getMaxSupportedSamples()); break; case GL_IMPLEMENTATION_COLOR_READ_TYPE: case GL_IMPLEMENTATION_COLOR_READ_FORMAT: { - GLenum format, type; - if (getCurrentReadFormatType(&format, &type)) - { - if (pname == GL_IMPLEMENTATION_COLOR_READ_FORMAT) - *params = format; - else - *params = type; - } + GLenum internalFormat, format, type; + getCurrentReadFormatType(&internalFormat, &format, &type); + if (pname == GL_IMPLEMENTATION_COLOR_READ_FORMAT) + *params = format; + else + *params = type; } break; case GL_MAX_VIEWPORT_DIMS: { - params[0] = mMaxViewportDimension; - params[1] = mMaxViewportDimension; + params[0] = mCaps.maxViewportWidth; + params[1] = mCaps.maxViewportHeight; } break; case GL_COMPRESSED_TEXTURE_FORMATS: { - if (supportsDXT1Textures()) + if (mExtensions.textureCompressionDXT1) { *params++ = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; *params++ = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; } - if (supportsDXT3Textures()) + if (mExtensions.textureCompressionDXT3) { *params++ = GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; } - if (supportsDXT5Textures()) + if (mExtensions.textureCompressionDXT5) { *params++ = GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; } } break; - case GL_VIEWPORT: - params[0] = mState.viewport.x; - params[1] = mState.viewport.y; - params[2] = mState.viewport.width; - params[3] = mState.viewport.height; + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + *params = mResetStrategy; break; - case GL_SCISSOR_BOX: - params[0] = mState.scissor.x; - params[1] = mState.scissor.y; - params[2] = mState.scissor.width; - params[3] = mState.scissor.height; + case GL_NUM_PROGRAM_BINARY_FORMATS_OES: + *params = 1; break; - case GL_CULL_FACE_MODE: *params = mState.rasterizer.cullMode; break; - case GL_FRONT_FACE: *params = mState.rasterizer.frontFace; break; - case GL_RED_BITS: - case GL_GREEN_BITS: - case GL_BLUE_BITS: - case GL_ALPHA_BITS: - { - gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::Renderbuffer *colorbuffer = framebuffer->getFirstColorbuffer(); - - if (colorbuffer) - { - switch (pname) - { - case GL_RED_BITS: *params = colorbuffer->getRedSize(); break; - case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); break; - case GL_BLUE_BITS: *params = colorbuffer->getBlueSize(); break; - case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); break; - } - } - else - { - *params = 0; - } - } + case GL_PROGRAM_BINARY_FORMATS_OES: + *params = GL_PROGRAM_BINARY_ANGLE; break; - case GL_DEPTH_BITS: - { - gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::Renderbuffer *depthbuffer = framebuffer->getDepthbuffer(); - - if (depthbuffer) - { - *params = depthbuffer->getDepthSize(); - } - else - { - *params = 0; - } - } + case GL_NUM_EXTENSIONS: + *params = static_cast<GLint>(mExtensionStrings.size()); break; - case GL_STENCIL_BITS: - { - gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer(); + default: + mState.getIntegerv(pname, params); + break; + } +} - if (stencilbuffer) - { - *params = stencilbuffer->getStencilSize(); - } - else - { - *params = 0; - } - } +void Context::getInteger64v(GLenum pname, GLint64 *params) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + switch (pname) + { + case GL_MAX_ELEMENT_INDEX: + *params = mCaps.maxElementIndex; break; - case GL_TEXTURE_BINDING_2D: + case GL_MAX_UNIFORM_BLOCK_SIZE: + *params = static_cast<GLint64>(mRenderer->getMaxUniformBufferSize()); + break; + case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: { - if (mState.activeSampler > mRenderer->getMaxCombinedTextureImageUnits() - 1) - { - gl::error(GL_INVALID_OPERATION); - return false; - } - - *params = mState.samplerTexture[TEXTURE_2D][mState.activeSampler].id(); + GLint64 uniformBufferComponents = static_cast<GLint64>(mRenderer->getMaxVertexShaderUniformBuffers()) * static_cast<GLint64>(mRenderer->getMaxUniformBufferSize() / 4); + GLint64 defaultBufferComponents = static_cast<GLint64>(mRenderer->getMaxVertexUniformVectors() * 4); + *params = uniformBufferComponents + defaultBufferComponents; } break; - case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: { - if (mState.activeSampler > mRenderer->getMaxCombinedTextureImageUnits() - 1) - { - gl::error(GL_INVALID_OPERATION); - return false; - } - - *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id(); + GLint64 uniformBufferComponents = static_cast<GLint64>(mRenderer->getMaxFragmentShaderUniformBuffers()) * static_cast<GLint64>(mRenderer->getMaxUniformBufferSize() / 4); + GLint64 defaultBufferComponents = static_cast<GLint64>(mRenderer->getMaxVertexUniformVectors() * 4); + *params = uniformBufferComponents + defaultBufferComponents; } break; - case GL_RESET_NOTIFICATION_STRATEGY_EXT: - *params = mResetStrategy; - break; - case GL_NUM_PROGRAM_BINARY_FORMATS_OES: - *params = 1; - break; - case GL_PROGRAM_BINARY_FORMATS_OES: - *params = GL_PROGRAM_BINARY_ANGLE; + case GL_MAX_SERVER_WAIT_TIMEOUT: + // We do not wait for server fence objects internally, so report a max timeout of zero. + *params = 0; break; default: - return false; + UNREACHABLE(); + break; } +} - return true; +bool Context::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + // Indexed integer queries all refer to current state, so this function is a + // mere passthrough. + return mState.getIndexedIntegerv(target, index, data); +} + +bool Context::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + // Indexed integer queries all refer to current state, so this function is a + // mere passthrough. + return mState.getIndexedInteger64v(target, index, data); } bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) @@ -1538,7 +1078,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu // Please note: the query type returned for DEPTH_CLEAR_VALUE in this implementation // is FLOAT rather than INT, as would be suggested by the GL ES 2.0 spec. This is due // to the fact that it is stored internally as a float, and so would require conversion - // if returned from Context::getIntegerv. Since this conversion is already implemented + // if returned from Context::getIntegerv. Since this conversion is already implemented // in the case that one calls glGetIntegerv to retrieve a float-typed state variable, we // place DEPTH_CLEAR_VALUE with the floats. This should make no difference to the calling // application. @@ -1549,13 +1089,13 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu *type = GL_INT; *numParams = mNumCompressedTextureFormats; } - break; + return true; case GL_SHADER_BINARY_FORMATS: { *type = GL_INT; *numParams = 0; } - break; + return true; case GL_MAX_VERTEX_ATTRIBS: case GL_MAX_VERTEX_UNIFORM_VECTORS: case GL_MAX_VARYING_VECTORS: @@ -1569,7 +1109,9 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu case GL_NUM_SHADER_BINARY_FORMATS: case GL_NUM_COMPRESSED_TEXTURE_FORMATS: case GL_ARRAY_BUFFER_BINDING: - case GL_FRAMEBUFFER_BINDING: + //case GL_FRAMEBUFFER_BINDING: // equivalent to DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: case GL_RENDERBUFFER_BINDING: case GL_CURRENT_PROGRAM: case GL_PACK_ALIGNMENT: @@ -1625,10 +1167,10 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu *type = GL_INT; *numParams = 1; } - break; + return true; case GL_MAX_SAMPLES_ANGLE: { - if (getMaxSupportedSamples() != 0) + if (mExtensions.framebufferMultisample) { *type = GL_INT; *numParams = 1; @@ -1638,20 +1180,34 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu return false; } } - break; + return true; + case GL_PIXEL_PACK_BUFFER_BINDING: + case GL_PIXEL_UNPACK_BUFFER_BINDING: + { + if (mExtensions.pixelBufferObject) + { + *type = GL_INT; + *numParams = 1; + } + else + { + return false; + } + } + return true; case GL_MAX_VIEWPORT_DIMS: { *type = GL_INT; *numParams = 2; } - break; + return true; case GL_VIEWPORT: case GL_SCISSOR_BOX: { *type = GL_INT; *numParams = 4; } - break; + return true; case GL_SHADER_COMPILER: case GL_SAMPLE_COVERAGE_INVERT: case GL_DEPTH_WRITEMASK: @@ -1669,13 +1225,13 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu *type = GL_BOOL; *numParams = 1; } - break; + return true; case GL_COLOR_WRITEMASK: { *type = GL_BOOL; *numParams = 4; } - break; + return true; case GL_POLYGON_OFFSET_FACTOR: case GL_POLYGON_OFFSET_UNITS: case GL_SAMPLE_COVERAGE_VALUE: @@ -1685,7 +1241,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu *type = GL_FLOAT; *numParams = 1; } - break; + return true; case GL_ALIASED_LINE_WIDTH_RANGE: case GL_ALIASED_POINT_SIZE_RANGE: case GL_DEPTH_RANGE: @@ -1693,49 +1249,133 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu *type = GL_FLOAT; *numParams = 2; } - break; + return true; case GL_COLOR_CLEAR_VALUE: case GL_BLEND_COLOR: { *type = GL_FLOAT; *numParams = 4; } - break; + return true; case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: - if (!supportsTextureFilterAnisotropy()) + if (!mExtensions.maxTextureAnisotropy) { return false; } *type = GL_FLOAT; *numParams = 1; - break; - default: + return true; + } + + if (mClientVersion < 3) + { return false; } - return true; + // Check for ES3.0+ parameter names + switch (pname) + { + case GL_MAX_UNIFORM_BUFFER_BINDINGS: + case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: + case GL_UNIFORM_BUFFER_BINDING: + case GL_TRANSFORM_FEEDBACK_BINDING: + case GL_COPY_READ_BUFFER_BINDING: + case GL_COPY_WRITE_BUFFER_BINDING: + case GL_TEXTURE_BINDING_3D: + case GL_TEXTURE_BINDING_2D_ARRAY: + case GL_MAX_3D_TEXTURE_SIZE: + case GL_MAX_ARRAY_TEXTURE_LAYERS: + case GL_MAX_VERTEX_UNIFORM_BLOCKS: + case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: + case GL_MAX_COMBINED_UNIFORM_BLOCKS: + case GL_MAX_VARYING_COMPONENTS: + case GL_VERTEX_ARRAY_BINDING: + case GL_MAX_VERTEX_UNIFORM_COMPONENTS: + case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: + case GL_NUM_EXTENSIONS: + case GL_MAJOR_VERSION: + case GL_MINOR_VERSION: + case GL_MAX_ELEMENTS_INDICES: + case GL_MAX_ELEMENTS_VERTICES: + case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: + { + *type = GL_INT; + *numParams = 1; + } + return true; + + case GL_MAX_ELEMENT_INDEX: + case GL_MAX_UNIFORM_BLOCK_SIZE: + case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: + case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: + case GL_MAX_SERVER_WAIT_TIMEOUT: + { + *type = GL_INT_64_ANGLEX; + *numParams = 1; + } + return true; + + case GL_TRANSFORM_FEEDBACK_ACTIVE: + case GL_TRANSFORM_FEEDBACK_PAUSED: + { + *type = GL_BOOL; + *numParams = 1; + } + return true; + } + + return false; } -// Applies the render target surface, depth stencil surface, viewport rectangle and -// scissor rectangle to the renderer -bool Context::applyRenderTarget(GLenum drawMode, bool ignoreViewport) +bool Context::getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams) { - Framebuffer *framebufferObject = getDrawFramebuffer(); + if (mClientVersion < 3) + { + return false; + } - if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) + switch (target) { - return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + case GL_UNIFORM_BUFFER_BINDING: + { + *type = GL_INT; + *numParams = 1; + } + return true; + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case GL_UNIFORM_BUFFER_START: + case GL_UNIFORM_BUFFER_SIZE: + { + *type = GL_INT_64_ANGLEX; + *numParams = 1; + } } + return false; +} + +// Applies the render target surface, depth stencil surface, viewport rectangle and +// scissor rectangle to the renderer +bool Context::applyRenderTarget(GLenum drawMode, bool ignoreViewport) +{ + Framebuffer *framebufferObject = mState.getDrawFramebuffer(); + ASSERT(framebufferObject && framebufferObject->completeness() == GL_FRAMEBUFFER_COMPLETE); + mRenderer->applyRenderTarget(framebufferObject); - if (!mRenderer->setViewport(mState.viewport, mState.zNear, mState.zFar, drawMode, mState.rasterizer.frontFace, + float nearZ, farZ; + mState.getDepthRange(&nearZ, &farZ); + if (!mRenderer->setViewport(mState.getViewport(), nearZ, farZ, drawMode, mState.getRasterizerState().frontFace, ignoreViewport)) { return false; } - mRenderer->setScissorRectangle(mState.scissor, mState.scissorTest); + mRenderer->setScissorRectangle(mState.getScissor(), mState.isScissorTestEnabled()); return true; } @@ -1743,17 +1383,22 @@ bool Context::applyRenderTarget(GLenum drawMode, bool ignoreViewport) // Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device void Context::applyState(GLenum drawMode) { - Framebuffer *framebufferObject = getDrawFramebuffer(); + Framebuffer *framebufferObject = mState.getDrawFramebuffer(); int samples = framebufferObject->getSamples(); - mState.rasterizer.pointDrawMode = (drawMode == GL_POINTS); - mState.rasterizer.multiSample = (samples != 0); - mRenderer->setRasterizerState(mState.rasterizer); + RasterizerState rasterizer = mState.getRasterizerState(); + rasterizer.pointDrawMode = (drawMode == GL_POINTS); + rasterizer.multiSample = (samples != 0); + + mRenderer->setRasterizerState(rasterizer); unsigned int mask = 0; - if (mState.sampleCoverage) + if (mState.isSampleCoverageEnabled()) { - if (mState.sampleCoverageValue != 0) + GLclampf coverageValue; + bool coverageInvert = false; + mState.getSampleCoverageParams(&coverageValue, &coverageInvert); + if (coverageValue != 0) { float threshold = 0.5f; @@ -1762,7 +1407,7 @@ void Context::applyState(GLenum drawMode) { mask <<= 1; - if ((i + 1) * mState.sampleCoverageValue >= threshold) + if ((i + 1) * coverageValue >= threshold) { threshold += 1.0f; mask |= 1; @@ -1770,7 +1415,7 @@ void Context::applyState(GLenum drawMode) } } - if (mState.sampleCoverageInvert) + if (coverageInvert) { mask = ~mask; } @@ -1779,192 +1424,333 @@ void Context::applyState(GLenum drawMode) { mask = 0xFFFFFFFF; } - mRenderer->setBlendState(framebufferObject, mState.blend, mState.blendColor, mask); + mRenderer->setBlendState(framebufferObject, mState.getBlendState(), mState.getBlendColor(), mask); - mRenderer->setDepthStencilState(mState.depthStencil, mState.stencilRef, mState.stencilBackRef, - mState.rasterizer.frontFace == GL_CCW); + mRenderer->setDepthStencilState(mState.getDepthStencilState(), mState.getStencilRef(), mState.getStencilBackRef(), + rasterizer.frontFace == GL_CCW); } // Applies the shaders and shader constants to the Direct3D 9 device -void Context::applyShaders() +void Context::applyShaders(ProgramBinary *programBinary, bool transformFeedbackActive) { - ProgramBinary *programBinary = getCurrentProgramBinary(); + const VertexAttribute *vertexAttributes = mState.getVertexArray()->getVertexAttributes(); + + VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]; + VertexFormat::GetInputLayout(inputLayout, programBinary, vertexAttributes, mState.getVertexAttribCurrentValues()); + + const Framebuffer *fbo = mState.getDrawFramebuffer(); + + mRenderer->applyShaders(programBinary, inputLayout, fbo, mState.getRasterizerState().rasterizerDiscard, transformFeedbackActive); - mRenderer->applyShaders(programBinary); - programBinary->applyUniforms(); } -// Applies the textures and sampler states to the Direct3D 9 device -void Context::applyTextures() +size_t Context::getCurrentTexturesAndSamplerStates(ProgramBinary *programBinary, SamplerType type, Texture **outTextures, + TextureType *outTextureTypes, SamplerState *outSamplers) { - applyTextures(SAMPLER_PIXEL); + size_t samplerRange = programBinary->getUsedSamplerRange(type); + for (size_t i = 0; i < samplerRange; i++) + { + outTextureTypes[i] = programBinary->getSamplerTextureType(type, i); + GLint textureUnit = programBinary->getSamplerMapping(type, i); // OpenGL texture image unit index + if (textureUnit != -1) + { + outTextures[i] = getSamplerTexture(textureUnit, outTextureTypes[i]); + outTextures[i]->getSamplerStateWithNativeOffset(&outSamplers[i]); + Sampler *samplerObject = mState.getSampler(textureUnit); + if (samplerObject) + { + samplerObject->getState(&outSamplers[i]); + } + } + else + { + outTextures[i] = NULL; + } + } + + return samplerRange; +} - if (mSupportsVertexTexture) +void Context::generateSwizzles(Texture *textures[], size_t count) +{ + for (size_t i = 0; i < count; i++) { - applyTextures(SAMPLER_VERTEX); + if (textures[i] && textures[i]->getSamplerState().swizzleRequired()) + { + mRenderer->generateSwizzle(textures[i]); + } } } -// For each Direct3D 9 sampler of either the pixel or vertex stage, +// For each Direct3D sampler of either the pixel or vertex stage, // looks up the corresponding OpenGL texture image unit and texture type, // and sets the texture and its addressing/filtering state (or NULL when inactive). -void Context::applyTextures(SamplerType type) +void Context::applyTextures(SamplerType shaderType, Texture *textures[], TextureType *textureTypes, SamplerState *samplers, + size_t textureCount, const FramebufferTextureSerialArray& framebufferSerials, + size_t framebufferSerialCount) { - ProgramBinary *programBinary = getCurrentProgramBinary(); - - FramebufferTextureSerialSet boundFramebufferTextures = getBoundFramebufferTextureSerials(); - // Range of Direct3D samplers of given sampler type - int samplerCount = (type == SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS : mRenderer->getMaxVertexTextureImageUnits(); - int samplerRange = programBinary->getUsedSamplerRange(type); + size_t samplerCount = (shaderType == SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS + : mRenderer->getMaxVertexTextureImageUnits(); - for (int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) + for (size_t samplerIndex = 0; samplerIndex < textureCount; samplerIndex++) { - int textureUnit = programBinary->getSamplerMapping(type, samplerIndex); // OpenGL texture image unit index + Texture *texture = textures[samplerIndex]; + const SamplerState &sampler = samplers[samplerIndex]; + TextureType textureType = textureTypes[samplerIndex]; - if (textureUnit != -1) + if (texture) { - TextureType textureType = programBinary->getSamplerTextureType(type, samplerIndex); - Texture *texture = getSamplerTexture(textureUnit, textureType); - - if (texture->isSamplerComplete() && - boundFramebufferTextures.find(texture->getTextureSerial()) == boundFramebufferTextures.end()) + // TODO: std::binary_search may become unavailable using older versions of GCC + if (texture->isSamplerComplete(sampler) && + !std::binary_search(framebufferSerials.begin(), framebufferSerials.begin() + framebufferSerialCount, texture->getTextureSerial())) { - SamplerState samplerState; - texture->getSamplerState(&samplerState); - mRenderer->setSamplerState(type, samplerIndex, samplerState); - - mRenderer->setTexture(type, samplerIndex, texture); - + mRenderer->setSamplerState(shaderType, samplerIndex, sampler); + mRenderer->setTexture(shaderType, samplerIndex, texture); texture->resetDirty(); } else { - mRenderer->setTexture(type, samplerIndex, getIncompleteTexture(textureType)); + Texture *incompleteTexture = getIncompleteTexture(textureType); + mRenderer->setTexture(shaderType, samplerIndex, incompleteTexture); + incompleteTexture->resetDirty(); } } else { - mRenderer->setTexture(type, samplerIndex, NULL); + mRenderer->setTexture(shaderType, samplerIndex, NULL); } } - for (int samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) + for (size_t samplerIndex = textureCount; samplerIndex < samplerCount; samplerIndex++) { - mRenderer->setTexture(type, samplerIndex, NULL); + mRenderer->setTexture(shaderType, samplerIndex, NULL); } } -void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLsizei *bufSize, void* pixels) +bool Context::applyUniformBuffers() { - Framebuffer *framebuffer = getReadFramebuffer(); + Program *programObject = getProgram(mState.getCurrentProgramId()); + ProgramBinary *programBinary = programObject->getProgramBinary(); + + std::vector<gl::Buffer*> boundBuffers; - if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < programBinary->getActiveUniformBlockCount(); uniformBlockIndex++) { - return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION); + GLuint blockBinding = programObject->getUniformBlockBinding(uniformBlockIndex); + + if (mState.getIndexedUniformBuffer(blockBinding)->id() == 0) + { + // undefined behaviour + return false; + } + else + { + Buffer *uniformBuffer = mState.getIndexedUniformBuffer(blockBinding); + ASSERT(uniformBuffer); + boundBuffers.push_back(uniformBuffer); + } } - if (getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0) + return programBinary->applyUniformBuffers(boundBuffers); +} + +bool Context::applyTransformFeedbackBuffers() +{ + TransformFeedback *curTransformFeedback = mState.getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) + { + Buffer *transformFeedbackBuffers[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + GLintptr transformFeedbackOffsets[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + transformFeedbackBuffers[i] = mState.getIndexedTransformFeedbackBuffer(i); + transformFeedbackOffsets[i] = mState.getIndexedTransformFeedbackBufferOffset(i); + } + mRenderer->applyTransformFeedbackBuffers(transformFeedbackBuffers, transformFeedbackOffsets); + return true; + } + else { - return gl::error(GL_INVALID_OPERATION); + return false; } +} - GLsizei outputPitch = ComputePitch(width, ConvertSizedInternalFormat(format, type), getPackAlignment()); - // sized query sanity check - if (bufSize) +void Context::markTransformFeedbackUsage() +{ + for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) { - int requiredSize = outputPitch * height; - if (requiredSize > *bufSize) + Buffer *buffer = mState.getIndexedTransformFeedbackBuffer(i); + if (buffer) { - return gl::error(GL_INVALID_OPERATION); + buffer->markTransformFeedbackUsage(); } } - - mRenderer->readPixels(framebuffer, x, y, width, height, format, type, outputPitch, getPackReverseRowOrder(), getPackAlignment(), pixels); } void Context::clear(GLbitfield mask) { - Framebuffer *framebufferObject = getDrawFramebuffer(); + if (mState.isRasterizerDiscardEnabled()) + { + return; + } + + ClearParameters clearParams = mState.getClearParameters(mask); - if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) + if (!applyRenderTarget(GL_TRIANGLES, true)) // Clips the clear to the scissor rectangle but not the viewport { - return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION); + return; } - DWORD flags = 0; - GLbitfield finalMask = 0; + mRenderer->clear(clearParams, mState.getDrawFramebuffer()); +} - if (mask & GL_COLOR_BUFFER_BIT) +void Context::clearBufferfv(GLenum buffer, int drawbuffer, const float *values) +{ + if (mState.isRasterizerDiscardEnabled()) { - mask &= ~GL_COLOR_BUFFER_BIT; + return; + } - if (framebufferObject->hasEnabledColorAttachment()) + // glClearBufferfv can be called to clear the color buffer or depth buffer + ClearParameters clearParams = mState.getClearParameters(0); + + if (buffer == GL_COLOR) + { + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) { - finalMask |= GL_COLOR_BUFFER_BIT; + clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i)); } + clearParams.colorFClearValue = ColorF(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_FLOAT; + } + + if (buffer == GL_DEPTH) + { + clearParams.clearDepth = true; + clearParams.depthClearValue = values[0]; + } + + if (!applyRenderTarget(GL_TRIANGLES, true)) // Clips the clear to the scissor rectangle but not the viewport + { + return; + } + + mRenderer->clear(clearParams, mState.getDrawFramebuffer()); +} + +void Context::clearBufferuiv(GLenum buffer, int drawbuffer, const unsigned int *values) +{ + if (mState.isRasterizerDiscardEnabled()) + { + return; + } + + // glClearBufferuv can only be called to clear a color buffer + ClearParameters clearParams = mState.getClearParameters(0); + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i)); + } + clearParams.colorUIClearValue = ColorUI(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_UNSIGNED_INT; + + if (!applyRenderTarget(GL_TRIANGLES, true)) // Clips the clear to the scissor rectangle but not the viewport + { + return; + } + + mRenderer->clear(clearParams, mState.getDrawFramebuffer()); +} + +void Context::clearBufferiv(GLenum buffer, int drawbuffer, const int *values) +{ + if (mState.isRasterizerDiscardEnabled()) + { + return; } - if (mask & GL_DEPTH_BUFFER_BIT) + // glClearBufferfv can be called to clear the color buffer or stencil buffer + ClearParameters clearParams = mState.getClearParameters(0); + + if (buffer == GL_COLOR) { - mask &= ~GL_DEPTH_BUFFER_BIT; - if (mState.depthStencil.depthMask && framebufferObject->getDepthbufferType() != GL_NONE) + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) { - finalMask |= GL_DEPTH_BUFFER_BIT; + clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i)); } + clearParams.colorIClearValue = ColorI(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_INT; } - if (mask & GL_STENCIL_BUFFER_BIT) + if (buffer == GL_STENCIL) { - mask &= ~GL_STENCIL_BUFFER_BIT; - if (framebufferObject->getStencilbufferType() != GL_NONE) - { - rx::RenderTarget *depthStencil = framebufferObject->getStencilbuffer()->getDepthStencil(); - if (!depthStencil) - { - ERR("Depth stencil pointer unexpectedly null."); - return; - } + clearParams.clearStencil = true; + clearParams.stencilClearValue = values[1]; + } - if (GetStencilSize(depthStencil->getActualFormat()) > 0) - { - finalMask |= GL_STENCIL_BUFFER_BIT; - } - } + if (!applyRenderTarget(GL_TRIANGLES, true)) // Clips the clear to the scissor rectangle but not the viewport + { + return; } - if (mask != 0) + mRenderer->clear(clearParams, mState.getDrawFramebuffer()); +} + +void Context::clearBufferfi(GLenum buffer, int drawbuffer, float depth, int stencil) +{ + if (mState.isRasterizerDiscardEnabled()) { - return gl::error(GL_INVALID_VALUE); + return; } + // glClearBufferfi can only be called to clear a depth stencil buffer + ClearParameters clearParams = mState.getClearParameters(0); + clearParams.clearDepth = true; + clearParams.depthClearValue = depth; + clearParams.clearStencil = true; + clearParams.stencilClearValue = stencil; + if (!applyRenderTarget(GL_TRIANGLES, true)) // Clips the clear to the scissor rectangle but not the viewport { return; } - ClearParameters clearParams; - clearParams.mask = finalMask; - clearParams.colorClearValue = mState.colorClearValue; - clearParams.colorMaskRed = mState.blend.colorMaskRed; - clearParams.colorMaskGreen = mState.blend.colorMaskGreen; - clearParams.colorMaskBlue = mState.blend.colorMaskBlue; - clearParams.colorMaskAlpha = mState.blend.colorMaskAlpha; - clearParams.depthClearValue = mState.depthClearValue; - clearParams.stencilClearValue = mState.stencilClearValue; - clearParams.stencilWriteMask = mState.depthStencil.stencilWritemask; + mRenderer->clear(clearParams, mState.getDrawFramebuffer()); +} + +void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, void* pixels) +{ + gl::Framebuffer *framebuffer = mState.getReadFramebuffer(); + + bool isSized = IsSizedInternalFormat(format); + GLenum sizedInternalFormat = (isSized ? format : GetSizedInternalFormat(format, type)); + GLuint outputPitch = GetRowPitch(sizedInternalFormat, type, width, mState.getPackAlignment()); - mRenderer->clear(clearParams, framebufferObject); + mRenderer->readPixels(framebuffer, x, y, width, height, format, type, outputPitch, mState.getPackState(), pixels); } void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances) { - if (!mState.currentProgram) - { - return gl::error(GL_INVALID_OPERATION); - } + ASSERT(mState.getCurrentProgramId() != 0); + + ProgramBinary *programBinary = mState.getCurrentProgramBinary(); + programBinary->updateSamplerMapping(); + + Texture *vsTextures[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + TextureType vsTextureTypes[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + SamplerState vsSamplers[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + size_t vsTextureCount = getCurrentTexturesAndSamplerStates(programBinary, SAMPLER_VERTEX, vsTextures, vsTextureTypes, vsSamplers); + + Texture *psTextures[MAX_TEXTURE_IMAGE_UNITS]; + TextureType psTextureTypes[MAX_TEXTURE_IMAGE_UNITS]; + SamplerState psSamplers[MAX_TEXTURE_IMAGE_UNITS]; + size_t psTextureCount = getCurrentTexturesAndSamplerStates(programBinary, SAMPLER_PIXEL, psTextures, psTextureTypes, psSamplers); + + generateSwizzles(vsTextures, vsTextureCount); + generateSwizzles(psTextures, psTextureCount); if (!mRenderer->applyPrimitiveType(mode, count)) { @@ -1978,40 +1764,58 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instan applyState(mode); - ProgramBinary *programBinary = getCurrentProgramBinary(); - - GLenum err = mRenderer->applyVertexBuffer(programBinary, mState.vertexAttribute, first, count, instances); + GLenum err = mRenderer->applyVertexBuffer(programBinary, mState.getVertexArray()->getVertexAttributes(), mState.getVertexAttribCurrentValues(), first, count, instances); if (err != GL_NO_ERROR) { return gl::error(err); } - applyShaders(); - applyTextures(); + bool transformFeedbackActive = applyTransformFeedbackBuffers(); + + applyShaders(programBinary, transformFeedbackActive); - if (!programBinary->validateSamplers(NULL)) + FramebufferTextureSerialArray frameBufferSerials; + size_t framebufferSerialCount = getBoundFramebufferTextureSerials(&frameBufferSerials); + + applyTextures(SAMPLER_VERTEX, vsTextures, vsTextureTypes, vsSamplers, vsTextureCount, frameBufferSerials, framebufferSerialCount); + applyTextures(SAMPLER_PIXEL, psTextures, psTextureTypes, psSamplers, psTextureCount, frameBufferSerials, framebufferSerialCount); + + if (!applyUniformBuffers()) { - return gl::error(GL_INVALID_OPERATION); + return; } if (!skipDraw(mode)) { - mRenderer->drawArrays(mode, count, instances); + mRenderer->drawArrays(mode, count, instances, transformFeedbackActive); + + if (transformFeedbackActive) + { + markTransformFeedbackUsage(); + } } } void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances) { - if (!mState.currentProgram) - { - return gl::error(GL_INVALID_OPERATION); - } + ASSERT(mState.getCurrentProgramId() != 0); + + ProgramBinary *programBinary = mState.getCurrentProgramBinary(); + programBinary->updateSamplerMapping(); + + Texture *vsTextures[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + TextureType vsTextureTypes[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + SamplerState vsSamplers[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + size_t vsTextureCount = getCurrentTexturesAndSamplerStates(programBinary, SAMPLER_VERTEX, vsTextures, vsTextureTypes, vsSamplers); + + Texture *psTextures[MAX_TEXTURE_IMAGE_UNITS]; + TextureType psTextureTypes[MAX_TEXTURE_IMAGE_UNITS]; + SamplerState psSamplers[MAX_TEXTURE_IMAGE_UNITS]; + size_t psTextureCount = getCurrentTexturesAndSamplerStates(programBinary, SAMPLER_PIXEL, psTextures, psTextureTypes, psSamplers); + + generateSwizzles(vsTextures, vsTextureCount); + generateSwizzles(psTextures, psTextureCount); - if (!indices && !mState.elementArrayBuffer) - { - return gl::error(GL_INVALID_OPERATION); - } - if (!mRenderer->applyPrimitiveType(mode, count)) { return; @@ -2024,33 +1828,42 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid applyState(mode); + VertexArray *vao = mState.getVertexArray(); rx::TranslatedIndexData indexInfo; - GLenum err = mRenderer->applyIndexBuffer(indices, mState.elementArrayBuffer.get(), count, mode, type, &indexInfo); + GLenum err = mRenderer->applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo); if (err != GL_NO_ERROR) { return gl::error(err); } - ProgramBinary *programBinary = getCurrentProgramBinary(); - GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1; - err = mRenderer->applyVertexBuffer(programBinary, mState.vertexAttribute, indexInfo.minIndex, vertexCount, instances); + err = mRenderer->applyVertexBuffer(programBinary, vao->getVertexAttributes(), mState.getVertexAttribCurrentValues(), indexInfo.minIndex, vertexCount, instances); if (err != GL_NO_ERROR) { return gl::error(err); } - applyShaders(); - applyTextures(); + bool transformFeedbackActive = applyTransformFeedbackBuffers(); + // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation + // layer. + ASSERT(!transformFeedbackActive); + + applyShaders(programBinary, transformFeedbackActive); - if (!programBinary->validateSamplers(NULL)) + FramebufferTextureSerialArray frameBufferSerials; + size_t framebufferSerialCount = getBoundFramebufferTextureSerials(&frameBufferSerials); + + applyTextures(SAMPLER_VERTEX, vsTextures, vsTextureTypes, vsSamplers, vsTextureCount, frameBufferSerials, framebufferSerialCount); + applyTextures(SAMPLER_PIXEL, psTextures, psTextureTypes, psSamplers, psTextureCount, frameBufferSerials, framebufferSerialCount); + + if (!applyUniformBuffers()) { - return gl::error(GL_INVALID_OPERATION); + return; } if (!skipDraw(mode)) { - mRenderer->drawElements(mode, count, type, indices, mState.elementArrayBuffer.get(), indexInfo, instances); + mRenderer->drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances); } } @@ -2147,7 +1960,7 @@ GLenum Context::getResetStatus() mResetStatus = GL_NO_ERROR; } } - + return status; } @@ -2156,244 +1969,129 @@ bool Context::isResetNotificationEnabled() return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); } -int Context::getMajorShaderModel() const -{ - return mMajorShaderModel; -} - -float Context::getMaximumPointSize() const -{ - return mMaximumPointSize; -} - -unsigned int Context::getMaximumCombinedTextureImageUnits() const -{ - return mRenderer->getMaxCombinedTextureImageUnits(); -} - -int Context::getMaxSupportedSamples() const -{ - return mRenderer->getMaxSupportedSamples(); -} - -unsigned int Context::getMaximumRenderTargets() const -{ - return mRenderer->getMaxRenderTargets(); -} - -bool Context::supportsEventQueries() const -{ - return mSupportsEventQueries; -} - -bool Context::supportsOcclusionQueries() const -{ - return mSupportsOcclusionQueries; -} - -bool Context::supportsBGRATextures() const -{ - return mSupportsBGRATextures; -} - -bool Context::supportsDXT1Textures() const -{ - return mSupportsDXT1Textures; -} - -bool Context::supportsDXT3Textures() const -{ - return mSupportsDXT3Textures; -} - -bool Context::supportsDXT5Textures() const -{ - return mSupportsDXT5Textures; -} - -bool Context::supportsFloat32Textures() const -{ - return mSupportsFloat32Textures; -} - -bool Context::supportsFloat32LinearFilter() const -{ - return mSupportsFloat32LinearFilter; -} - -bool Context::supportsFloat32RenderableTextures() const +int Context::getClientVersion() const { - return mSupportsFloat32RenderableTextures; + return mClientVersion; } -bool Context::supportsFloat16Textures() const +const Caps &Context::getCaps() const { - return mSupportsFloat16Textures; + return mCaps; } -bool Context::supportsFloat16LinearFilter() const +const TextureCapsMap &Context::getTextureCaps() const { - return mSupportsFloat16LinearFilter; + return mTextureCaps; } -bool Context::supportsFloat16RenderableTextures() const +const Extensions &Context::getExtensions() const { - return mSupportsFloat16RenderableTextures; + return mExtensions; } -int Context::getMaximumRenderbufferDimension() const +int Context::getMajorShaderModel() const { - return mMaxRenderbufferDimension; + return mMajorShaderModel; } -int Context::getMaximumTextureDimension() const +unsigned int Context::getMaximumCombinedTextureImageUnits() const { - return mMaxTextureDimension; + return mRenderer->getMaxCombinedTextureImageUnits(); } -int Context::getMaximumCubeTextureDimension() const +unsigned int Context::getMaximumCombinedUniformBufferBindings() const { - return mMaxCubeTextureDimension; + return mRenderer->getMaxVertexShaderUniformBuffers() + + mRenderer->getMaxFragmentShaderUniformBuffers(); } -int Context::getMaximumTextureLevel() const +int Context::getMaxSupportedSamples() const { - return mMaxTextureLevel; + return mRenderer->getMaxSupportedSamples(); } -bool Context::supportsLuminanceTextures() const +GLsizei Context::getMaxSupportedFormatSamples(GLenum internalFormat) const { - return mSupportsLuminanceTextures; + return mRenderer->getMaxSupportedFormatSamples(internalFormat); } -bool Context::supportsLuminanceAlphaTextures() const +GLsizei Context::getNumSampleCounts(GLenum internalFormat) const { - return mSupportsLuminanceAlphaTextures; + return mRenderer->getNumSampleCounts(internalFormat); } -bool Context::supportsDepthTextures() const +void Context::getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const { - return mSupportsDepthTextures; + mRenderer->getSampleCounts(internalFormat, bufSize, params); } -bool Context::supports32bitIndices() const +unsigned int Context::getMaxTransformFeedbackBufferBindings() const { - return mSupports32bitIndices; + return mRenderer->getMaxTransformFeedbackBuffers(); } -bool Context::supportsNonPower2Texture() const +GLintptr Context::getUniformBufferOffsetAlignment() const { - return mSupportsNonPower2Texture; + // setting a large alignment forces uniform buffers to bind with zero offset + return static_cast<GLintptr>(std::numeric_limits<GLint>::max()); } -bool Context::supportsInstancing() const +void Context::getCurrentReadFormatType(GLenum *internalFormat, GLenum *format, GLenum *type) { - return mSupportsInstancing; -} + Framebuffer *framebuffer = mState.getReadFramebuffer(); + ASSERT(framebuffer && framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE); -bool Context::supportsTextureFilterAnisotropy() const -{ - return mSupportsTextureFilterAnisotropy; -} + FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); + ASSERT(attachment); -float Context::getTextureMaxAnisotropy() const -{ - return mMaxTextureAnisotropy; + *internalFormat = attachment->getActualFormat(); + *format = gl::GetFormat(attachment->getActualFormat()); + *type = gl::GetType(attachment->getActualFormat()); } -bool Context::getCurrentReadFormatType(GLenum *format, GLenum *type) +void Context::detachTexture(GLuint texture) { - Framebuffer *framebuffer = getReadFramebuffer(); - if (!framebuffer || framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) - { - return gl::error(GL_INVALID_OPERATION, false); - } - - Renderbuffer *renderbuffer = framebuffer->getReadColorbuffer(); - if (!renderbuffer) - { - return gl::error(GL_INVALID_OPERATION, false); - } - - *format = gl::ExtractFormat(renderbuffer->getActualFormat()); - *type = gl::ExtractType(renderbuffer->getActualFormat()); - - return true; + // Simple pass-through to State's detachTexture method, as textures do not require + // allocation map management either here or in the resource manager at detach time. + // Zero textures are held by the Context, and we don't attempt to request them from + // the State. + mState.detachTexture(texture); } void Context::detachBuffer(GLuint buffer) { + // Buffer detachment is handled by Context, because the buffer must also be + // attached from any VAOs in existence, and Context holds the VAO map. + // [OpenGL ES 2.0.24] section 2.9 page 22: // If a buffer object is deleted while it is bound, all bindings to that object in the current context // (i.e. in the thread that called Delete-Buffers) are reset to zero. - if (mState.arrayBuffer.id() == buffer) - { - mState.arrayBuffer.set(NULL); - } - - if (mState.elementArrayBuffer.id() == buffer) - { - mState.elementArrayBuffer.set(NULL); - } - - for (int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++) - { - if (mState.vertexAttribute[attribute].mBoundBuffer.id() == buffer) - { - mState.vertexAttribute[attribute].mBoundBuffer.set(NULL); - } - } -} - -void Context::detachTexture(GLuint texture) -{ - // [OpenGL ES 2.0.24] section 3.8 page 84: - // If a texture object is deleted, it is as if all texture units which are bound to that texture object are - // rebound to texture object zero - - for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) - { - for (int sampler = 0; sampler < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; sampler++) - { - if (mState.samplerTexture[type][sampler].id() == texture) - { - mState.samplerTexture[type][sampler].set(NULL); - } - } - } - - // [OpenGL ES 2.0.24] section 4.4 page 112: - // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is - // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this - // image was attached in the currently bound framebuffer. + mState.removeArrayBufferBinding(buffer); - Framebuffer *readFramebuffer = getReadFramebuffer(); - Framebuffer *drawFramebuffer = getDrawFramebuffer(); - - if (readFramebuffer) - { - readFramebuffer->detachTexture(texture); - } - - if (drawFramebuffer && drawFramebuffer != readFramebuffer) + // mark as freed among the vertex array objects + for (auto vaoIt = mVertexArrayMap.begin(); vaoIt != mVertexArrayMap.end(); vaoIt++) { - drawFramebuffer->detachTexture(texture); + vaoIt->second->detachBuffer(buffer); } } void Context::detachFramebuffer(GLuint framebuffer) { + // Framebuffer detachment is handled by Context, because 0 is a valid + // Framebuffer object, and a pointer to it must be passed from Context + // to State at binding time. + // [OpenGL ES 2.0.24] section 4.4 page 107: // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero. - if (mState.readFramebuffer == framebuffer) + if (mState.removeReadFramebufferBinding(framebuffer)) { bindReadFramebuffer(0); } - if (mState.drawFramebuffer == framebuffer) + if (mState.removeDrawFramebufferBinding(framebuffer)) { bindDrawFramebuffer(0); } @@ -2401,32 +2099,32 @@ void Context::detachFramebuffer(GLuint framebuffer) void Context::detachRenderbuffer(GLuint renderbuffer) { - // [OpenGL ES 2.0.24] section 4.4 page 109: - // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer - // had been executed with the target RENDERBUFFER and name of zero. - - if (mState.renderbuffer.id() == renderbuffer) - { - bindRenderbuffer(0); - } - - // [OpenGL ES 2.0.24] section 4.4 page 111: - // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer, - // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment - // point to which this image was attached in the currently bound framebuffer. + mState.detachRenderbuffer(renderbuffer); +} - Framebuffer *readFramebuffer = getReadFramebuffer(); - Framebuffer *drawFramebuffer = getDrawFramebuffer(); +void Context::detachVertexArray(GLuint vertexArray) +{ + // Vertex array detachment is handled by Context, because 0 is a valid + // VAO, and a pointer to it must be passed from Context to State at + // binding time. - if (readFramebuffer) + // [OpenGL ES 3.0.2] section 2.10 page 43: + // If a vertex array object that is currently bound is deleted, the binding + // for that object reverts to zero and the default vertex array becomes current. + if (mState.removeVertexArrayBinding(vertexArray)) { - readFramebuffer->detachRenderbuffer(renderbuffer); + bindVertexArray(0); } +} - if (drawFramebuffer && drawFramebuffer != readFramebuffer) - { - drawFramebuffer->detachRenderbuffer(renderbuffer); - } +void Context::detachTransformFeedback(GLuint transformFeedback) +{ + mState.detachTransformFeedback(transformFeedback); +} + +void Context::detachSampler(GLuint sampler) +{ + mState.detachSampler(sampler); } Texture *Context::getIncompleteTexture(TextureType type) @@ -2435,7 +2133,8 @@ Texture *Context::getIncompleteTexture(TextureType type) if (t == NULL) { - static const GLubyte color[] = { 0, 0, 0, 255 }; + const GLubyte color[] = { 0, 0, 0, 255 }; + const PixelUnpackState incompleteUnpackState(1); switch (type) { @@ -2445,26 +2144,44 @@ Texture *Context::getIncompleteTexture(TextureType type) case TEXTURE_2D: { - Texture2D *incomplete2d = new Texture2D(mRenderer, Texture::INCOMPLETE_TEXTURE_ID); - incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + Texture2D *incomplete2d = new Texture2D(mRenderer->createTexture2D(), Texture::INCOMPLETE_TEXTURE_ID); + incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); t = incomplete2d; } break; case TEXTURE_CUBE: { - TextureCubeMap *incompleteCube = new TextureCubeMap(mRenderer, Texture::INCOMPLETE_TEXTURE_ID); + TextureCubeMap *incompleteCube = new TextureCubeMap(mRenderer->createTextureCube(), Texture::INCOMPLETE_TEXTURE_ID); - incompleteCube->setImagePosX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImageNegX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImagePosY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImageNegY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImagePosZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); - incompleteCube->setImageNegZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImagePosX(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImageNegX(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImagePosY(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImageNegY(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImagePosZ(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImageNegZ(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); t = incompleteCube; } break; + + case TEXTURE_3D: + { + Texture3D *incomplete3d = new Texture3D(mRenderer->createTexture3D(), Texture::INCOMPLETE_TEXTURE_ID); + incomplete3d->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + + t = incomplete3d; + } + break; + + case TEXTURE_2D_ARRAY: + { + Texture2DArray *incomplete2darray = new Texture2DArray(mRenderer->createTexture2DArray(), Texture::INCOMPLETE_TEXTURE_ID); + incomplete2darray->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + + t = incomplete2darray; + } + break; } mIncompleteTextures[type].set(t); @@ -2480,9 +2197,9 @@ bool Context::skipDraw(GLenum drawMode) // ProgramBinary assumes non-point rendering if gl_PointSize isn't written, // which affects varying interpolation. Since the value of gl_PointSize is // undefined when not written, just skip drawing to avoid unexpected results. - if (!getCurrentProgramBinary()->usesPointSize()) + if (!mState.getCurrentProgramBinary()->usesPointSize()) { - // This is stictly speaking not an error, but developers should be + // This is stictly speaking not an error, but developers should be // notified of risking undefined behavior. ERR("Point rendering without writing to gl_PointSize."); @@ -2491,7 +2208,7 @@ bool Context::skipDraw(GLenum drawMode) } else if (IsTriangleMode(drawMode)) { - if (mState.rasterizer.cullFace && mState.rasterizer.cullMode == GL_FRONT_AND_BACK) + if (mState.getRasterizerState().cullFace && mState.getRasterizerState().cullMode == GL_FRONT_AND_BACK) { return true; } @@ -2500,148 +2217,97 @@ bool Context::skipDraw(GLenum drawMode) return false; } -void Context::setVertexAttrib(GLuint index, const GLfloat *values) -{ - ASSERT(index < gl::MAX_VERTEX_ATTRIBS); - - mState.vertexAttribute[index].mCurrentValue[0] = values[0]; - mState.vertexAttribute[index].mCurrentValue[1] = values[1]; - mState.vertexAttribute[index].mCurrentValue[2] = values[2]; - mState.vertexAttribute[index].mCurrentValue[3] = values[3]; -} - void Context::setVertexAttribDivisor(GLuint index, GLuint divisor) { - ASSERT(index < gl::MAX_VERTEX_ATTRIBS); - - mState.vertexAttribute[index].mDivisor = divisor; + mState.getVertexArray()->setVertexAttribDivisor(index, divisor); } -// keep list sorted in following order -// OES extensions -// EXT extensions -// Vendor extensions -void Context::initExtensionString() +void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param) { - std::string extensionString = ""; - - // OES extensions - if (supports32bitIndices()) - { - extensionString += "GL_OES_element_index_uint "; - } - - extensionString += "GL_OES_packed_depth_stencil "; - extensionString += "GL_OES_get_program_binary "; - extensionString += "GL_OES_rgb8_rgba8 "; - if (mRenderer->getDerivativeInstructionSupport()) - { - extensionString += "GL_OES_standard_derivatives "; - } - - if (supportsFloat16Textures()) - { - extensionString += "GL_OES_texture_half_float "; - } - if (supportsFloat16LinearFilter()) - { - extensionString += "GL_OES_texture_half_float_linear "; - } - if (supportsFloat32Textures()) - { - extensionString += "GL_OES_texture_float "; - } - if (supportsFloat32LinearFilter()) - { - extensionString += "GL_OES_texture_float_linear "; - } + mResourceManager->checkSamplerAllocation(sampler); - if (supportsNonPower2Texture()) - { - extensionString += "GL_OES_texture_npot "; - } - - // Multi-vendor (EXT) extensions - if (supportsOcclusionQueries()) - { - extensionString += "GL_EXT_occlusion_query_boolean "; - } - - extensionString += "GL_EXT_read_format_bgra "; - extensionString += "GL_EXT_robustness "; - - if (supportsDXT1Textures()) - { - extensionString += "GL_EXT_texture_compression_dxt1 "; - } - - if (supportsTextureFilterAnisotropy()) - { - extensionString += "GL_EXT_texture_filter_anisotropic "; - } + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); - if (supportsBGRATextures()) - { - extensionString += "GL_EXT_texture_format_BGRA8888 "; - } - - if (mRenderer->getMaxRenderTargets() > 1) + switch (pname) { - extensionString += "GL_EXT_draw_buffers "; + case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(static_cast<GLenum>(param)); break; + case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(static_cast<GLenum>(param)); break; + case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(static_cast<GLenum>(param)); break; + case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(static_cast<GLenum>(param)); break; + case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(static_cast<GLenum>(param)); break; + case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(static_cast<GLfloat>(param)); break; + case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(static_cast<GLfloat>(param)); break; + case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(static_cast<GLenum>(param)); break; + case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(static_cast<GLenum>(param)); break; + default: UNREACHABLE(); break; } +} - extensionString += "GL_EXT_texture_storage "; - extensionString += "GL_EXT_frag_depth "; +void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param) +{ + mResourceManager->checkSamplerAllocation(sampler); - // ANGLE-specific extensions - if (supportsDepthTextures()) - { - extensionString += "GL_ANGLE_depth_texture "; - } + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); - extensionString += "GL_ANGLE_framebuffer_blit "; - if (getMaxSupportedSamples() != 0) + switch (pname) { - extensionString += "GL_ANGLE_framebuffer_multisample "; + case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(uiround<GLenum>(param)); break; + case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(uiround<GLenum>(param)); break; + case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(uiround<GLenum>(param)); break; + case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(uiround<GLenum>(param)); break; + case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(uiround<GLenum>(param)); break; + case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(param); break; + case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(param); break; + case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(uiround<GLenum>(param)); break; + case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(uiround<GLenum>(param)); break; + default: UNREACHABLE(); break; } +} - if (supportsInstancing()) - { - extensionString += "GL_ANGLE_instanced_arrays "; - } +GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname) +{ + mResourceManager->checkSamplerAllocation(sampler); - extensionString += "GL_ANGLE_pack_reverse_row_order "; + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); - if (supportsDXT3Textures()) - { - extensionString += "GL_ANGLE_texture_compression_dxt3 "; - } - if (supportsDXT5Textures()) + switch (pname) { - extensionString += "GL_ANGLE_texture_compression_dxt5 "; + case GL_TEXTURE_MIN_FILTER: return static_cast<GLint>(samplerObject->getMinFilter()); + case GL_TEXTURE_MAG_FILTER: return static_cast<GLint>(samplerObject->getMagFilter()); + case GL_TEXTURE_WRAP_S: return static_cast<GLint>(samplerObject->getWrapS()); + case GL_TEXTURE_WRAP_T: return static_cast<GLint>(samplerObject->getWrapT()); + case GL_TEXTURE_WRAP_R: return static_cast<GLint>(samplerObject->getWrapR()); + case GL_TEXTURE_MIN_LOD: return uiround<GLint>(samplerObject->getMinLod()); + case GL_TEXTURE_MAX_LOD: return uiround<GLint>(samplerObject->getMaxLod()); + case GL_TEXTURE_COMPARE_MODE: return static_cast<GLint>(samplerObject->getComparisonMode()); + case GL_TEXTURE_COMPARE_FUNC: return static_cast<GLint>(samplerObject->getComparisonFunc()); + default: UNREACHABLE(); return 0; } +} - extensionString += "GL_ANGLE_texture_usage "; - extensionString += "GL_ANGLE_translated_shader_source "; +GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname) +{ + mResourceManager->checkSamplerAllocation(sampler); - // Other vendor-specific extensions - if (supportsEventQueries()) - { - extensionString += "GL_NV_fence "; - } + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); - std::string::size_type end = extensionString.find_last_not_of(' '); - if (end != std::string::npos) + switch (pname) { - extensionString.resize(end+1); + case GL_TEXTURE_MIN_FILTER: return static_cast<GLfloat>(samplerObject->getMinFilter()); + case GL_TEXTURE_MAG_FILTER: return static_cast<GLfloat>(samplerObject->getMagFilter()); + case GL_TEXTURE_WRAP_S: return static_cast<GLfloat>(samplerObject->getWrapS()); + case GL_TEXTURE_WRAP_T: return static_cast<GLfloat>(samplerObject->getWrapT()); + case GL_TEXTURE_WRAP_R: return static_cast<GLfloat>(samplerObject->getWrapR()); + case GL_TEXTURE_MIN_LOD: return samplerObject->getMinLod(); + case GL_TEXTURE_MAX_LOD: return samplerObject->getMaxLod(); + case GL_TEXTURE_COMPARE_MODE: return static_cast<GLfloat>(samplerObject->getComparisonMode()); + case GL_TEXTURE_COMPARE_FUNC: return static_cast<GLfloat>(samplerObject->getComparisonFunc()); + default: UNREACHABLE(); return 0; } - - mExtensionString = makeStaticString(extensionString); -} - -const char *Context::getExtensionString() const -{ - return mExtensionString; } void Context::initRendererString() @@ -2651,319 +2317,226 @@ void Context::initRendererString() rendererString << mRenderer->getRendererDescription(); rendererString << ")"; - mRendererString = makeStaticString(rendererString.str()); + mRendererString = MakeStaticString(rendererString.str()); } -const char *Context::getRendererString() const +const std::string &Context::getRendererString() const { return mRendererString; } -Context::FramebufferTextureSerialSet Context::getBoundFramebufferTextureSerials() +void Context::initExtensionStrings() { - FramebufferTextureSerialSet set; - - Framebuffer *drawFramebuffer = getDrawFramebuffer(); - for (unsigned int i = 0; i < IMPLEMENTATION_MAX_DRAW_BUFFERS; i++) - { - Renderbuffer *renderBuffer = drawFramebuffer->getColorbuffer(i); - if (renderBuffer && renderBuffer->getTextureSerial() != 0) - { - set.insert(renderBuffer->getTextureSerial()); - } - } + mExtensionStrings = mExtensions.getStrings(); - Renderbuffer *depthStencilBuffer = drawFramebuffer->getDepthOrStencilbuffer(); - if (depthStencilBuffer && depthStencilBuffer->getTextureSerial() != 0) - { - set.insert(depthStencilBuffer->getTextureSerial()); - } - - return set; + std::ostringstream combinedStringStream; + std::copy(mExtensionStrings.begin(), mExtensionStrings.end(), std::ostream_iterator<std::string>(combinedStringStream, " ")); + mExtensionString = combinedStringStream.str(); } -void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask) +const std::string &Context::getExtensionString() const { - Framebuffer *readFramebuffer = getReadFramebuffer(); - Framebuffer *drawFramebuffer = getDrawFramebuffer(); - - if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE || - !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) - { - return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION); - } - - if (drawFramebuffer->getSamples() != 0) - { - return gl::error(GL_INVALID_OPERATION); - } - - Renderbuffer *readColorBuffer = readFramebuffer->getReadColorbuffer(); - Renderbuffer *drawColorBuffer = drawFramebuffer->getFirstColorbuffer(); - - if (drawColorBuffer == NULL) - { - ERR("Draw buffers formats don't match, which is not supported in this implementation of BlitFramebufferANGLE"); - return gl::error(GL_INVALID_OPERATION); - } - - int readBufferWidth = readColorBuffer->getWidth(); - int readBufferHeight = readColorBuffer->getHeight(); - int drawBufferWidth = drawColorBuffer->getWidth(); - int drawBufferHeight = drawColorBuffer->getHeight(); - - Rectangle sourceRect; - Rectangle destRect; + return mExtensionString; +} - if (srcX0 < srcX1) - { - sourceRect.x = srcX0; - destRect.x = dstX0; - sourceRect.width = srcX1 - srcX0; - destRect.width = dstX1 - dstX0; - } - else - { - sourceRect.x = srcX1; - destRect.x = dstX1; - sourceRect.width = srcX0 - srcX1; - destRect.width = dstX0 - dstX1; - } +const std::string &Context::getExtensionString(size_t idx) const +{ + return mExtensionStrings[idx]; +} - if (srcY0 < srcY1) - { - sourceRect.height = srcY1 - srcY0; - destRect.height = dstY1 - dstY0; - sourceRect.y = srcY0; - destRect.y = dstY0; - } - else - { - sourceRect.height = srcY0 - srcY1; - destRect.height = dstY0 - srcY1; - sourceRect.y = srcY1; - destRect.y = dstY1; - } +size_t Context::getExtensionStringCount() const +{ + return mExtensionStrings.size(); +} - Rectangle sourceScissoredRect = sourceRect; - Rectangle destScissoredRect = destRect; +size_t Context::getBoundFramebufferTextureSerials(FramebufferTextureSerialArray *outSerialArray) +{ + size_t serialCount = 0; - if (mState.scissorTest) + Framebuffer *drawFramebuffer = mState.getDrawFramebuffer(); + for (unsigned int i = 0; i < IMPLEMENTATION_MAX_DRAW_BUFFERS; i++) { - // Only write to parts of the destination framebuffer which pass the scissor test. - if (destRect.x < mState.scissor.x) - { - int xDiff = mState.scissor.x - destRect.x; - destScissoredRect.x = mState.scissor.x; - destScissoredRect.width -= xDiff; - sourceScissoredRect.x += xDiff; - sourceScissoredRect.width -= xDiff; - - } - - if (destRect.x + destRect.width > mState.scissor.x + mState.scissor.width) - { - int xDiff = (destRect.x + destRect.width) - (mState.scissor.x + mState.scissor.width); - destScissoredRect.width -= xDiff; - sourceScissoredRect.width -= xDiff; - } - - if (destRect.y < mState.scissor.y) + FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i); + if (attachment && attachment->isTexture()) { - int yDiff = mState.scissor.y - destRect.y; - destScissoredRect.y = mState.scissor.y; - destScissoredRect.height -= yDiff; - sourceScissoredRect.y += yDiff; - sourceScissoredRect.height -= yDiff; - } - - if (destRect.y + destRect.height > mState.scissor.y + mState.scissor.height) - { - int yDiff = (destRect.y + destRect.height) - (mState.scissor.y + mState.scissor.height); - destScissoredRect.height -= yDiff; - sourceScissoredRect.height -= yDiff; + (*outSerialArray)[serialCount++] = attachment->getTextureSerial(); } } - bool blitRenderTarget = false; - bool blitDepthStencil = false; - - Rectangle sourceTrimmedRect = sourceScissoredRect; - Rectangle destTrimmedRect = destScissoredRect; - - // The source & destination rectangles also may need to be trimmed if they fall out of the bounds of - // the actual draw and read surfaces. - if (sourceTrimmedRect.x < 0) + FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer(); + if (depthStencilAttachment && depthStencilAttachment->isTexture()) { - int xDiff = 0 - sourceTrimmedRect.x; - sourceTrimmedRect.x = 0; - sourceTrimmedRect.width -= xDiff; - destTrimmedRect.x += xDiff; - destTrimmedRect.width -= xDiff; + (*outSerialArray)[serialCount++] = depthStencilAttachment->getTextureSerial(); } - if (sourceTrimmedRect.x + sourceTrimmedRect.width > readBufferWidth) - { - int xDiff = (sourceTrimmedRect.x + sourceTrimmedRect.width) - readBufferWidth; - sourceTrimmedRect.width -= xDiff; - destTrimmedRect.width -= xDiff; - } + std::sort(outSerialArray->begin(), outSerialArray->begin() + serialCount); - if (sourceTrimmedRect.y < 0) - { - int yDiff = 0 - sourceTrimmedRect.y; - sourceTrimmedRect.y = 0; - sourceTrimmedRect.height -= yDiff; - destTrimmedRect.y += yDiff; - destTrimmedRect.height -= yDiff; - } + return serialCount; +} - if (sourceTrimmedRect.y + sourceTrimmedRect.height > readBufferHeight) - { - int yDiff = (sourceTrimmedRect.y + sourceTrimmedRect.height) - readBufferHeight; - sourceTrimmedRect.height -= yDiff; - destTrimmedRect.height -= yDiff; - } +void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + Framebuffer *readFramebuffer = mState.getReadFramebuffer(); + Framebuffer *drawFramebuffer = mState.getDrawFramebuffer(); - if (destTrimmedRect.x < 0) + bool blitRenderTarget = false; + bool blitDepth = false; + bool blitStencil = false; + if ((mask & GL_COLOR_BUFFER_BIT) && readFramebuffer->getReadColorbuffer() && drawFramebuffer->getFirstColorbuffer()) { - int xDiff = 0 - destTrimmedRect.x; - destTrimmedRect.x = 0; - destTrimmedRect.width -= xDiff; - sourceTrimmedRect.x += xDiff; - sourceTrimmedRect.width -= xDiff; + blitRenderTarget = true; } - - if (destTrimmedRect.x + destTrimmedRect.width > drawBufferWidth) + if ((mask & GL_STENCIL_BUFFER_BIT) && readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer()) { - int xDiff = (destTrimmedRect.x + destTrimmedRect.width) - drawBufferWidth; - destTrimmedRect.width -= xDiff; - sourceTrimmedRect.width -= xDiff; + blitStencil = true; } - - if (destTrimmedRect.y < 0) + if ((mask & GL_DEPTH_BUFFER_BIT) && readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer()) { - int yDiff = 0 - destTrimmedRect.y; - destTrimmedRect.y = 0; - destTrimmedRect.height -= yDiff; - sourceTrimmedRect.y += yDiff; - sourceTrimmedRect.height -= yDiff; + blitDepth = true; } - if (destTrimmedRect.y + destTrimmedRect.height > drawBufferHeight) + gl::Rectangle srcRect(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0); + gl::Rectangle dstRect(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0); + if (blitRenderTarget || blitDepth || blitStencil) { - int yDiff = (destTrimmedRect.y + destTrimmedRect.height) - drawBufferHeight; - destTrimmedRect.height -= yDiff; - sourceTrimmedRect.height -= yDiff; + const gl::Rectangle *scissor = mState.isScissorTestEnabled() ? &mState.getScissor() : NULL; + mRenderer->blitRect(readFramebuffer, srcRect, drawFramebuffer, dstRect, scissor, + blitRenderTarget, blitDepth, blitStencil, filter); } +} - bool partialBufferCopy = false; - if (sourceTrimmedRect.height < readBufferHeight || - sourceTrimmedRect.width < readBufferWidth || - destTrimmedRect.height < drawBufferHeight || - destTrimmedRect.width < drawBufferWidth || - sourceTrimmedRect.y != 0 || destTrimmedRect.y != 0 || sourceTrimmedRect.x != 0 || destTrimmedRect.x != 0) +void Context::invalidateFrameBuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, + GLint x, GLint y, GLsizei width, GLsizei height) +{ + Framebuffer *frameBuffer = NULL; + switch (target) { - partialBufferCopy = true; + case GL_FRAMEBUFFER: + case GL_DRAW_FRAMEBUFFER: + frameBuffer = mState.getDrawFramebuffer(); + break; + case GL_READ_FRAMEBUFFER: + frameBuffer = mState.getReadFramebuffer(); + break; + default: + UNREACHABLE(); } - if (mask & GL_COLOR_BUFFER_BIT) + if (frameBuffer && frameBuffer->completeness() == GL_FRAMEBUFFER_COMPLETE) { - const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType(); - const bool validReadType = (readColorbufferType == GL_TEXTURE_2D) || (readColorbufferType == GL_RENDERBUFFER); - bool validDrawType = true; - bool validDrawFormat = true; - - for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) + for (int i = 0; i < numAttachments; ++i) { - if (drawFramebuffer->isEnabledColorAttachment(colorAttachment)) + rx::RenderTarget *renderTarget = NULL; + + if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) + { + gl::FramebufferAttachment *attachment = frameBuffer->getColorbuffer(attachments[i] - GL_COLOR_ATTACHMENT0); + if (attachment) + { + renderTarget = attachment->getRenderTarget(); + } + } + else if (attachments[i] == GL_COLOR) + { + gl::FramebufferAttachment *attachment = frameBuffer->getColorbuffer(0); + if (attachment) + { + renderTarget = attachment->getRenderTarget(); + } + } + else { - if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D && - drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER) + gl::FramebufferAttachment *attachment = NULL; + switch (attachments[i]) { - validDrawType = false; + case GL_DEPTH_ATTACHMENT: + case GL_DEPTH: + attachment = frameBuffer->getDepthbuffer(); + break; + case GL_STENCIL_ATTACHMENT: + case GL_STENCIL: + attachment = frameBuffer->getStencilbuffer(); + break; + case GL_DEPTH_STENCIL_ATTACHMENT: + attachment = frameBuffer->getDepthOrStencilbuffer(); + break; + default: + UNREACHABLE(); } - if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat()) + if (attachment) { - validDrawFormat = false; + renderTarget = attachment->getDepthStencil(); } } - } - if (!validReadType || !validDrawType || !validDrawFormat) - { - ERR("Color buffer format conversion in BlitFramebufferANGLE not supported by this implementation"); - return gl::error(GL_INVALID_OPERATION); - } - - if (partialBufferCopy && readFramebuffer->getSamples() != 0) - { - return gl::error(GL_INVALID_OPERATION); + if (renderTarget) + { + renderTarget->invalidate(x, y, width, height); + } } - - blitRenderTarget = true; - } +} - if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) +bool Context::hasMappedBuffer(GLenum target) const +{ + if (target == GL_ARRAY_BUFFER) { - Renderbuffer *readDSBuffer = NULL; - Renderbuffer *drawDSBuffer = NULL; - - // We support OES_packed_depth_stencil, and do not support a separately attached depth and stencil buffer, so if we have - // both a depth and stencil buffer, it will be the same buffer. - - if (mask & GL_DEPTH_BUFFER_BIT) + for (unsigned int attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; attribIndex++) { - if (readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer()) + const gl::VertexAttribute &vertexAttrib = mState.getVertexAttribState(attribIndex); + gl::Buffer *boundBuffer = vertexAttrib.buffer.get(); + if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped()) { - if (readFramebuffer->getDepthbufferType() != drawFramebuffer->getDepthbufferType() || - readFramebuffer->getDepthbuffer()->getActualFormat() != drawFramebuffer->getDepthbuffer()->getActualFormat()) - { - return gl::error(GL_INVALID_OPERATION); - } - - blitDepthStencil = true; - readDSBuffer = readFramebuffer->getDepthbuffer(); - drawDSBuffer = drawFramebuffer->getDepthbuffer(); + return true; } } + } + else if (target == GL_ELEMENT_ARRAY_BUFFER) + { + Buffer *elementBuffer = mState.getTargetBuffer(target); + return (elementBuffer && elementBuffer->isMapped()); + } + else if (target == GL_TRANSFORM_FEEDBACK_BUFFER) + { + UNIMPLEMENTED(); + } + else UNREACHABLE(); + return false; +} - if (mask & GL_STENCIL_BUFFER_BIT) - { - if (readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer()) - { - if (readFramebuffer->getStencilbufferType() != drawFramebuffer->getStencilbufferType() || - readFramebuffer->getStencilbuffer()->getActualFormat() != drawFramebuffer->getStencilbuffer()->getActualFormat()) - { - return gl::error(GL_INVALID_OPERATION); - } +void Context::initCaps(GLuint clientVersion) +{ + mCaps = mRenderer->getRendererCaps(); - blitDepthStencil = true; - readDSBuffer = readFramebuffer->getStencilbuffer(); - drawDSBuffer = drawFramebuffer->getStencilbuffer(); - } - } + mExtensions = mRenderer->getRendererExtensions(); - if (partialBufferCopy) - { - ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); - return gl::error(GL_INVALID_OPERATION); // only whole-buffer copies are permitted - } + if (clientVersion < 3) + { + // Disable ES3+ extensions + mExtensions.colorBufferFloat = false; + } - if ((drawDSBuffer && drawDSBuffer->getSamples() != 0) || - (readDSBuffer && readDSBuffer->getSamples() != 0)) - { - return gl::error(GL_INVALID_OPERATION); - } + if (clientVersion > 2) + { + // FIXME(geofflang): Don't support EXT_sRGB in non-ES2 contexts + //mExtensions.sRGB = false; } - if (blitRenderTarget || blitDepthStencil) + const TextureCapsMap &rendererFormats = mRenderer->getRendererTextureCaps(); + for (TextureCapsMap::const_iterator i = rendererFormats.begin(); i != rendererFormats.end(); i++) { - mRenderer->blitRect(readFramebuffer, sourceTrimmedRect, drawFramebuffer, destTrimmedRect, blitRenderTarget, blitDepthStencil); + GLenum format = i->first; + TextureCaps formatCaps = i->second; + + if (formatCaps.texturable && IsValidInternalFormat(format, mExtensions, clientVersion)) + { + // Update the format caps based on the client version and extensions + formatCaps.renderable = IsRenderingSupported(format, mExtensions, clientVersion); + formatCaps.filterable = IsFilteringSupported(format, mExtensions, clientVersion); + mTextureCaps.insert(format, formatCaps); + } } } @@ -2971,9 +2544,9 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 extern "C" { -gl::Context *glCreateContext(const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) +gl::Context *glCreateContext(int clientVersion, const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) { - return new gl::Context(shareContext, renderer, notifyResets, robustAccess); + return new gl::Context(clientVersion, shareContext, renderer, notifyResets, robustAccess); } void glDestroyContext(gl::Context *context) diff --git a/src/3rdparty/angle/src/libGLESv2/Context.h b/src/3rdparty/angle/src/libGLESv2/Context.h index 3dc95e3b95..6c93c74e79 100644 --- a/src/3rdparty/angle/src/libGLESv2/Context.h +++ b/src/3rdparty/angle/src/libGLESv2/Context.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,26 +10,22 @@ #ifndef LIBGLESV2_CONTEXT_H_ #define LIBGLESV2_CONTEXT_H_ -#define GL_APICALL -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#define EGLAPI -#include <EGL/egl.h> +#include "angle_gl.h" #include <string> -#include <map> #include <set> -#ifdef _MSC_VER -#include <hash_map> -#else +#include <map> #include <unordered_map> -#endif +#include <array> #include "common/angleutils.h" #include "common/RefCountObject.h" +#include "libGLESv2/Caps.h" #include "libGLESv2/HandleAllocator.h" #include "libGLESv2/angletypes.h" #include "libGLESv2/Constants.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/State.h" namespace rx { @@ -49,6 +45,8 @@ class ProgramBinary; class Texture; class Texture2D; class TextureCubeMap; +class Texture3D; +class Texture2DArray; class Framebuffer; class Renderbuffer; class RenderbufferStorage; @@ -56,222 +54,28 @@ class Colorbuffer; class Depthbuffer; class Stencilbuffer; class DepthStencilbuffer; -class Fence; +class FenceNV; +class FenceSync; class Query; class ResourceManager; class Buffer; - -enum QueryType -{ - QUERY_ANY_SAMPLES_PASSED, - QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE, - - QUERY_TYPE_COUNT -}; - -// Helper structure describing a single vertex attribute -class VertexAttribute -{ - public: - VertexAttribute() : mType(GL_FLOAT), mSize(4), mNormalized(false), mStride(0), mPointer(NULL), mArrayEnabled(false), mDivisor(0) - { - mCurrentValue[0] = 0.0f; - mCurrentValue[1] = 0.0f; - mCurrentValue[2] = 0.0f; - mCurrentValue[3] = 1.0f; - } - - int typeSize() const - { - switch (mType) - { - case GL_BYTE: return mSize * sizeof(GLbyte); - case GL_UNSIGNED_BYTE: return mSize * sizeof(GLubyte); - case GL_SHORT: return mSize * sizeof(GLshort); - case GL_UNSIGNED_SHORT: return mSize * sizeof(GLushort); - case GL_FIXED: return mSize * sizeof(GLfixed); - case GL_FLOAT: return mSize * sizeof(GLfloat); - default: UNREACHABLE(); return mSize * sizeof(GLfloat); - } - } - - GLsizei stride() const - { - return mStride ? mStride : typeSize(); - } - - // From glVertexAttribPointer - GLenum mType; - GLint mSize; - bool mNormalized; - GLsizei mStride; // 0 means natural stride - - union - { - const void *mPointer; - intptr_t mOffset; - }; - - BindingPointer<Buffer> mBoundBuffer; // Captured when glVertexAttribPointer is called. - - bool mArrayEnabled; // From glEnable/DisableVertexAttribArray - float mCurrentValue[4]; // From glVertexAttrib - unsigned int mDivisor; -}; - -// Helper structure to store all raw state -struct State -{ - Color colorClearValue; - GLclampf depthClearValue; - int stencilClearValue; - - RasterizerState rasterizer; - bool scissorTest; - Rectangle scissor; - - BlendState blend; - Color blendColor; - bool sampleCoverage; - GLclampf sampleCoverageValue; - bool sampleCoverageInvert; - - DepthStencilState depthStencil; - GLint stencilRef; - GLint stencilBackRef; - - GLfloat lineWidth; - - GLenum generateMipmapHint; - GLenum fragmentShaderDerivativeHint; - - Rectangle viewport; - float zNear; - float zFar; - - unsigned int activeSampler; // Active texture unit selector - GL_TEXTURE0 - BindingPointer<Buffer> arrayBuffer; - BindingPointer<Buffer> elementArrayBuffer; - GLuint readFramebuffer; - GLuint drawFramebuffer; - BindingPointer<Renderbuffer> renderbuffer; - GLuint currentProgram; - - VertexAttribute vertexAttribute[MAX_VERTEX_ATTRIBS]; - BindingPointer<Texture> samplerTexture[TEXTURE_TYPE_COUNT][IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS]; - BindingPointer<Query> activeQuery[QUERY_TYPE_COUNT]; - - GLint unpackAlignment; - GLint packAlignment; - bool packReverseRowOrder; -}; +struct VertexAttribute; +class VertexArray; +class Sampler; +class TransformFeedback; class Context { public: - Context(const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess); + Context(int clientVersion, const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess); - ~Context(); + virtual ~Context(); void makeCurrent(egl::Surface *surface); virtual void markContextLost(); bool isContextLost(); - // State manipulation - void setClearColor(float red, float green, float blue, float alpha); - - void setClearDepth(float depth); - - void setClearStencil(int stencil); - - void setCullFace(bool enabled); - bool isCullFaceEnabled() const; - - void setCullMode(GLenum mode); - - void setFrontFace(GLenum front); - - void setDepthTest(bool enabled); - bool isDepthTestEnabled() const; - - void setDepthFunc(GLenum depthFunc); - - void setDepthRange(float zNear, float zFar); - - void setBlend(bool enabled); - bool isBlendEnabled() const; - - void setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha); - void setBlendColor(float red, float green, float blue, float alpha); - void setBlendEquation(GLenum rgbEquation, GLenum alphaEquation); - - void setStencilTest(bool enabled); - bool isStencilTestEnabled() const; - - void setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask); - void setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask); - void setStencilWritemask(GLuint stencilWritemask); - void setStencilBackWritemask(GLuint stencilBackWritemask); - void setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass); - void setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass); - - void setPolygonOffsetFill(bool enabled); - bool isPolygonOffsetFillEnabled() const; - - void setPolygonOffsetParams(GLfloat factor, GLfloat units); - - void setSampleAlphaToCoverage(bool enabled); - bool isSampleAlphaToCoverageEnabled() const; - - void setSampleCoverage(bool enabled); - bool isSampleCoverageEnabled() const; - - void setSampleCoverageParams(GLclampf value, bool invert); - - void setScissorTest(bool enabled); - bool isScissorTestEnabled() const; - - void setDither(bool enabled); - bool isDitherEnabled() const; - - void setLineWidth(GLfloat width); - - void setGenerateMipmapHint(GLenum hint); - void setFragmentShaderDerivativeHint(GLenum hint); - - void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height); - - void setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height); - - void setColorMask(bool red, bool green, bool blue, bool alpha); - void setDepthMask(bool mask); - - void setActiveSampler(unsigned int active); - - GLuint getReadFramebufferHandle() const; - GLuint getDrawFramebufferHandle() const; - GLuint getRenderbufferHandle() const; - - GLuint getArrayBufferHandle() const; - - GLuint getActiveQuery(GLenum target) const; - - void setEnableVertexAttribArray(unsigned int attribNum, bool enabled); - const VertexAttribute &getVertexAttribState(unsigned int attribNum); - void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, - bool normalized, GLsizei stride, const void *pointer); - const void *getVertexAttribPointer(unsigned int attribNum) const; - - void setUnpackAlignment(GLint alignment); - GLint getUnpackAlignment() const; - - void setPackAlignment(GLint alignment); - GLint getPackAlignment() const; - - void setPackReverseRowOrder(bool reverseRowOrder); - bool getPackReverseRowOrder() const; - // These create and destroy methods are merely pass-throughs to // ResourceManager, which owns these object types GLuint createBuffer(); @@ -279,35 +83,58 @@ class Context GLuint createProgram(); GLuint createTexture(); GLuint createRenderbuffer(); + GLuint createSampler(); + GLuint createTransformFeedback(); + GLsync createFenceSync(GLenum condition); void deleteBuffer(GLuint buffer); void deleteShader(GLuint shader); void deleteProgram(GLuint program); void deleteTexture(GLuint texture); void deleteRenderbuffer(GLuint renderbuffer); + void deleteSampler(GLuint sampler); + void deleteTransformFeedback(GLuint transformFeedback); + void deleteFenceSync(GLsync fenceSync); // Framebuffers are owned by the Context, so these methods do not pass through GLuint createFramebuffer(); void deleteFramebuffer(GLuint framebuffer); - // Fences are owned by the Context. - GLuint createFence(); - void deleteFence(GLuint fence); + // NV Fences are owned by the Context. + GLuint createFenceNV(); + void deleteFenceNV(GLuint fence); // Queries are owned by the Context; GLuint createQuery(); void deleteQuery(GLuint query); + // Vertex arrays are owned by the Context + GLuint createVertexArray(); + void deleteVertexArray(GLuint vertexArray); + void bindArrayBuffer(GLuint buffer); void bindElementArrayBuffer(GLuint buffer); void bindTexture2D(GLuint texture); void bindTextureCubeMap(GLuint texture); + void bindTexture3D(GLuint texture); + void bindTexture2DArray(GLuint texture); void bindReadFramebuffer(GLuint framebuffer); void bindDrawFramebuffer(GLuint framebuffer); void bindRenderbuffer(GLuint renderbuffer); + void bindVertexArray(GLuint vertexArray); + void bindSampler(GLuint textureUnit, GLuint sampler); + void bindGenericUniformBuffer(GLuint buffer); + void bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); + void bindGenericTransformFeedbackBuffer(GLuint buffer); + void bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); + void bindCopyReadBuffer(GLuint buffer); + void bindCopyWriteBuffer(GLuint buffer); + void bindPixelPackBuffer(GLuint buffer); + void bindPixelUnpackBuffer(GLuint buffer); void useProgram(GLuint program); void linkProgram(GLuint program); void setProgramBinary(GLuint program, const void *binary, GLint length); + void bindTransformFeedback(GLuint transformFeedback); void beginQuery(GLenum target, GLuint query); void endQuery(GLenum target); @@ -316,35 +143,54 @@ class Context void setRenderbufferStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples); - void setVertexAttrib(GLuint index, const GLfloat *values); void setVertexAttribDivisor(GLuint index, GLuint divisor); + void samplerParameteri(GLuint sampler, GLenum pname, GLint param); + void samplerParameterf(GLuint sampler, GLenum pname, GLfloat param); + GLint getSamplerParameteri(GLuint sampler, GLenum pname); + GLfloat getSamplerParameterf(GLuint sampler, GLenum pname); + Buffer *getBuffer(GLuint handle); - Fence *getFence(GLuint handle); - Shader *getShader(GLuint handle); - Program *getProgram(GLuint handle); - Texture *getTexture(GLuint handle); - Framebuffer *getFramebuffer(GLuint handle); + FenceNV *getFenceNV(GLuint handle); + FenceSync *getFenceSync(GLsync handle) const; + Shader *getShader(GLuint handle) const; + Program *getProgram(GLuint handle) const; + Texture *getTexture(GLuint handle) const; + Framebuffer *getFramebuffer(GLuint handle) const; Renderbuffer *getRenderbuffer(GLuint handle); + VertexArray *getVertexArray(GLuint handle) const; + Sampler *getSampler(GLuint handle) const; Query *getQuery(GLuint handle, bool create, GLenum type); + TransformFeedback *getTransformFeedback(GLuint handle) const; + + Texture *getTargetTexture(GLenum target) const; + Texture2D *getTexture2D() const; + TextureCubeMap *getTextureCubeMap() const; + Texture3D *getTexture3D() const; + Texture2DArray *getTexture2DArray() const; + + Texture *getSamplerTexture(unsigned int sampler, TextureType type) const; + + bool isSampler(GLuint samplerName) const; - Buffer *getArrayBuffer(); - Buffer *getElementArrayBuffer(); - ProgramBinary *getCurrentProgramBinary(); - Texture2D *getTexture2D(); - TextureCubeMap *getTextureCubeMap(); - Texture *getSamplerTexture(unsigned int sampler, TextureType type); - Framebuffer *getReadFramebuffer(); - Framebuffer *getDrawFramebuffer(); + void getBooleanv(GLenum pname, GLboolean *params); + void getFloatv(GLenum pname, GLfloat *params); + void getIntegerv(GLenum pname, GLint *params); + void getInteger64v(GLenum pname, GLint64 *params); - bool getFloatv(GLenum pname, GLfloat *params); - bool getIntegerv(GLenum pname, GLint *params); - bool getBooleanv(GLenum pname, GLboolean *params); + bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data); + bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data); bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); + bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams); - void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels); void clear(GLbitfield mask); + void clearBufferfv(GLenum buffer, int drawbuffer, const float *values); + void clearBufferuiv(GLenum buffer, int drawbuffer, const unsigned int *values); + void clearBufferiv(GLenum buffer, int drawbuffer, const int *values); + void clearBufferfi(GLenum buffer, int drawbuffer, float depth, int stencil); + + void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels); void drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances); void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances); void sync(bool block); // flush/finish @@ -359,101 +205,120 @@ class Context GLenum getResetStatus(); virtual bool isResetNotificationEnabled(); + virtual int getClientVersion() const; + + const Caps &getCaps() const; + const TextureCapsMap &getTextureCaps() const; + const Extensions &getExtensions() const; + int getMajorShaderModel() const; - float getMaximumPointSize() const; unsigned int getMaximumCombinedTextureImageUnits() const; - int getMaximumRenderbufferDimension() const; - int getMaximumTextureDimension() const; - int getMaximumCubeTextureDimension() const; - int getMaximumTextureLevel() const; - unsigned int getMaximumRenderTargets() const; + unsigned int getMaximumCombinedUniformBufferBindings() const; GLsizei getMaxSupportedSamples() const; - const char *getExtensionString() const; - const char *getRendererString() const; - bool supportsEventQueries() const; - bool supportsOcclusionQueries() const; - bool supportsBGRATextures() const; - bool supportsDXT1Textures() const; - bool supportsDXT3Textures() const; - bool supportsDXT5Textures() const; - bool supportsFloat32Textures() const; - bool supportsFloat32LinearFilter() const; - bool supportsFloat32RenderableTextures() const; - bool supportsFloat16Textures() const; - bool supportsFloat16LinearFilter() const; - bool supportsFloat16RenderableTextures() const; - bool supportsLuminanceTextures() const; - bool supportsLuminanceAlphaTextures() const; - bool supportsDepthTextures() const; - bool supports32bitIndices() const; - bool supportsNonPower2Texture() const; - bool supportsInstancing() const; - bool supportsTextureFilterAnisotropy() const; - - bool getCurrentReadFormatType(GLenum *format, GLenum *type); - - float getTextureMaxAnisotropy() const; - - void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask); + GLsizei getMaxSupportedFormatSamples(GLenum internalFormat) const; + GLsizei getNumSampleCounts(GLenum internalFormat) const; + void getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const; + unsigned int getMaxTransformFeedbackBufferBindings() const; + GLintptr getUniformBufferOffsetAlignment() const; + const std::string &getRendererString() const; + + const std::string &getExtensionString() const; + const std::string &getExtensionString(size_t idx) const; + size_t getExtensionStringCount() const; + + void getCurrentReadFormatType(GLenum *internalFormat, GLenum *format, GLenum *type); + + void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter); + + void invalidateFrameBuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, + GLint x, GLint y, GLsizei width, GLsizei height); + + bool hasMappedBuffer(GLenum target) const; rx::Renderer *getRenderer() { return mRenderer; } + State &getState() { return mState; } + const State &getState() const { return mState; } + private: DISALLOW_COPY_AND_ASSIGN(Context); + // TODO: std::array may become unavailable using older versions of GCC + typedef std::array<unsigned int, IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS> FramebufferTextureSerialArray; + bool applyRenderTarget(GLenum drawMode, bool ignoreViewport); void applyState(GLenum drawMode); - void applyShaders(); - void applyTextures(); - void applyTextures(SamplerType type); + void applyShaders(ProgramBinary *programBinary, bool transformFeedbackActive); + void applyTextures(SamplerType shaderType, Texture *textures[], TextureType *textureTypes, SamplerState *samplers, + size_t textureCount, const FramebufferTextureSerialArray& framebufferSerials, + size_t framebufferSerialCount); + bool applyUniformBuffers(); + bool applyTransformFeedbackBuffers(); + void markTransformFeedbackUsage(); void detachBuffer(GLuint buffer); void detachTexture(GLuint texture); void detachFramebuffer(GLuint framebuffer); void detachRenderbuffer(GLuint renderbuffer); + void detachVertexArray(GLuint vertexArray); + void detachTransformFeedback(GLuint transformFeedback); + void detachSampler(GLuint sampler); + void generateSwizzles(Texture *textures[], size_t count); + size_t getCurrentTexturesAndSamplerStates(ProgramBinary *programBinary, SamplerType type, Texture **outTextures, + TextureType *outTextureTypes, SamplerState *outSamplers); Texture *getIncompleteTexture(TextureType type); bool skipDraw(GLenum drawMode); - void initExtensionString(); void initRendererString(); + void initExtensionStrings(); - typedef std::set<unsigned> FramebufferTextureSerialSet; - FramebufferTextureSerialSet getBoundFramebufferTextureSerials(); + size_t getBoundFramebufferTextureSerials(FramebufferTextureSerialArray *outSerialArray); - rx::Renderer *const mRenderer; + void initCaps(GLuint clientVersion); + // Caps to use for validation + Caps mCaps; + TextureCapsMap mTextureCaps; + Extensions mExtensions; + + rx::Renderer *const mRenderer; State mState; + int mClientVersion; + BindingPointer<Texture2D> mTexture2DZero; BindingPointer<TextureCubeMap> mTextureCubeMapZero; + BindingPointer<Texture3D> mTexture3DZero; + BindingPointer<Texture2DArray> mTexture2DArrayZero; -#ifndef HASH_MAP -# ifdef _MSC_VER -# define HASH_MAP stdext::hash_map -# else -# define HASH_MAP std::unordered_map -# endif -#endif - - typedef HASH_MAP<GLuint, Framebuffer*> FramebufferMap; + typedef std::unordered_map<GLuint, Framebuffer*> FramebufferMap; FramebufferMap mFramebufferMap; HandleAllocator mFramebufferHandleAllocator; - typedef HASH_MAP<GLuint, Fence*> FenceMap; - FenceMap mFenceMap; - HandleAllocator mFenceHandleAllocator; + typedef std::unordered_map<GLuint, FenceNV*> FenceNVMap; + FenceNVMap mFenceNVMap; + HandleAllocator mFenceNVHandleAllocator; - typedef HASH_MAP<GLuint, Query*> QueryMap; + typedef std::unordered_map<GLuint, Query*> QueryMap; QueryMap mQueryMap; HandleAllocator mQueryHandleAllocator; - const char *mExtensionString; - const char *mRendererString; - + typedef std::unordered_map<GLuint, VertexArray*> VertexArrayMap; + VertexArrayMap mVertexArrayMap; + HandleAllocator mVertexArrayHandleAllocator; + + BindingPointer<TransformFeedback> mTransformFeedbackZero; + typedef std::unordered_map<GLuint, TransformFeedback*> TransformFeedbackMap; + TransformFeedbackMap mTransformFeedbackMap; + HandleAllocator mTransformFeedbackAllocator; + + std::string mRendererString; + std::string mExtensionString; + std::vector<std::string> mExtensionStrings; + BindingPointer<Texture> mIncompleteTextures[TEXTURE_TYPE_COUNT]; // Recorded errors @@ -470,37 +335,8 @@ class Context GLenum mResetStrategy; bool mRobustAccess; - BindingPointer<ProgramBinary> mCurrentProgramBinary; - Framebuffer *mBoundDrawFramebuffer; - int mMajorShaderModel; - float mMaximumPointSize; bool mSupportsVertexTexture; - bool mSupportsNonPower2Texture; - bool mSupportsInstancing; - int mMaxViewportDimension; - int mMaxRenderbufferDimension; - int mMaxTextureDimension; - int mMaxCubeTextureDimension; - int mMaxTextureLevel; - float mMaxTextureAnisotropy; - bool mSupportsEventQueries; - bool mSupportsOcclusionQueries; - bool mSupportsBGRATextures; - bool mSupportsDXT1Textures; - bool mSupportsDXT3Textures; - bool mSupportsDXT5Textures; - bool mSupportsFloat32Textures; - bool mSupportsFloat32LinearFilter; - bool mSupportsFloat32RenderableTextures; - bool mSupportsFloat16Textures; - bool mSupportsFloat16LinearFilter; - bool mSupportsFloat16RenderableTextures; - bool mSupportsLuminanceTextures; - bool mSupportsLuminanceAlphaTextures; - bool mSupportsDepthTextures; - bool mSupports32bitIndices; - bool mSupportsTextureFilterAnisotropy; int mNumCompressedTextureFormats; ResourceManager *mResourceManager; diff --git a/src/3rdparty/angle/src/libGLESv2/DynamicHLSL.cpp b/src/3rdparty/angle/src/libGLESv2/DynamicHLSL.cpp new file mode 100644 index 0000000000..e3ec391bfa --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/DynamicHLSL.cpp @@ -0,0 +1,1122 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DynamicHLSL.cpp: Implementation for link and run-time HLSL generation +// + +#include "precompiled.h" + +#include "libGLESv2/DynamicHLSL.h" +#include "libGLESv2/Shader.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/renderer/Renderer.h" +#include "common/utilities.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/formatutils.h" +#include "common/blocklayout.h" + +// For use with ArrayString, see angleutils.h +META_ASSERT(GL_INVALID_INDEX == UINT_MAX); + +namespace gl_d3d +{ + +std::string HLSLComponentTypeString(GLenum componentType) +{ + switch (componentType) + { + case GL_UNSIGNED_INT: return "uint"; + case GL_INT: return "int"; + case GL_UNSIGNED_NORMALIZED: + case GL_SIGNED_NORMALIZED: + case GL_FLOAT: return "float"; + default: UNREACHABLE(); return "not-component-type"; + } +} + +std::string HLSLComponentTypeString(GLenum componentType, int componentCount) +{ + return HLSLComponentTypeString(componentType) + (componentCount > 1 ? Str(componentCount) : ""); +} + +std::string HLSLMatrixTypeString(GLenum type) +{ + switch (type) + { + case GL_FLOAT_MAT2: return "float2x2"; + case GL_FLOAT_MAT3: return "float3x3"; + case GL_FLOAT_MAT4: return "float4x4"; + case GL_FLOAT_MAT2x3: return "float2x3"; + case GL_FLOAT_MAT3x2: return "float3x2"; + case GL_FLOAT_MAT2x4: return "float2x4"; + case GL_FLOAT_MAT4x2: return "float4x2"; + case GL_FLOAT_MAT3x4: return "float3x4"; + case GL_FLOAT_MAT4x3: return "float4x3"; + default: UNREACHABLE(); return "not-matrix-type"; + } +} + +std::string HLSLTypeString(GLenum type) +{ + if (gl::IsMatrixType(type)) + { + return HLSLMatrixTypeString(type); + } + + return HLSLComponentTypeString(gl::VariableComponentType(type), gl::VariableComponentCount(type)); +} + +} + +namespace gl +{ + +const std::string VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@"; +const std::string PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@"; + +DynamicHLSL::DynamicHLSL(rx::Renderer *const renderer) + : mRenderer(renderer) +{ +} + +static bool packVarying(PackedVarying *varying, const int maxVaryingVectors, VaryingPacking packing) +{ + GLenum transposedType = TransposeMatrixType(varying->type); + + // matrices within varying structs are not transposed + int registers = (varying->isStruct() ? HLSLVariableRegisterCount(*varying) : VariableRowCount(transposedType)) * varying->elementCount(); + int elements = (varying->isStruct() ? 4 : VariableColumnCount(transposedType)); + + if (elements >= 2 && elements <= 4) + { + for (int r = 0; r <= maxVaryingVectors - registers; r++) + { + bool available = true; + + for (int y = 0; y < registers && available; y++) + { + for (int x = 0; x < elements && available; x++) + { + if (packing[r + y][x]) + { + available = false; + } + } + } + + if (available) + { + varying->registerIndex = r; + + for (int y = 0; y < registers; y++) + { + for (int x = 0; x < elements; x++) + { + packing[r + y][x] = &*varying; + } + } + + return true; + } + } + + if (elements == 2) + { + for (int r = maxVaryingVectors - registers; r >= 0; r--) + { + bool available = true; + + for (int y = 0; y < registers && available; y++) + { + for (int x = 2; x < 4 && available; x++) + { + if (packing[r + y][x]) + { + available = false; + } + } + } + + if (available) + { + varying->registerIndex = r; + + for (int y = 0; y < registers; y++) + { + for (int x = 2; x < 4; x++) + { + packing[r + y][x] = &*varying; + } + } + + return true; + } + } + } + } + else if (elements == 1) + { + int space[4] = { 0 }; + + for (int y = 0; y < maxVaryingVectors; y++) + { + for (int x = 0; x < 4; x++) + { + space[x] += packing[y][x] ? 0 : 1; + } + } + + int column = 0; + + for (int x = 0; x < 4; x++) + { + if (space[x] >= registers && space[x] < space[column]) + { + column = x; + } + } + + if (space[column] >= registers) + { + for (int r = 0; r < maxVaryingVectors; r++) + { + if (!packing[r][column]) + { + varying->registerIndex = r; + + for (int y = r; y < r + registers; y++) + { + packing[y][column] = &*varying; + } + + break; + } + } + + return true; + } + } + else UNREACHABLE(); + + return false; +} + +// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111 +// Returns the number of used varying registers, or -1 if unsuccesful +int DynamicHLSL::packVaryings(InfoLog &infoLog, VaryingPacking packing, FragmentShader *fragmentShader, + VertexShader *vertexShader, const std::vector<std::string>& transformFeedbackVaryings) +{ + const int maxVaryingVectors = mRenderer->getMaxVaryingVectors(); + + vertexShader->resetVaryingsRegisterAssignment(); + fragmentShader->resetVaryingsRegisterAssignment(); + + std::set<std::string> packedVaryings; + + for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++) + { + PackedVarying *varying = &fragmentShader->mVaryings[varyingIndex]; + if (packVarying(varying, maxVaryingVectors, packing)) + { + packedVaryings.insert(varying->name); + } + else + { + infoLog.append("Could not pack varying %s", varying->name.c_str()); + return -1; + } + } + + for (unsigned int feedbackVaryingIndex = 0; feedbackVaryingIndex < transformFeedbackVaryings.size(); feedbackVaryingIndex++) + { + const std::string &transformFeedbackVarying = transformFeedbackVaryings[feedbackVaryingIndex]; + if (packedVaryings.find(transformFeedbackVarying) == packedVaryings.end()) + { + bool found = false; + for (unsigned int varyingIndex = 0; varyingIndex < vertexShader->mVaryings.size(); varyingIndex++) + { + PackedVarying *varying = &vertexShader->mVaryings[varyingIndex]; + if (transformFeedbackVarying == varying->name) + { + if (!packVarying(varying, maxVaryingVectors, packing)) + { + infoLog.append("Could not pack varying %s", varying->name.c_str()); + return -1; + } + + found = true; + break; + } + } + + if (!found && transformFeedbackVarying != "gl_Position" && transformFeedbackVarying != "gl_PointSize") + { + infoLog.append("Transform feedback varying %s does not exist in the vertex shader.", transformFeedbackVarying.c_str()); + return -1; + } + } + } + + // Return the number of used registers + int registers = 0; + + for (int r = 0; r < maxVaryingVectors; r++) + { + if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3]) + { + registers++; + } + } + + return registers; +} + +std::string DynamicHLSL::generateVaryingHLSL(VertexShader *shader) const +{ + std::string varyingSemantic = getVaryingSemantic(shader->mUsesPointSize); + std::string varyingHLSL; + + for (unsigned int varyingIndex = 0; varyingIndex < shader->mVaryings.size(); varyingIndex++) + { + const PackedVarying &varying = shader->mVaryings[varyingIndex]; + if (varying.registerAssigned()) + { + GLenum transposedType = TransposeMatrixType(varying.type); + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); + + for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) + { + for (int row = 0; row < variableRows; row++) + { + switch (varying.interpolation) + { + case sh::INTERPOLATION_SMOOTH: varyingHLSL += " "; break; + case sh::INTERPOLATION_FLAT: varyingHLSL += " nointerpolation "; break; + case sh::INTERPOLATION_CENTROID: varyingHLSL += " centroid "; break; + default: UNREACHABLE(); + } + + unsigned int semanticIndex = elementIndex * variableRows + varying.registerIndex + row; + std::string n = Str(semanticIndex); + + std::string typeString; + + if (varying.isStruct()) + { + // matrices within structs are not transposed, so + // do not use the special struct prefix "rm" + typeString = decorateVariable(varying.structName); + } + else + { + GLenum componentType = VariableComponentType(transposedType); + int columnCount = VariableColumnCount(transposedType); + typeString = gl_d3d::HLSLComponentTypeString(componentType, columnCount); + } + varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n"; + } + } + } + } + + return varyingHLSL; +} + +std::string DynamicHLSL::generateVertexShaderForInputLayout(const std::string &sourceShader, + const VertexFormat inputLayout[], + const sh::Attribute shaderAttributes[]) const +{ + std::string structHLSL, initHLSL; + + int semanticIndex = 0; + unsigned int inputIndex = 0; + + for (unsigned int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + ASSERT(inputIndex < MAX_VERTEX_ATTRIBS); + + const VertexFormat &vertexFormat = inputLayout[inputIndex]; + const sh::Attribute &shaderAttribute = shaderAttributes[attributeIndex]; + + if (!shaderAttribute.name.empty()) + { + // HLSL code for input structure + if (IsMatrixType(shaderAttribute.type)) + { + // Matrix types are always transposed + structHLSL += " " + gl_d3d::HLSLMatrixTypeString(TransposeMatrixType(shaderAttribute.type)); + } + else + { + GLenum componentType = mRenderer->getVertexComponentType(vertexFormat); + structHLSL += " " + gl_d3d::HLSLComponentTypeString(componentType, VariableComponentCount(shaderAttribute.type)); + } + + structHLSL += " " + decorateVariable(shaderAttribute.name) + " : TEXCOORD" + Str(semanticIndex) + ";\n"; + semanticIndex += VariableRegisterCount(shaderAttribute.type); + + // HLSL code for initialization + initHLSL += " " + decorateVariable(shaderAttribute.name) + " = "; + + // Mismatched vertex attribute to vertex input may result in an undefined + // data reinterpretation (eg for pure integer->float, float->pure integer) + // TODO: issue warning with gl debug info extension, when supported + if (IsMatrixType(shaderAttribute.type) || + (mRenderer->getVertexConversionType(vertexFormat) & rx::VERTEX_CONVERT_GPU) != 0) + { + initHLSL += generateAttributeConversionHLSL(vertexFormat, shaderAttribute); + } + else + { + initHLSL += "input." + decorateVariable(shaderAttribute.name); + } + + initHLSL += ";\n"; + + inputIndex += VariableRowCount(TransposeMatrixType(shaderAttribute.type)); + } + } + + std::string replacementHLSL = "struct VS_INPUT\n" + "{\n" + + structHLSL + + "};\n" + "\n" + "void initAttributes(VS_INPUT input)\n" + "{\n" + + initHLSL + + "}\n"; + + std::string vertexHLSL(sourceShader); + + size_t copyInsertionPos = vertexHLSL.find(VERTEX_ATTRIBUTE_STUB_STRING); + vertexHLSL.replace(copyInsertionPos, VERTEX_ATTRIBUTE_STUB_STRING.length(), replacementHLSL); + + return vertexHLSL; +} + +std::string DynamicHLSL::generatePixelShaderForOutputSignature(const std::string &sourceShader, const std::vector<PixelShaderOuputVariable> &outputVariables, + bool usesFragDepth, const std::vector<GLenum> &outputLayout) const +{ + const int shaderModel = mRenderer->getMajorShaderModel(); + std::string targetSemantic = (shaderModel >= 4) ? "SV_TARGET" : "COLOR"; + std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH"; + + std::string declarationHLSL; + std::string copyHLSL; + for (size_t i = 0; i < outputVariables.size(); i++) + { + const PixelShaderOuputVariable& outputVariable = outputVariables[i]; + ASSERT(outputLayout.size() > outputVariable.outputIndex); + + // FIXME(geofflang): Work around NVIDIA driver bug by repacking buffers + bool outputIndexEnabled = true; // outputLayout[outputVariable.outputIndex] != GL_NONE + if (outputIndexEnabled) + { + declarationHLSL += " " + gl_d3d::HLSLTypeString(outputVariable.type) + " " + outputVariable.name + + " : " + targetSemantic + Str(outputVariable.outputIndex) + ";\n"; + + copyHLSL += " output." + outputVariable.name + " = " + outputVariable.source + ";\n"; + } + } + + if (usesFragDepth) + { + declarationHLSL += " float gl_Depth : " + depthSemantic + ";\n"; + copyHLSL += " output.gl_Depth = gl_Depth; \n"; + } + + std::string replacementHLSL = "struct PS_OUTPUT\n" + "{\n" + + declarationHLSL + + "};\n" + "\n" + "PS_OUTPUT generateOutput()\n" + "{\n" + " PS_OUTPUT output;\n" + + copyHLSL + + " return output;\n" + "}\n"; + + std::string pixelHLSL(sourceShader); + + size_t outputInsertionPos = pixelHLSL.find(PIXEL_OUTPUT_STUB_STRING); + pixelHLSL.replace(outputInsertionPos, PIXEL_OUTPUT_STUB_STRING.length(), replacementHLSL); + + return pixelHLSL; +} + +std::string DynamicHLSL::getVaryingSemantic(bool pointSize) const +{ + // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) + // In D3D11 we manually compute gl_PointCoord in the GS. + int shaderModel = mRenderer->getMajorShaderModel(); + return ((pointSize && shaderModel < 4) ? "COLOR" : "TEXCOORD"); +} + +struct DynamicHLSL::SemanticInfo +{ + struct BuiltinInfo + { + BuiltinInfo() + : enabled(false), + index(0), + systemValue(false) + {} + + bool enabled; + std::string semantic; + unsigned int index; + bool systemValue; + + std::string str() const + { + return (systemValue ? semantic : (semantic + Str(index))); + } + + void enableSystem(const std::string &systemValueSemantic) + { + enabled = true; + semantic = systemValueSemantic; + systemValue = true; + } + + void enable(const std::string &semanticVal, unsigned int indexVal) + { + enabled = true; + semantic = semanticVal; + index = indexVal; + } + }; + + BuiltinInfo dxPosition; + BuiltinInfo glPosition; + BuiltinInfo glFragCoord; + BuiltinInfo glPointCoord; + BuiltinInfo glPointSize; +}; + +DynamicHLSL::SemanticInfo DynamicHLSL::getSemanticInfo(int startRegisters, bool fragCoord, bool pointCoord, + bool pointSize, bool pixelShader) const +{ + SemanticInfo info; + bool hlsl4 = (mRenderer->getMajorShaderModel() >= 4); + const std::string &varyingSemantic = getVaryingSemantic(pointSize); + + int reservedRegisterIndex = startRegisters; + + if (hlsl4) + { + info.dxPosition.enableSystem("SV_Position"); + } + else if (pixelShader) + { + info.dxPosition.enableSystem("VPOS"); + } + else + { + info.dxPosition.enableSystem("POSITION"); + } + + info.glPosition.enable(varyingSemantic, reservedRegisterIndex++); + + if (fragCoord) + { + info.glFragCoord.enable(varyingSemantic, reservedRegisterIndex++); + } + + if (pointCoord) + { + // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) + // In D3D11 we manually compute gl_PointCoord in the GS. + if (hlsl4) + { + info.glPointCoord.enable(varyingSemantic, reservedRegisterIndex++); + } + else + { + info.glPointCoord.enable("TEXCOORD", 0); + } + } + + // Special case: do not include PSIZE semantic in HLSL 3 pixel shaders + if (pointSize && (!pixelShader || hlsl4)) + { + info.glPointSize.enableSystem("PSIZE"); + } + + return info; +} + +std::string DynamicHLSL::generateVaryingLinkHLSL(const SemanticInfo &info, const std::string &varyingHLSL) const +{ + std::string linkHLSL = "{\n"; + + ASSERT(info.dxPosition.enabled && info.glPosition.enabled); + + linkHLSL += " float4 dx_Position : " + info.dxPosition.str() + ";\n"; + linkHLSL += " float4 gl_Position : " + info.glPosition.str() + ";\n"; + + if (info.glFragCoord.enabled) + { + linkHLSL += " float4 gl_FragCoord : " + info.glFragCoord.str() + ";\n"; + } + + if (info.glPointCoord.enabled) + { + linkHLSL += " float2 gl_PointCoord : " + info.glPointCoord.str() + ";\n"; + } + + linkHLSL += varyingHLSL; + + if (info.glPointSize.enabled) + { + linkHLSL += " float gl_PointSize : " + info.glPointSize.str() + ";\n"; + } + + linkHLSL += "};\n"; + + return linkHLSL; +} + +void DynamicHLSL::storeBuiltinLinkedVaryings(const SemanticInfo &info, + std::vector<LinkedVarying> *linkedVaryings) const +{ + ASSERT(info.glPosition.enabled); + + linkedVaryings->push_back(LinkedVarying("gl_Position", GL_FLOAT_VEC4, 1, info.glPosition.semantic, + info.glPosition.index, 1)); + + if (info.glFragCoord.enabled) + { + linkedVaryings->push_back(LinkedVarying("gl_FragCoord", GL_FLOAT_VEC4, 1, info.glFragCoord.semantic, + info.glFragCoord.index, 1)); + } + + if (info.glPointSize.enabled) + { + linkedVaryings->push_back(LinkedVarying("gl_PointSize", GL_FLOAT, 1, "PSIZE", 0, 1)); + } +} + +void DynamicHLSL::storeUserLinkedVaryings(const VertexShader *vertexShader, + std::vector<LinkedVarying> *linkedVaryings) const +{ + const std::string &varyingSemantic = getVaryingSemantic(vertexShader->mUsesPointSize); + const std::vector<PackedVarying> &varyings = vertexShader->mVaryings; + + for (unsigned int varyingIndex = 0; varyingIndex < varyings.size(); varyingIndex++) + { + const PackedVarying &varying = varyings[varyingIndex]; + if (varying.registerAssigned()) + { + GLenum transposedType = TransposeMatrixType(varying.type); + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); + + linkedVaryings->push_back(LinkedVarying(varying.name, varying.type, varying.elementCount(), + varyingSemantic, varying.registerIndex, + variableRows * varying.elementCount())); + } + } +} + +bool DynamicHLSL::generateShaderLinkHLSL(InfoLog &infoLog, int registers, const VaryingPacking packing, + std::string& pixelHLSL, std::string& vertexHLSL, + FragmentShader *fragmentShader, VertexShader *vertexShader, + const std::vector<std::string>& transformFeedbackVaryings, + std::vector<LinkedVarying> *linkedVaryings, + std::map<int, VariableLocation> *programOutputVars, + std::vector<PixelShaderOuputVariable> *outPixelShaderKey, + bool *outUsesFragDepth) const +{ + if (pixelHLSL.empty() || vertexHLSL.empty()) + { + return false; + } + + bool usesMRT = fragmentShader->mUsesMultipleRenderTargets; + bool usesFragColor = fragmentShader->mUsesFragColor; + bool usesFragData = fragmentShader->mUsesFragData; + bool usesFragCoord = fragmentShader->mUsesFragCoord; + bool usesPointCoord = fragmentShader->mUsesPointCoord; + bool usesPointSize = vertexShader->mUsesPointSize; + + if (usesFragColor && usesFragData) + { + infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader."); + return false; + } + + // Write the HLSL input/output declarations + const int shaderModel = mRenderer->getMajorShaderModel(); + const int maxVaryingVectors = mRenderer->getMaxVaryingVectors(); + + const int registersNeeded = registers + (usesFragCoord ? 1 : 0) + (usesPointCoord ? 1 : 0); + + // Two cases when writing to gl_FragColor and using ESSL 1.0: + // - with a 3.0 context, the output color is copied to channel 0 + // - with a 2.0 context, the output color is broadcast to all channels + const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3); + const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getRendererCaps().maxDrawBuffers : 1); + + int shaderVersion = vertexShader->getShaderVersion(); + + if (registersNeeded > maxVaryingVectors) + { + infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord"); + return false; + } + + const std::string &varyingHLSL = generateVaryingHLSL(vertexShader); + const SemanticInfo &vertexSemantics = getSemanticInfo(registers, usesFragCoord, + false, usesPointSize, false); + + storeUserLinkedVaryings(vertexShader, linkedVaryings); + storeBuiltinLinkedVaryings(vertexSemantics, linkedVaryings); + + // Add stub string to be replaced when shader is dynamically defined by its layout + vertexHLSL += "\n" + VERTEX_ATTRIBUTE_STUB_STRING + "\n" + "struct VS_OUTPUT\n" + generateVaryingLinkHLSL(vertexSemantics, varyingHLSL) + "\n" + "VS_OUTPUT main(VS_INPUT input)\n" + "{\n" + " initAttributes(input);\n"; + + if (shaderModel >= 4) + { + vertexHLSL += "\n" + " gl_main();\n" + "\n" + " VS_OUTPUT output;\n" + " output.gl_Position = gl_Position;\n" + " output.dx_Position.x = gl_Position.x;\n" + " output.dx_Position.y = -gl_Position.y;\n" + " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" + " output.dx_Position.w = gl_Position.w;\n"; + } + else + { + vertexHLSL += "\n" + " gl_main();\n" + "\n" + " VS_OUTPUT output;\n" + " output.gl_Position = gl_Position;\n" + " output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n" + " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n" + " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" + " output.dx_Position.w = gl_Position.w;\n"; + } + + if (usesPointSize && shaderModel >= 3) + { + vertexHLSL += " output.gl_PointSize = gl_PointSize;\n"; + } + + if (usesFragCoord) + { + vertexHLSL += " output.gl_FragCoord = gl_Position;\n"; + } + + for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexShader->mVaryings.size(); vertVaryingIndex++) + { + const PackedVarying &varying = vertexShader->mVaryings[vertVaryingIndex]; + if (varying.registerAssigned()) + { + for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) + { + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(TransposeMatrixType(varying.type))); + + for (int row = 0; row < variableRows; row++) + { + int r = varying.registerIndex + elementIndex * variableRows + row; + vertexHLSL += " output.v" + Str(r); + + bool sharedRegister = false; // Register used by multiple varyings + + for (int x = 0; x < 4; x++) + { + if (packing[r][x] && packing[r][x] != packing[r][0]) + { + sharedRegister = true; + break; + } + } + + if(sharedRegister) + { + vertexHLSL += "."; + + for (int x = 0; x < 4; x++) + { + if (packing[r][x] == &varying) + { + switch(x) + { + case 0: vertexHLSL += "x"; break; + case 1: vertexHLSL += "y"; break; + case 2: vertexHLSL += "z"; break; + case 3: vertexHLSL += "w"; break; + } + } + } + } + + vertexHLSL += " = _" + varying.name; + + if (varying.isArray()) + { + vertexHLSL += ArrayString(elementIndex); + } + + if (variableRows > 1) + { + vertexHLSL += ArrayString(row); + } + + vertexHLSL += ";\n"; + } + } + } + } + + vertexHLSL += "\n" + " return output;\n" + "}\n"; + + const SemanticInfo &pixelSemantics = getSemanticInfo(registers, usesFragCoord, usesPointCoord, + usesPointSize, true); + + pixelHLSL += "struct PS_INPUT\n" + generateVaryingLinkHLSL(pixelSemantics, varyingHLSL) + "\n"; + + if (shaderVersion < 300) + { + for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++) + { + PixelShaderOuputVariable outputKeyVariable; + outputKeyVariable.type = GL_FLOAT_VEC4; + outputKeyVariable.name = "gl_Color" + Str(renderTargetIndex); + outputKeyVariable.source = broadcast ? "gl_Color[0]" : "gl_Color[" + Str(renderTargetIndex) + "]"; + outputKeyVariable.outputIndex = renderTargetIndex; + + outPixelShaderKey->push_back(outputKeyVariable); + } + + *outUsesFragDepth = fragmentShader->mUsesFragDepth; + } + else + { + defineOutputVariables(fragmentShader, programOutputVars); + + const std::vector<sh::Attribute> &shaderOutputVars = fragmentShader->getOutputVariables(); + for (auto locationIt = programOutputVars->begin(); locationIt != programOutputVars->end(); locationIt++) + { + const VariableLocation &outputLocation = locationIt->second; + const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index]; + const std::string &variableName = "out_" + outputLocation.name; + const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element)); + + PixelShaderOuputVariable outputKeyVariable; + outputKeyVariable.type = outputVariable.type; + outputKeyVariable.name = variableName + elementString; + outputKeyVariable.source = variableName + ArrayString(outputLocation.element); + outputKeyVariable.outputIndex = locationIt->first; + + outPixelShaderKey->push_back(outputKeyVariable); + } + + *outUsesFragDepth = false; + } + + pixelHLSL += PIXEL_OUTPUT_STUB_STRING + "\n"; + + if (fragmentShader->mUsesFrontFacing) + { + if (shaderModel >= 4) + { + pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n" + "{\n"; + } + else + { + pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n" + "{\n"; + } + } + else + { + pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n" + "{\n"; + } + + if (usesFragCoord) + { + pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"; + + if (shaderModel >= 4) + { + pixelHLSL += " gl_FragCoord.x = input.dx_Position.x;\n" + " gl_FragCoord.y = input.dx_Position.y;\n"; + } + else if (shaderModel >= 3) + { + pixelHLSL += " gl_FragCoord.x = input.dx_Position.x + 0.5;\n" + " gl_FragCoord.y = input.dx_Position.y + 0.5;\n"; + } + else + { + // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport() + pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n" + " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n"; + } + + pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n" + " gl_FragCoord.w = rhw;\n"; + } + + if (usesPointCoord && shaderModel >= 3) + { + pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n"; + pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n"; + } + + if (fragmentShader->mUsesFrontFacing) + { + if (shaderModel <= 3) + { + pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n"; + } + else + { + pixelHLSL += " gl_FrontFacing = isFrontFace;\n"; + } + } + + for (unsigned int varyingIndex = 0; varyingIndex < fragmentShader->mVaryings.size(); varyingIndex++) + { + const PackedVarying &varying = fragmentShader->mVaryings[varyingIndex]; + if (varying.registerAssigned()) + { + for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) + { + GLenum transposedType = TransposeMatrixType(varying.type); + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); + for (int row = 0; row < variableRows; row++) + { + std::string n = Str(varying.registerIndex + elementIndex * variableRows + row); + pixelHLSL += " _" + varying.name; + + if (varying.isArray()) + { + pixelHLSL += ArrayString(elementIndex); + } + + if (variableRows > 1) + { + pixelHLSL += ArrayString(row); + } + + if (varying.isStruct()) + { + pixelHLSL += " = input.v" + n + ";\n"; break; + } + else + { + switch (VariableColumnCount(transposedType)) + { + case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break; + case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break; + case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break; + case 4: pixelHLSL += " = input.v" + n + ";\n"; break; + default: UNREACHABLE(); + } + } + } + } + } + else UNREACHABLE(); + } + + pixelHLSL += "\n" + " gl_main();\n" + "\n" + " return generateOutput();\n" + "}\n"; + + return true; +} + +void DynamicHLSL::defineOutputVariables(FragmentShader *fragmentShader, std::map<int, VariableLocation> *programOutputVars) const +{ + const std::vector<sh::Attribute> &shaderOutputVars = fragmentShader->getOutputVariables(); + + for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size(); outputVariableIndex++) + { + const sh::Attribute &outputVariable = shaderOutputVars[outputVariableIndex]; + const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location; + + if (outputVariable.arraySize > 0) + { + for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++) + { + const int location = baseLocation + elementIndex; + ASSERT(programOutputVars->count(location) == 0); + (*programOutputVars)[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex); + } + } + else + { + ASSERT(programOutputVars->count(baseLocation) == 0); + (*programOutputVars)[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex); + } + } +} + +std::string DynamicHLSL::generateGeometryShaderHLSL(int registers, FragmentShader *fragmentShader, VertexShader *vertexShader) const +{ + // for now we only handle point sprite emulation + ASSERT(vertexShader->mUsesPointSize && mRenderer->getMajorShaderModel() >= 4); + return generatePointSpriteHLSL(registers, fragmentShader, vertexShader); +} + +std::string DynamicHLSL::generatePointSpriteHLSL(int registers, FragmentShader *fragmentShader, VertexShader *vertexShader) const +{ + ASSERT(registers >= 0); + ASSERT(vertexShader->mUsesPointSize); + ASSERT(mRenderer->getMajorShaderModel() >= 4); + + std::string geomHLSL; + + const SemanticInfo &inSemantics = getSemanticInfo(registers, fragmentShader->mUsesFragCoord, + false, true, false); + const SemanticInfo &outSemantics = getSemanticInfo(registers, fragmentShader->mUsesFragCoord, + fragmentShader->mUsesPointCoord, true, false); + + std::string varyingHLSL = generateVaryingHLSL(vertexShader); + std::string inLinkHLSL = generateVaryingLinkHLSL(inSemantics, varyingHLSL); + std::string outLinkHLSL = generateVaryingLinkHLSL(outSemantics, varyingHLSL); + + // TODO(geofflang): use context's caps + geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n" + "\n" + "struct GS_INPUT\n" + inLinkHLSL + "\n" + + "struct GS_OUTPUT\n" + outLinkHLSL + "\n" + + "\n" + "static float2 pointSpriteCorners[] = \n" + "{\n" + " float2( 0.5f, -0.5f),\n" + " float2( 0.5f, 0.5f),\n" + " float2(-0.5f, -0.5f),\n" + " float2(-0.5f, 0.5f)\n" + "};\n" + "\n" + "static float2 pointSpriteTexcoords[] = \n" + "{\n" + " float2(1.0f, 1.0f),\n" + " float2(1.0f, 0.0f),\n" + " float2(0.0f, 1.0f),\n" + " float2(0.0f, 0.0f)\n" + "};\n" + "\n" + "static float minPointSize = " + Str(mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n" + "static float maxPointSize = " + Str(mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n" + "\n" + "[maxvertexcount(4)]\n" + "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n" + "{\n" + " GS_OUTPUT output = (GS_OUTPUT)0;\n" + " output.gl_Position = input[0].gl_Position;\n"; + " output.gl_PointSize = input[0].gl_PointSize;\n"; + + for (int r = 0; r < registers; r++) + { + geomHLSL += " output.v" + Str(r) + " = input[0].v" + Str(r) + ";\n"; + } + + if (fragmentShader->mUsesFragCoord) + { + geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n"; + } + + geomHLSL += " \n" + " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n" + " float4 dx_Position = input[0].dx_Position;\n" + " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * dx_Position.w;\n"; + + for (int corner = 0; corner < 4; corner++) + { + geomHLSL += " \n" + " output.dx_Position = dx_Position + float4(pointSpriteCorners[" + Str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n"; + + if (fragmentShader->mUsesPointCoord) + { + geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + Str(corner) + "];\n"; + } + + geomHLSL += " outStream.Append(output);\n"; + } + + geomHLSL += " \n" + " outStream.RestartStrip();\n" + "}\n"; + + return geomHLSL; +} + +// This method needs to match OutputHLSL::decorate +std::string DynamicHLSL::decorateVariable(const std::string &name) +{ + if (name.compare(0, 3, "gl_") != 0) + { + return "_" + name; + } + + return name; +} + +std::string DynamicHLSL::generateAttributeConversionHLSL(const VertexFormat &vertexFormat, const sh::ShaderVariable &shaderAttrib) const +{ + std::string attribString = "input." + decorateVariable(shaderAttrib.name); + + // Matrix + if (IsMatrixType(shaderAttrib.type)) + { + return "transpose(" + attribString + ")"; + } + + GLenum shaderComponentType = VariableComponentType(shaderAttrib.type); + int shaderComponentCount = VariableComponentCount(shaderAttrib.type); + + // Perform integer to float conversion (if necessary) + bool requiresTypeConversion = (shaderComponentType == GL_FLOAT && vertexFormat.mType != GL_FLOAT); + + if (requiresTypeConversion) + { + // TODO: normalization for 32-bit integer formats + ASSERT(!vertexFormat.mNormalized && !vertexFormat.mPureInteger); + return "float" + Str(shaderComponentCount) + "(" + attribString + ")"; + } + + // No conversion necessary + return attribString; +} + +void DynamicHLSL::getInputLayoutSignature(const VertexFormat inputLayout[], GLenum signature[]) const +{ + for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++) + { + const VertexFormat &vertexFormat = inputLayout[inputIndex]; + + if (vertexFormat.mType == GL_NONE) + { + signature[inputIndex] = GL_NONE; + } + else + { + bool gpuConverted = ((mRenderer->getVertexConversionType(vertexFormat) & rx::VERTEX_CONVERT_GPU) != 0); + signature[inputIndex] = (gpuConverted ? GL_TRUE : GL_FALSE); + } + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/DynamicHLSL.h b/src/3rdparty/angle/src/libGLESv2/DynamicHLSL.h new file mode 100644 index 0000000000..68abd6e1a4 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/DynamicHLSL.h @@ -0,0 +1,96 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DynamicHLSL.h: Interface for link and run-time HLSL generation +// + +#ifndef LIBGLESV2_DYNAMIC_HLSL_H_ +#define LIBGLESV2_DYNAMIC_HLSL_H_ + +#include "common/angleutils.h" +#include "libGLESv2/constants.h" + +namespace rx +{ +class Renderer; +} + +namespace sh +{ +struct Attribute; +struct ShaderVariable; +} + +namespace gl +{ + +class InfoLog; +class FragmentShader; +class VertexShader; +struct VariableLocation; +struct LinkedVarying; +struct VertexAttribute; +struct VertexFormat; +struct PackedVarying; + +typedef const PackedVarying *VaryingPacking[IMPLEMENTATION_MAX_VARYING_VECTORS][4]; + +struct PixelShaderOuputVariable +{ + GLenum type; + std::string name; + std::string source; + size_t outputIndex; +}; + +class DynamicHLSL +{ + public: + explicit DynamicHLSL(rx::Renderer *const renderer); + + int packVaryings(InfoLog &infoLog, VaryingPacking packing, FragmentShader *fragmentShader, + VertexShader *vertexShader, const std::vector<std::string>& transformFeedbackVaryings); + std::string generateVertexShaderForInputLayout(const std::string &sourceShader, const VertexFormat inputLayout[], + const sh::Attribute shaderAttributes[]) const; + std::string generatePixelShaderForOutputSignature(const std::string &sourceShader, const std::vector<PixelShaderOuputVariable> &outputVariables, + bool usesFragDepth, const std::vector<GLenum> &outputLayout) const; + bool generateShaderLinkHLSL(InfoLog &infoLog, int registers, const VaryingPacking packing, + std::string& pixelHLSL, std::string& vertexHLSL, + FragmentShader *fragmentShader, VertexShader *vertexShader, + const std::vector<std::string>& transformFeedbackVaryings, + std::vector<LinkedVarying> *linkedVaryings, + std::map<int, VariableLocation> *programOutputVars, + std::vector<PixelShaderOuputVariable> *outPixelShaderKey, + bool *outUsesFragDepth) const; + + std::string generateGeometryShaderHLSL(int registers, FragmentShader *fragmentShader, VertexShader *vertexShader) const; + void getInputLayoutSignature(const VertexFormat inputLayout[], GLenum signature[]) const; + + private: + DISALLOW_COPY_AND_ASSIGN(DynamicHLSL); + + rx::Renderer *const mRenderer; + + struct SemanticInfo; + + std::string getVaryingSemantic(bool pointSize) const; + SemanticInfo getSemanticInfo(int startRegisters, bool fragCoord, bool pointCoord, bool pointSize, + bool pixelShader) const; + std::string generateVaryingLinkHLSL(const SemanticInfo &info, const std::string &varyingHLSL) const; + std::string generateVaryingHLSL(VertexShader *shader) const; + void storeUserLinkedVaryings(const VertexShader *vertexShader, std::vector<LinkedVarying> *linkedVaryings) const; + void storeBuiltinLinkedVaryings(const SemanticInfo &info, std::vector<LinkedVarying> *linkedVaryings) const; + void defineOutputVariables(FragmentShader *fragmentShader, std::map<int, VariableLocation> *programOutputVars) const; + std::string generatePointSpriteHLSL(int registers, FragmentShader *fragmentShader, VertexShader *vertexShader) const; + + // Prepend an underscore + static std::string decorateVariable(const std::string &name); + + std::string generateAttributeConversionHLSL(const VertexFormat &vertexFormat, const sh::ShaderVariable &shaderAttrib) const; +}; + +} + +#endif // LIBGLESV2_DYNAMIC_HLSL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Fence.cpp b/src/3rdparty/angle/src/libGLESv2/Fence.cpp index e4218bbeec..31d149d629 100644 --- a/src/3rdparty/angle/src/libGLESv2/Fence.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Fence.cpp @@ -7,46 +7,187 @@ // Fence.cpp: Implements the gl::Fence class, which supports the GL_NV_fence extension. +// Important note on accurate timers in Windows: +// +// QueryPerformanceCounter has a few major issues, including being 10x as expensive to call +// as timeGetTime on laptops and "jumping" during certain hardware events. +// +// See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc" +// https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc +// +// We still opt to use QPC. In the present and moving forward, most newer systems will not suffer +// from buggy implementations. + #include "libGLESv2/Fence.h" #include "libGLESv2/renderer/FenceImpl.h" #include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/main.h" namespace gl { -Fence::Fence(rx::Renderer *renderer) +FenceNV::FenceNV(rx::Renderer *renderer) { mFence = renderer->createFence(); } -Fence::~Fence() +FenceNV::~FenceNV() { delete mFence; } -GLboolean Fence::isFence() +GLboolean FenceNV::isFence() const +{ + // GL_NV_fence spec: + // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence. + return (mFence->isSet() ? GL_TRUE : GL_FALSE); +} + +void FenceNV::setFence(GLenum condition) +{ + mFence->set(); + + mCondition = condition; + mStatus = GL_FALSE; +} + +GLboolean FenceNV::testFence() +{ + // Flush the command buffer by default + bool result = mFence->test(true); + + mStatus = (result ? GL_TRUE : GL_FALSE); + return mStatus; +} + +void FenceNV::finishFence() +{ + ASSERT(mFence->isSet()); + + while (!mFence->test(true)) + { + Sleep(0); + } +} + +GLint FenceNV::getFencei(GLenum pname) +{ + ASSERT(mFence->isSet()); + + switch (pname) + { + case GL_FENCE_STATUS_NV: + { + // GL_NV_fence spec: + // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV + // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence. + if (mStatus == GL_TRUE) + { + return GL_TRUE; + } + + mStatus = (mFence->test(false) ? GL_TRUE : GL_FALSE); + return mStatus; + } + + case GL_FENCE_CONDITION_NV: + return mCondition; + + default: UNREACHABLE(); return 0; + } +} + +FenceSync::FenceSync(rx::Renderer *renderer, GLuint id) + : RefCountObject(id) { - return mFence->isFence(); + mFence = renderer->createFence(); + + LARGE_INTEGER counterFreqency = { 0 }; + BOOL success = QueryPerformanceFrequency(&counterFreqency); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + mCounterFrequency = counterFreqency.QuadPart; +} + +FenceSync::~FenceSync() +{ + delete mFence; } -void Fence::setFence(GLenum condition) +void FenceSync::set(GLenum condition) { - mFence->setFence(condition); + mCondition = condition; + mFence->set(); } -GLboolean Fence::testFence() +GLenum FenceSync::clientWait(GLbitfield flags, GLuint64 timeout) { - return mFence->testFence(); + ASSERT(mFence->isSet()); + + bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0); + + if (mFence->test(flushCommandBuffer)) + { + return GL_ALREADY_SIGNALED; + } + + if (mFence->hasError()) + { + return GL_WAIT_FAILED; + } + + if (timeout == 0) + { + return GL_TIMEOUT_EXPIRED; + } + + LARGE_INTEGER currentCounter = { 0 }; + BOOL success = QueryPerformanceCounter(¤tCounter); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + LONGLONG timeoutInSeconds = static_cast<LONGLONG>(timeout) * static_cast<LONGLONG>(1000000ll); + LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; + + while (currentCounter.QuadPart < endCounter && !mFence->test(flushCommandBuffer)) + { + Sleep(0); + BOOL success = QueryPerformanceCounter(¤tCounter); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + } + + if (mFence->hasError()) + { + return GL_WAIT_FAILED; + } + + if (currentCounter.QuadPart >= endCounter) + { + return GL_TIMEOUT_EXPIRED; + } + + return GL_CONDITION_SATISFIED; } -void Fence::finishFence() +void FenceSync::serverWait() { - mFence->finishFence(); + // Because our API is currently designed to be called from a single thread, we don't need to do + // extra work for a server-side fence. GPU commands issued after the fence is created will always + // be processed after the fence is signaled. } -void Fence::getFenceiv(GLenum pname, GLint *params) +GLenum FenceSync::getStatus() const { - mFence->getFenceiv(pname, params); + if (mFence->test(false)) + { + // The spec does not specify any way to report errors during the status test (e.g. device lost) + // so we report the fence is unblocked in case of error or signaled. + return GL_SIGNALED; + } + + return GL_UNSIGNALED; } } diff --git a/src/3rdparty/angle/src/libGLESv2/Fence.h b/src/3rdparty/angle/src/libGLESv2/Fence.h index 1cedebb112..291edb3de1 100644 --- a/src/3rdparty/angle/src/libGLESv2/Fence.h +++ b/src/3rdparty/angle/src/libGLESv2/Fence.h @@ -10,6 +10,7 @@ #define LIBGLESV2_FENCE_H_ #include "common/angleutils.h" +#include "common/RefCountObject.h" namespace rx { @@ -20,22 +21,50 @@ class FenceImpl; namespace gl { -class Fence +class FenceNV { public: - explicit Fence(rx::Renderer *renderer); - virtual ~Fence(); + explicit FenceNV(rx::Renderer *renderer); + virtual ~FenceNV(); - GLboolean isFence(); + GLboolean isFence() const; void setFence(GLenum condition); GLboolean testFence(); void finishFence(); - void getFenceiv(GLenum pname, GLint *params); + GLint getFencei(GLenum pname); + + GLboolean getStatus() const { return mStatus; } + GLuint getCondition() const { return mCondition; } private: - DISALLOW_COPY_AND_ASSIGN(Fence); + DISALLOW_COPY_AND_ASSIGN(FenceNV); rx::FenceImpl *mFence; + + GLboolean mStatus; + GLenum mCondition; +}; + +class FenceSync : public RefCountObject +{ + public: + explicit FenceSync(rx::Renderer *renderer, GLuint id); + virtual ~FenceSync(); + + void set(GLenum condition); + GLenum clientWait(GLbitfield flags, GLuint64 timeout); + void serverWait(); + GLenum getStatus() const; + + GLuint getCondition() const { return mCondition; } + + private: + DISALLOW_COPY_AND_ASSIGN(FenceSync); + + rx::FenceImpl *mFence; + LONGLONG mCounterFrequency; + + GLenum mCondition; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp b/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp index b0abba0ac4..f808175250 100644 --- a/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -11,253 +11,288 @@ #include "libGLESv2/Framebuffer.h" #include "libGLESv2/main.h" -#include "libGLESv2/utilities.h" +#include "common/utilities.h" +#include "libGLESv2/formatutils.h" #include "libGLESv2/Texture.h" #include "libGLESv2/Context.h" #include "libGLESv2/renderer/Renderer.h" #include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/FramebufferAttachment.h" namespace gl { -Framebuffer::Framebuffer(rx::Renderer *renderer) - : mRenderer(renderer) +Framebuffer::Framebuffer(rx::Renderer *renderer, GLuint id) + : mRenderer(renderer), + mId(id), + mReadBufferState(GL_COLOR_ATTACHMENT0_EXT), + mDepthbuffer(NULL), + mStencilbuffer(NULL) { for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { - mColorbufferTypes[colorAttachment] = GL_NONE; + mColorbuffers[colorAttachment] = NULL; mDrawBufferStates[colorAttachment] = GL_NONE; } mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT; - mReadBufferState = GL_COLOR_ATTACHMENT0_EXT; - - mDepthbufferType = GL_NONE; - mStencilbufferType = GL_NONE; } Framebuffer::~Framebuffer() { for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { - mColorbufferPointers[colorAttachment].set(NULL); + SafeDelete(mColorbuffers[colorAttachment]); } - mDepthbufferPointer.set(NULL); - mStencilbufferPointer.set(NULL); + SafeDelete(mDepthbuffer); + SafeDelete(mStencilbuffer); } -Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const +FramebufferAttachment *Framebuffer::createAttachment(GLenum type, GLuint handle, GLint level, GLint layer) const { - gl::Context *context = gl::getContext(); - Renderbuffer *buffer = NULL; - - if (type == GL_NONE) + if (handle == 0) { - buffer = NULL; + return NULL; } - else if (type == GL_RENDERBUFFER) - { - buffer = context->getRenderbuffer(handle); - } - else if (IsInternalTextureTarget(type)) - { - buffer = context->getTexture(handle)->getRenderbuffer(type); - } - else + + gl::Context *context = gl::getContext(); + + switch (type) { + case GL_NONE: + return NULL; + + case GL_RENDERBUFFER: + return new RenderbufferAttachment(context->getRenderbuffer(handle)); + + case GL_TEXTURE_2D: + { + Texture *texture = context->getTexture(handle); + if (texture && texture->getTarget() == GL_TEXTURE_2D) + { + Texture2D *tex2D = static_cast<Texture2D*>(texture); + return new Texture2DAttachment(tex2D, level); + } + else + { + return NULL; + } + } + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + { + Texture *texture = context->getTexture(handle); + if (texture && texture->getTarget() == GL_TEXTURE_CUBE_MAP) + { + TextureCubeMap *texCube = static_cast<TextureCubeMap*>(texture); + return new TextureCubeMapAttachment(texCube, type, level); + } + else + { + return NULL; + } + } + + case GL_TEXTURE_3D: + { + Texture *texture = context->getTexture(handle); + if (texture && texture->getTarget() == GL_TEXTURE_3D) + { + Texture3D *tex3D = static_cast<Texture3D*>(texture); + return new Texture3DAttachment(tex3D, level, layer); + } + else + { + return NULL; + } + } + + case GL_TEXTURE_2D_ARRAY: + { + Texture *texture = context->getTexture(handle); + if (texture && texture->getTarget() == GL_TEXTURE_2D_ARRAY) + { + Texture2DArray *tex2DArray = static_cast<Texture2DArray*>(texture); + return new Texture2DArrayAttachment(tex2DArray, level, layer); + } + else + { + return NULL; + } + } + + default: UNREACHABLE(); + return NULL; } - - return buffer; } -void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer) +void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer, GLint level, GLint layer) { ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS); - mColorbufferTypes[colorAttachment] = (colorbuffer != 0) ? type : GL_NONE; - mColorbufferPointers[colorAttachment].set(lookupRenderbuffer(type, colorbuffer)); + SafeDelete(mColorbuffers[colorAttachment]); + mColorbuffers[colorAttachment] = createAttachment(type, colorbuffer, level, layer); } -void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer) +void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer) { - mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE; - mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer)); + SafeDelete(mDepthbuffer); + mDepthbuffer = createAttachment(type, depthbuffer, level, layer); } -void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer) +void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer) { - mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE; - mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer)); + SafeDelete(mStencilbuffer); + mStencilbuffer = createAttachment(type, stencilbuffer, level, layer); } -void Framebuffer::detachTexture(GLuint texture) +void Framebuffer::setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer) { - for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - if (mColorbufferPointers[colorAttachment].id() == texture && IsInternalTextureTarget(mColorbufferTypes[colorAttachment])) - { - mColorbufferTypes[colorAttachment] = GL_NONE; - mColorbufferPointers[colorAttachment].set(NULL); - } - } + FramebufferAttachment *attachment = createAttachment(type, depthStencilBuffer, level, layer); - if (mDepthbufferPointer.id() == texture && IsInternalTextureTarget(mDepthbufferType)) - { - mDepthbufferType = GL_NONE; - mDepthbufferPointer.set(NULL); - } + SafeDelete(mDepthbuffer); + SafeDelete(mStencilbuffer); - if (mStencilbufferPointer.id() == texture && IsInternalTextureTarget(mStencilbufferType)) + // ensure this is a legitimate depth+stencil format + if (attachment && attachment->getDepthSize() > 0 && attachment->getStencilSize() > 0) { - mStencilbufferType = GL_NONE; - mStencilbufferPointer.set(NULL); + mDepthbuffer = attachment; + + // Make a new attachment object to ensure we do not double-delete + // See angle issue 686 + mStencilbuffer = createAttachment(type, depthStencilBuffer, level, layer); } } -void Framebuffer::detachRenderbuffer(GLuint renderbuffer) +void Framebuffer::detachTexture(GLuint textureId) { for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { - if (mColorbufferPointers[colorAttachment].id() == renderbuffer && mColorbufferTypes[colorAttachment] == GL_RENDERBUFFER) + FramebufferAttachment *attachment = mColorbuffers[colorAttachment]; + + if (attachment && attachment->isTextureWithId(textureId)) { - mColorbufferTypes[colorAttachment] = GL_NONE; - mColorbufferPointers[colorAttachment].set(NULL); + SafeDelete(mColorbuffers[colorAttachment]); } } - if (mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER) + if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId)) { - mDepthbufferType = GL_NONE; - mDepthbufferPointer.set(NULL); + SafeDelete(mDepthbuffer); } - if (mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER) + if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId)) { - mStencilbufferType = GL_NONE; - mStencilbufferPointer.set(NULL); + SafeDelete(mStencilbuffer); } } -unsigned int Framebuffer::getRenderTargetSerial(unsigned int colorAttachment) const +void Framebuffer::detachRenderbuffer(GLuint renderbufferId) { - ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS); + for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) + { + FramebufferAttachment *attachment = mColorbuffers[colorAttachment]; - Renderbuffer *colorbuffer = mColorbufferPointers[colorAttachment].get(); + if (attachment && attachment->isRenderbufferWithId(renderbufferId)) + { + SafeDelete(mColorbuffers[colorAttachment]); + } + } - if (colorbuffer) + if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId)) { - return colorbuffer->getSerial(); + SafeDelete(mDepthbuffer); } - return 0; -} - -unsigned int Framebuffer::getDepthbufferSerial() const -{ - Renderbuffer *depthbuffer = mDepthbufferPointer.get(); - - if (depthbuffer) + if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId)) { - return depthbuffer->getSerial(); + SafeDelete(mStencilbuffer); } - - return 0; } -unsigned int Framebuffer::getStencilbufferSerial() const +FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const { - Renderbuffer *stencilbuffer = mStencilbufferPointer.get(); - - if (stencilbuffer) - { - return stencilbuffer->getSerial(); - } - - return 0; + ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS); + return mColorbuffers[colorAttachment]; } -Renderbuffer *Framebuffer::getColorbuffer(unsigned int colorAttachment) const +FramebufferAttachment *Framebuffer::getDepthbuffer() const { - ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS); - return mColorbufferPointers[colorAttachment].get(); + return mDepthbuffer; } -Renderbuffer *Framebuffer::getDepthbuffer() const +FramebufferAttachment *Framebuffer::getStencilbuffer() const { - return mDepthbufferPointer.get(); + return mStencilbuffer; } -Renderbuffer *Framebuffer::getStencilbuffer() const +FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const { - return mStencilbufferPointer.get(); + return (hasValidDepthStencil() ? mDepthbuffer : NULL); } -Renderbuffer *Framebuffer::getDepthOrStencilbuffer() const +FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const { - Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get(); + FramebufferAttachment *depthstencilbuffer = mDepthbuffer; if (!depthstencilbuffer) { - depthstencilbuffer = mStencilbufferPointer.get(); + depthstencilbuffer = mStencilbuffer; } return depthstencilbuffer; } -Renderbuffer *Framebuffer::getReadColorbuffer() const +FramebufferAttachment *Framebuffer::getReadColorbuffer() const { // Will require more logic if glReadBuffers is supported - return mColorbufferPointers[0].get(); + return mColorbuffers[0]; } GLenum Framebuffer::getReadColorbufferType() const { // Will require more logic if glReadBuffers is supported - return mColorbufferTypes[0]; + return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE); } -Renderbuffer *Framebuffer::getFirstColorbuffer() const +FramebufferAttachment *Framebuffer::getFirstColorbuffer() const { for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { - if (mColorbufferTypes[colorAttachment] != GL_NONE) + if (mColorbuffers[colorAttachment]) { - return mColorbufferPointers[colorAttachment].get(); + return mColorbuffers[colorAttachment]; } } return NULL; } -GLenum Framebuffer::getColorbufferType(unsigned int colorAttachment) const +FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const { - ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS); - return mColorbufferTypes[colorAttachment]; -} - -GLenum Framebuffer::getDepthbufferType() const -{ - return mDepthbufferType; -} - -GLenum Framebuffer::getStencilbufferType() const -{ - return mStencilbufferType; -} - -GLuint Framebuffer::getColorbufferHandle(unsigned int colorAttachment) const -{ - ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS); - return mColorbufferPointers[colorAttachment].id(); -} - -GLuint Framebuffer::getDepthbufferHandle() const -{ - return mDepthbufferPointer.id(); -} - -GLuint Framebuffer::getStencilbufferHandle() const -{ - return mStencilbufferPointer.id(); + if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) + { + return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0); + } + else + { + switch (attachment) + { + case GL_DEPTH_ATTACHMENT: + return getDepthbuffer(); + case GL_STENCIL_ATTACHMENT: + return getStencilbuffer(); + case GL_DEPTH_STENCIL_ATTACHMENT: + return getDepthStencilBuffer(); + default: + UNREACHABLE(); + return NULL; + } + } } GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const @@ -272,7 +307,7 @@ void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBu bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const { - return (mColorbufferTypes[colorAttachment] != GL_NONE && mDrawBufferStates[colorAttachment] != GL_NONE); + return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE); } bool Framebuffer::hasEnabledColorAttachment() const @@ -290,17 +325,7 @@ bool Framebuffer::hasEnabledColorAttachment() const bool Framebuffer::hasStencil() const { - if (mStencilbufferType != GL_NONE) - { - const Renderbuffer *stencilbufferObject = getStencilbuffer(); - - if (stencilbufferObject) - { - return stencilbufferObject->getStencilSize() > 0; - } - } - - return false; + return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0); } bool Framebuffer::usingExtendedDrawBuffers() const @@ -320,63 +345,43 @@ GLenum Framebuffer::completeness() const { int width = 0; int height = 0; - int colorbufferSize = 0; + unsigned int colorbufferSize = 0; int samples = -1; bool missingAttachment = true; + GLuint clientVersion = mRenderer->getCurrentClientVersion(); for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { - if (mColorbufferTypes[colorAttachment] != GL_NONE) - { - const Renderbuffer *colorbuffer = getColorbuffer(colorAttachment); - - if (!colorbuffer) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment]; + if (colorbuffer) + { if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - if (mColorbufferTypes[colorAttachment] == GL_RENDERBUFFER) + GLenum internalformat = colorbuffer->getInternalFormat(); + // TODO(geofflang): use context's texture caps + const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat); + if (colorbuffer->isTexture()) { - if (!gl::IsColorRenderable(colorbuffer->getInternalFormat())) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - } - else if (IsInternalTextureTarget(mColorbufferTypes[colorAttachment])) - { - GLint internalformat = colorbuffer->getInternalFormat(); - GLenum format = gl::ExtractFormat(internalformat); - - if (IsCompressed(format) || - format == GL_ALPHA || - format == GL_LUMINANCE || - format == GL_LUMINANCE_ALPHA) + if (!formatCaps.renderable) { return GL_FRAMEBUFFER_UNSUPPORTED; } - bool filtering, renderable; - - if ((gl::IsFloat32Format(internalformat) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) || - (gl::IsFloat16Format(internalformat) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable))) - { - return GL_FRAMEBUFFER_UNSUPPORTED; - } - - if (gl::IsDepthTexture(internalformat) || gl::IsStencilTexture(internalformat)) + if (gl::GetDepthBits(internalformat) > 0 || gl::GetStencilBits(internalformat) > 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } else { - UNREACHABLE(); - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + if (!formatCaps.renderable || gl::GetDepthBits(internalformat) > 0 || gl::GetStencilBits(internalformat) > 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } } if (!missingAttachment) @@ -394,16 +399,24 @@ GLenum Framebuffer::completeness() const return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT; } - // all color attachments attachments must have the same number of bitplanes - if (gl::ComputePixelSize(colorbuffer->getInternalFormat()) != colorbufferSize) + // in GLES 2.0, all color attachments attachments must have the same number of bitplanes + // in GLES 3.0, there is no such restriction + if (clientVersion < 3) { - return GL_FRAMEBUFFER_UNSUPPORTED; + if (gl::GetPixelBytes(colorbuffer->getInternalFormat()) != colorbufferSize) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } } // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++) { - if (mColorbufferPointers[colorAttachment].get() == mColorbufferPointers[previousColorAttachment].get()) + const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment]; + + if (previousAttachment && + (colorbuffer->id() == previousAttachment->id() && + colorbuffer->type() == previousAttachment->type())) { return GL_FRAMEBUFFER_UNSUPPORTED; } @@ -414,129 +427,120 @@ GLenum Framebuffer::completeness() const width = colorbuffer->getWidth(); height = colorbuffer->getHeight(); samples = colorbuffer->getSamples(); - colorbufferSize = gl::ComputePixelSize(colorbuffer->getInternalFormat()); + colorbufferSize = gl::GetPixelBytes(colorbuffer->getInternalFormat()); missingAttachment = false; } } } - const Renderbuffer *depthbuffer = NULL; - const Renderbuffer *stencilbuffer = NULL; - - if (mDepthbufferType != GL_NONE) + if (mDepthbuffer) { - depthbuffer = getDepthbuffer(); - - if (!depthbuffer) + if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0) + GLenum internalformat = mDepthbuffer->getInternalFormat(); + // TODO(geofflang): use context's texture caps + const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat); + if (mDepthbuffer->isTexture()) { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + GLenum internalformat = mDepthbuffer->getInternalFormat(); - if (mDepthbufferType == GL_RENDERBUFFER) - { - if (!gl::IsDepthRenderable(depthbuffer->getInternalFormat())) + // depth texture attachments require OES/ANGLE_depth_texture + // TODO(geofflang): use context's extensions + if (!mRenderer->getRendererExtensions().depthTextures) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - } - else if (IsInternalTextureTarget(mDepthbufferType)) - { - GLint internalformat = depthbuffer->getInternalFormat(); - // depth texture attachments require OES/ANGLE_depth_texture - if (!mRenderer->getDepthTextureSupport()) + if (!formatCaps.renderable) { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + return GL_FRAMEBUFFER_UNSUPPORTED; } - if (!gl::IsDepthTexture(internalformat)) + if (gl::GetDepthBits(internalformat) == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } else { - UNREACHABLE(); - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + if (!formatCaps.renderable || gl::GetDepthBits(internalformat) == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } } if (missingAttachment) { - width = depthbuffer->getWidth(); - height = depthbuffer->getHeight(); - samples = depthbuffer->getSamples(); + width = mDepthbuffer->getWidth(); + height = mDepthbuffer->getHeight(); + samples = mDepthbuffer->getSamples(); missingAttachment = false; } - else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight()) + else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight()) { return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; } - else if (samples != depthbuffer->getSamples()) + else if (samples != mDepthbuffer->getSamples()) { return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; } } - if (mStencilbufferType != GL_NONE) + if (mStencilbuffer) { - stencilbuffer = getStencilbuffer(); - - if (!stencilbuffer) + if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0) + GLenum internalformat = mStencilbuffer->getInternalFormat(); + // TODO(geofflang): use context's texture caps + const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat); + if (mStencilbuffer->isTexture()) { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + GLenum internalformat = mStencilbuffer->getInternalFormat(); - if (mStencilbufferType == GL_RENDERBUFFER) - { - if (!gl::IsStencilRenderable(stencilbuffer->getInternalFormat())) + // texture stencil attachments come along as part + // of OES_packed_depth_stencil + OES/ANGLE_depth_texture + // TODO(geofflang): use context's extensions + if (!mRenderer->getRendererExtensions().depthTextures) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - } - else if (IsInternalTextureTarget(mStencilbufferType)) - { - GLint internalformat = stencilbuffer->getInternalFormat(); - // texture stencil attachments come along as part - // of OES_packed_depth_stencil + OES/ANGLE_depth_texture - if (!mRenderer->getDepthTextureSupport()) + if (!formatCaps.renderable) { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + return GL_FRAMEBUFFER_UNSUPPORTED; } - if (!gl::IsStencilTexture(internalformat)) + if (gl::GetStencilBits(internalformat) == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } else { - UNREACHABLE(); - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + if (!formatCaps.renderable || gl::GetStencilBits(internalformat) == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } } if (missingAttachment) { - width = stencilbuffer->getWidth(); - height = stencilbuffer->getHeight(); - samples = stencilbuffer->getSamples(); + width = mStencilbuffer->getWidth(); + height = mStencilbuffer->getHeight(); + samples = mStencilbuffer->getSamples(); missingAttachment = false; } - else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()) + else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight()) { return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; } - else if (samples != stencilbuffer->getSamples()) + else if (samples != mStencilbuffer->getSamples()) { return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; } @@ -544,7 +548,7 @@ GLenum Framebuffer::completeness() const // if we have both a depth and stencil buffer, they must refer to the same object // since we only support packed_depth_stencil and not separate depth and stencil - if (depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer)) + if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil()) { return GL_FRAMEBUFFER_UNSUPPORTED; } @@ -559,17 +563,17 @@ GLenum Framebuffer::completeness() const } DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil) - : Framebuffer(renderer) + : Framebuffer(renderer, 0) { - mColorbufferPointers[0].set(new Renderbuffer(mRenderer, 0, colorbuffer)); + Renderbuffer *colorRenderbuffer = new Renderbuffer(0, colorbuffer); + mColorbuffers[0] = new RenderbufferAttachment(colorRenderbuffer); - Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(mRenderer, 0, depthStencil); - mDepthbufferPointer.set(depthStencilRenderbuffer); - mStencilbufferPointer.set(depthStencilRenderbuffer); + Renderbuffer *depthStencilBuffer = new Renderbuffer(0, depthStencil); - mColorbufferTypes[0] = GL_RENDERBUFFER; - mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE; - mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE; + // Make a new attachment objects to ensure we do not double-delete + // See angle issue 686 + mDepthbuffer = (depthStencilBuffer->getDepthSize() != 0 ? new RenderbufferAttachment(depthStencilBuffer) : NULL); + mStencilbuffer = (depthStencilBuffer->getStencilSize() != 0 ? new RenderbufferAttachment(depthStencilBuffer) : NULL); mDrawBufferStates[0] = GL_BACK; mReadBufferState = GL_BACK; @@ -583,9 +587,9 @@ int Framebuffer::getSamples() const // in this case return the first nonzero sample size for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { - if (mColorbufferTypes[colorAttachment] != GL_NONE) + if (mColorbuffers[colorAttachment]) { - return getColorbuffer(colorAttachment)->getSamples(); + return mColorbuffers[colorAttachment]->getSamples(); } } } @@ -593,6 +597,15 @@ int Framebuffer::getSamples() const return 0; } +bool Framebuffer::hasValidDepthStencil() const +{ + // A valid depth-stencil attachment has the same resource bound to both the + // depth and stencil attachment points. + return (mDepthbuffer && mStencilbuffer && + mDepthbuffer->type() == mStencilbuffer->type() && + mDepthbuffer->id() == mStencilbuffer->id()); +} + GLenum DefaultFramebuffer::completeness() const { // The default framebuffer *must* always be complete, though it may not be @@ -600,4 +613,22 @@ GLenum DefaultFramebuffer::completeness() const return GL_FRAMEBUFFER_COMPLETE; } +FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const +{ + switch (attachment) + { + case GL_BACK: + return getColorbuffer(0); + case GL_DEPTH: + return getDepthbuffer(); + case GL_STENCIL: + return getStencilbuffer(); + case GL_DEPTH_STENCIL: + return getDepthStencilBuffer(); + default: + UNREACHABLE(); + return NULL; + } +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/Framebuffer.h b/src/3rdparty/angle/src/libGLESv2/Framebuffer.h index 50bfd4fd0f..035e16fa45 100644 --- a/src/3rdparty/angle/src/libGLESv2/Framebuffer.h +++ b/src/3rdparty/angle/src/libGLESv2/Framebuffer.h @@ -12,7 +12,7 @@ #include "common/angleutils.h" #include "common/RefCountObject.h" -#include "Constants.h" +#include "constants.h" namespace rx { @@ -21,7 +21,7 @@ class Renderer; namespace gl { -class Renderbuffer; +class FramebufferAttachment; class Colorbuffer; class Depthbuffer; class Stencilbuffer; @@ -30,36 +30,30 @@ class DepthStencilbuffer; class Framebuffer { public: - explicit Framebuffer(rx::Renderer *renderer); + Framebuffer(rx::Renderer *renderer, GLuint id); virtual ~Framebuffer(); - void setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer); - void setDepthbuffer(GLenum type, GLuint depthbuffer); - void setStencilbuffer(GLenum type, GLuint stencilbuffer); + GLuint id() const { return mId; } + + void setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer, GLint level, GLint layer); + void setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer); + void setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer); + void setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer); void detachTexture(GLuint texture); void detachRenderbuffer(GLuint renderbuffer); - unsigned int getRenderTargetSerial(unsigned int colorAttachment) const; - unsigned int getDepthbufferSerial() const; - unsigned int getStencilbufferSerial() const; - - Renderbuffer *getColorbuffer(unsigned int colorAttachment) const; - Renderbuffer *getDepthbuffer() const; - Renderbuffer *getStencilbuffer() const; - Renderbuffer *getDepthOrStencilbuffer() const; - Renderbuffer *getReadColorbuffer() const; + FramebufferAttachment *getColorbuffer(unsigned int colorAttachment) const; + FramebufferAttachment *getDepthbuffer() const; + FramebufferAttachment *getStencilbuffer() const; + FramebufferAttachment *getDepthStencilBuffer() const; + FramebufferAttachment *getDepthOrStencilbuffer() const; + FramebufferAttachment *getReadColorbuffer() const; GLenum getReadColorbufferType() const; - Renderbuffer *getFirstColorbuffer() const; - - GLenum getColorbufferType(unsigned int colorAttachment) const; - GLenum getDepthbufferType() const; - GLenum getStencilbufferType() const; + FramebufferAttachment *getFirstColorbuffer() const; - GLuint getColorbufferHandle(unsigned int colorAttachment) const; - GLuint getDepthbufferHandle() const; - GLuint getStencilbufferHandle() const; + virtual FramebufferAttachment *getAttachment(GLenum attachment) const; GLenum getDrawBufferState(unsigned int colorAttachment) const; void setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer); @@ -71,25 +65,24 @@ class Framebuffer bool usingExtendedDrawBuffers() const; virtual GLenum completeness() const; + bool hasValidDepthStencil() const; protected: - GLenum mColorbufferTypes[IMPLEMENTATION_MAX_DRAW_BUFFERS]; - BindingPointer<Renderbuffer> mColorbufferPointers[IMPLEMENTATION_MAX_DRAW_BUFFERS]; - GLenum mDrawBufferStates[IMPLEMENTATION_MAX_DRAW_BUFFERS]; - GLenum mReadBufferState; + rx::Renderer *mRenderer; - GLenum mDepthbufferType; - BindingPointer<Renderbuffer> mDepthbufferPointer; + GLuint mId; - GLenum mStencilbufferType; - BindingPointer<Renderbuffer> mStencilbufferPointer; + FramebufferAttachment *mColorbuffers[IMPLEMENTATION_MAX_DRAW_BUFFERS]; + GLenum mDrawBufferStates[IMPLEMENTATION_MAX_DRAW_BUFFERS]; + GLenum mReadBufferState; - rx::Renderer *mRenderer; + FramebufferAttachment *mDepthbuffer; + FramebufferAttachment *mStencilbuffer; - private: +private: DISALLOW_COPY_AND_ASSIGN(Framebuffer); - Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle) const; + FramebufferAttachment *createAttachment(GLenum type, GLuint handle, GLint level, GLint layer) const; }; class DefaultFramebuffer : public Framebuffer @@ -98,6 +91,7 @@ class DefaultFramebuffer : public Framebuffer DefaultFramebuffer(rx::Renderer *Renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil); virtual GLenum completeness() const; + virtual FramebufferAttachment *getAttachment(GLenum attachment) const; private: DISALLOW_COPY_AND_ASSIGN(DefaultFramebuffer); diff --git a/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.cpp b/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.cpp new file mode 100644 index 0000000000..5855301c97 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.cpp @@ -0,0 +1,495 @@ +#include "precompiled.h" +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// FramebufferAttachment.cpp: the gl::FramebufferAttachment class and its derived classes +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#include "libGLESv2/FramebufferAttachment.h" +#include "libGLESv2/renderer/RenderTarget.h" + +#include "libGLESv2/Texture.h" +#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/d3d/TextureStorage.h" +#include "common/utilities.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/Renderbuffer.h" + +namespace gl +{ + +////// FramebufferAttachment Implementation ////// + +FramebufferAttachment::FramebufferAttachment() +{ +} + +FramebufferAttachment::~FramebufferAttachment() +{ +} + +GLuint FramebufferAttachment::getRedSize() const +{ + return (gl::GetRedBits(getInternalFormat()) > 0) ? gl::GetRedBits(getActualFormat()) : 0; +} + +GLuint FramebufferAttachment::getGreenSize() const +{ + return (gl::GetGreenBits(getInternalFormat()) > 0) ? gl::GetGreenBits(getActualFormat()) : 0; +} + +GLuint FramebufferAttachment::getBlueSize() const +{ + return (gl::GetBlueBits(getInternalFormat()) > 0) ? gl::GetBlueBits(getActualFormat()) : 0; +} + +GLuint FramebufferAttachment::getAlphaSize() const +{ + return (gl::GetAlphaBits(getInternalFormat()) > 0) ? gl::GetAlphaBits(getActualFormat()) : 0; +} + +GLuint FramebufferAttachment::getDepthSize() const +{ + return (gl::GetDepthBits(getInternalFormat()) > 0) ? gl::GetDepthBits(getActualFormat()) : 0; +} + +GLuint FramebufferAttachment::getStencilSize() const +{ + return (gl::GetStencilBits(getInternalFormat()) > 0) ? gl::GetStencilBits(getActualFormat()) : 0; +} + +GLenum FramebufferAttachment::getComponentType() const +{ + return gl::GetComponentType(getActualFormat()); +} + +GLenum FramebufferAttachment::getColorEncoding() const +{ + return gl::GetColorEncoding(getActualFormat()); +} + +bool FramebufferAttachment::isTexture() const +{ + return (type() != GL_RENDERBUFFER); +} + +///// Texture2DAttachment Implementation //////// + +Texture2DAttachment::Texture2DAttachment(Texture2D *texture, GLint level) : mLevel(level) +{ + mTexture2D.set(texture); +} + +Texture2DAttachment::~Texture2DAttachment() +{ + mTexture2D.set(NULL); +} + +rx::RenderTarget *Texture2DAttachment::getRenderTarget() +{ + return mTexture2D->getRenderTarget(mLevel); +} + +rx::RenderTarget *Texture2DAttachment::getDepthStencil() +{ + return mTexture2D->getDepthSencil(mLevel); +} + +rx::TextureStorage *Texture2DAttachment::getTextureStorage() +{ + return mTexture2D->getNativeTexture()->getStorageInstance(); +} + +GLsizei Texture2DAttachment::getWidth() const +{ + return mTexture2D->getWidth(mLevel); +} + +GLsizei Texture2DAttachment::getHeight() const +{ + return mTexture2D->getHeight(mLevel); +} + +GLenum Texture2DAttachment::getInternalFormat() const +{ + return mTexture2D->getInternalFormat(mLevel); +} + +GLenum Texture2DAttachment::getActualFormat() const +{ + return mTexture2D->getActualFormat(mLevel); +} + +GLsizei Texture2DAttachment::getSamples() const +{ + return 0; +} + +unsigned int Texture2DAttachment::getSerial() const +{ + return mTexture2D->getRenderTargetSerial(mLevel); +} + +GLuint Texture2DAttachment::id() const +{ + return mTexture2D->id(); +} + +GLenum Texture2DAttachment::type() const +{ + return GL_TEXTURE_2D; +} + +GLint Texture2DAttachment::mipLevel() const +{ + return mLevel; +} + +GLint Texture2DAttachment::layer() const +{ + return 0; +} + +unsigned int Texture2DAttachment::getTextureSerial() const +{ + return mTexture2D->getTextureSerial(); +} + +///// TextureCubeMapAttachment Implementation //////// + +TextureCubeMapAttachment::TextureCubeMapAttachment(TextureCubeMap *texture, GLenum faceTarget, GLint level) + : mFaceTarget(faceTarget), mLevel(level) +{ + mTextureCubeMap.set(texture); +} + +TextureCubeMapAttachment::~TextureCubeMapAttachment() +{ + mTextureCubeMap.set(NULL); +} + +rx::RenderTarget *TextureCubeMapAttachment::getRenderTarget() +{ + return mTextureCubeMap->getRenderTarget(mFaceTarget, mLevel); +} + +rx::RenderTarget *TextureCubeMapAttachment::getDepthStencil() +{ + return mTextureCubeMap->getDepthStencil(mFaceTarget, mLevel); +} + +rx::TextureStorage *TextureCubeMapAttachment::getTextureStorage() +{ + return mTextureCubeMap->getNativeTexture()->getStorageInstance(); +} + +GLsizei TextureCubeMapAttachment::getWidth() const +{ + return mTextureCubeMap->getWidth(mFaceTarget, mLevel); +} + +GLsizei TextureCubeMapAttachment::getHeight() const +{ + return mTextureCubeMap->getHeight(mFaceTarget, mLevel); +} + +GLenum TextureCubeMapAttachment::getInternalFormat() const +{ + return mTextureCubeMap->getInternalFormat(mFaceTarget, mLevel); +} + +GLenum TextureCubeMapAttachment::getActualFormat() const +{ + return mTextureCubeMap->getActualFormat(mFaceTarget, mLevel); +} + +GLsizei TextureCubeMapAttachment::getSamples() const +{ + return 0; +} + +unsigned int TextureCubeMapAttachment::getSerial() const +{ + return mTextureCubeMap->getRenderTargetSerial(mFaceTarget, mLevel); +} + +GLuint TextureCubeMapAttachment::id() const +{ + return mTextureCubeMap->id(); +} + +GLenum TextureCubeMapAttachment::type() const +{ + return mFaceTarget; +} + +GLint TextureCubeMapAttachment::mipLevel() const +{ + return mLevel; +} + +GLint TextureCubeMapAttachment::layer() const +{ + return 0; +} + +unsigned int TextureCubeMapAttachment::getTextureSerial() const +{ + return mTextureCubeMap->getTextureSerial(); +} + +///// Texture3DAttachment Implementation //////// + +Texture3DAttachment::Texture3DAttachment(Texture3D *texture, GLint level, GLint layer) + : mLevel(level), mLayer(layer) +{ + mTexture3D.set(texture); +} + +Texture3DAttachment::~Texture3DAttachment() +{ + mTexture3D.set(NULL); +} + +rx::RenderTarget *Texture3DAttachment::getRenderTarget() +{ + return mTexture3D->getRenderTarget(mLevel, mLayer); +} + +rx::RenderTarget *Texture3DAttachment::getDepthStencil() +{ + return mTexture3D->getDepthStencil(mLevel, mLayer); +} + +rx::TextureStorage *Texture3DAttachment::getTextureStorage() +{ + return mTexture3D->getNativeTexture()->getStorageInstance(); +} + +GLsizei Texture3DAttachment::getWidth() const +{ + return mTexture3D->getWidth(mLevel); +} + +GLsizei Texture3DAttachment::getHeight() const +{ + return mTexture3D->getHeight(mLevel); +} + +GLenum Texture3DAttachment::getInternalFormat() const +{ + return mTexture3D->getInternalFormat(mLevel); +} + +GLenum Texture3DAttachment::getActualFormat() const +{ + return mTexture3D->getActualFormat(mLevel); +} + +GLsizei Texture3DAttachment::getSamples() const +{ + return 0; +} + +unsigned int Texture3DAttachment::getSerial() const +{ + return mTexture3D->getRenderTargetSerial(mLevel, mLayer); +} + +GLuint Texture3DAttachment::id() const +{ + return mTexture3D->id(); +} + +GLenum Texture3DAttachment::type() const +{ + return GL_TEXTURE_3D; +} + +GLint Texture3DAttachment::mipLevel() const +{ + return mLevel; +} + +GLint Texture3DAttachment::layer() const +{ + return mLayer; +} + +unsigned int Texture3DAttachment::getTextureSerial() const +{ + return mTexture3D->getTextureSerial(); +} + +////// Texture2DArrayAttachment Implementation ////// + +Texture2DArrayAttachment::Texture2DArrayAttachment(Texture2DArray *texture, GLint level, GLint layer) + : mLevel(level), mLayer(layer) +{ + mTexture2DArray.set(texture); +} + +Texture2DArrayAttachment::~Texture2DArrayAttachment() +{ + mTexture2DArray.set(NULL); +} + +rx::RenderTarget *Texture2DArrayAttachment::getRenderTarget() +{ + return mTexture2DArray->getRenderTarget(mLevel, mLayer); +} + +rx::RenderTarget *Texture2DArrayAttachment::getDepthStencil() +{ + return mTexture2DArray->getDepthStencil(mLevel, mLayer); +} + +rx::TextureStorage *Texture2DArrayAttachment::getTextureStorage() +{ + return mTexture2DArray->getNativeTexture()->getStorageInstance(); +} + +GLsizei Texture2DArrayAttachment::getWidth() const +{ + return mTexture2DArray->getWidth(mLevel); +} + +GLsizei Texture2DArrayAttachment::getHeight() const +{ + return mTexture2DArray->getHeight(mLevel); +} + +GLenum Texture2DArrayAttachment::getInternalFormat() const +{ + return mTexture2DArray->getInternalFormat(mLevel); +} + +GLenum Texture2DArrayAttachment::getActualFormat() const +{ + return mTexture2DArray->getActualFormat(mLevel); +} + +GLsizei Texture2DArrayAttachment::getSamples() const +{ + return 0; +} + +unsigned int Texture2DArrayAttachment::getSerial() const +{ + return mTexture2DArray->getRenderTargetSerial(mLevel, mLayer); +} + +GLuint Texture2DArrayAttachment::id() const +{ + return mTexture2DArray->id(); +} + +GLenum Texture2DArrayAttachment::type() const +{ + return GL_TEXTURE_2D_ARRAY; +} + +GLint Texture2DArrayAttachment::mipLevel() const +{ + return mLevel; +} + +GLint Texture2DArrayAttachment::layer() const +{ + return mLayer; +} + +unsigned int Texture2DArrayAttachment::getTextureSerial() const +{ + return mTexture2DArray->getTextureSerial(); +} + +////// RenderbufferAttachment Implementation ////// + +RenderbufferAttachment::RenderbufferAttachment(Renderbuffer *renderbuffer) +{ + ASSERT(renderbuffer); + mRenderbuffer.set(renderbuffer); +} + +RenderbufferAttachment::~RenderbufferAttachment() +{ + mRenderbuffer.set(NULL); +} + +rx::RenderTarget *RenderbufferAttachment::getRenderTarget() +{ + return mRenderbuffer->getStorage()->getRenderTarget(); +} + +rx::RenderTarget *RenderbufferAttachment::getDepthStencil() +{ + return mRenderbuffer->getStorage()->getDepthStencil(); +} + +rx::TextureStorage *RenderbufferAttachment::getTextureStorage() +{ + UNREACHABLE(); + return NULL; +} + +GLsizei RenderbufferAttachment::getWidth() const +{ + return mRenderbuffer->getWidth(); +} + +GLsizei RenderbufferAttachment::getHeight() const +{ + return mRenderbuffer->getHeight(); +} + +GLenum RenderbufferAttachment::getInternalFormat() const +{ + return mRenderbuffer->getInternalFormat(); +} + +GLenum RenderbufferAttachment::getActualFormat() const +{ + return mRenderbuffer->getActualFormat(); +} + +GLsizei RenderbufferAttachment::getSamples() const +{ + return mRenderbuffer->getStorage()->getSamples(); +} + +unsigned int RenderbufferAttachment::getSerial() const +{ + return mRenderbuffer->getStorage()->getSerial(); +} + +GLuint RenderbufferAttachment::id() const +{ + return mRenderbuffer->id(); +} + +GLenum RenderbufferAttachment::type() const +{ + return GL_RENDERBUFFER; +} + +GLint RenderbufferAttachment::mipLevel() const +{ + return 0; +} + +GLint RenderbufferAttachment::layer() const +{ + return 0; +} + +unsigned int RenderbufferAttachment::getTextureSerial() const +{ + UNREACHABLE(); + return 0; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.h b/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.h new file mode 100644 index 0000000000..18768f9831 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.h @@ -0,0 +1,246 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// FramebufferAttachment.h: Defines the wrapper class gl::FramebufferAttachment, as well as the +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#ifndef LIBGLESV2_FRAMEBUFFERATTACHMENT_H_ +#define LIBGLESV2_FRAMEBUFFERATTACHMENT_H_ + +#include "angle_gl.h" + +#include "common/angleutils.h" +#include "common/RefCountObject.h" + +namespace rx +{ +class Renderer; +class RenderTarget; +class TextureStorage; +} + +namespace gl +{ +class Texture2D; +class TextureCubeMap; +class Texture3D; +class Texture2DArray; +class Renderbuffer; + +// FramebufferAttachment implements a GL framebuffer attachment. +// Attachments are "light" containers, which store pointers to ref-counted GL objects. +// We support GL texture (2D/3D/Cube/2D array) and renderbuffer object attachments. +// Note: Our old naming scheme used the term "Renderbuffer" for both GL renderbuffers and for +// framebuffer attachments, which confused their usage. + +class FramebufferAttachment +{ + public: + FramebufferAttachment(); + virtual ~FramebufferAttachment(); + + // Helper methods + GLuint getRedSize() const; + GLuint getGreenSize() const; + GLuint getBlueSize() const; + GLuint getAlphaSize() const; + GLuint getDepthSize() const; + GLuint getStencilSize() const; + GLenum getComponentType() const; + GLenum getColorEncoding() const; + bool isTexture() const; + + bool isTextureWithId(GLuint textureId) const { return isTexture() && id() == textureId; } + bool isRenderbufferWithId(GLuint renderbufferId) const { return !isTexture() && id() == renderbufferId; } + + // Child class interface + virtual rx::RenderTarget *getRenderTarget() = 0; + virtual rx::RenderTarget *getDepthStencil() = 0; + virtual rx::TextureStorage *getTextureStorage() = 0; + + virtual GLsizei getWidth() const = 0; + virtual GLsizei getHeight() const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual GLenum getActualFormat() const = 0; + virtual GLsizei getSamples() const = 0; + + virtual unsigned int getSerial() const = 0; + + virtual GLuint id() const = 0; + virtual GLenum type() const = 0; + virtual GLint mipLevel() const = 0; + virtual GLint layer() const = 0; + virtual unsigned int getTextureSerial() const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(FramebufferAttachment); +}; + +class Texture2DAttachment : public FramebufferAttachment +{ + public: + Texture2DAttachment(Texture2D *texture, GLint level); + + virtual ~Texture2DAttachment(); + + rx::RenderTarget *getRenderTarget(); + rx::RenderTarget *getDepthStencil(); + rx::TextureStorage *getTextureStorage(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual GLenum getActualFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; + + virtual GLuint id() const; + virtual GLenum type() const; + virtual GLint mipLevel() const; + virtual GLint layer() const; + virtual unsigned int getTextureSerial() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Texture2DAttachment); + + BindingPointer<Texture2D> mTexture2D; + const GLint mLevel; +}; + +class TextureCubeMapAttachment : public FramebufferAttachment +{ + public: + TextureCubeMapAttachment(TextureCubeMap *texture, GLenum faceTarget, GLint level); + + virtual ~TextureCubeMapAttachment(); + + rx::RenderTarget *getRenderTarget(); + rx::RenderTarget *getDepthStencil(); + rx::TextureStorage *getTextureStorage(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual GLenum getActualFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; + + virtual GLuint id() const; + virtual GLenum type() const; + virtual GLint mipLevel() const; + virtual GLint layer() const; + virtual unsigned int getTextureSerial() const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureCubeMapAttachment); + + BindingPointer<TextureCubeMap> mTextureCubeMap; + const GLint mLevel; + const GLenum mFaceTarget; +}; + +class Texture3DAttachment : public FramebufferAttachment +{ + public: + Texture3DAttachment(Texture3D *texture, GLint level, GLint layer); + + virtual ~Texture3DAttachment(); + + rx::RenderTarget *getRenderTarget(); + rx::RenderTarget *getDepthStencil(); + rx::TextureStorage *getTextureStorage(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual GLenum getActualFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; + + virtual GLuint id() const; + virtual GLenum type() const; + virtual GLint mipLevel() const; + virtual GLint layer() const; + virtual unsigned int getTextureSerial() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Texture3DAttachment); + + BindingPointer<Texture3D> mTexture3D; + const GLint mLevel; + const GLint mLayer; +}; + +class Texture2DArrayAttachment : public FramebufferAttachment +{ + public: + Texture2DArrayAttachment(Texture2DArray *texture, GLint level, GLint layer); + + virtual ~Texture2DArrayAttachment(); + + rx::RenderTarget *getRenderTarget(); + rx::RenderTarget *getDepthStencil(); + rx::TextureStorage *getTextureStorage(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual GLenum getActualFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; + + virtual GLuint id() const; + virtual GLenum type() const; + virtual GLint mipLevel() const; + virtual GLint layer() const; + virtual unsigned int getTextureSerial() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Texture2DArrayAttachment); + + BindingPointer<Texture2DArray> mTexture2DArray; + const GLint mLevel; + const GLint mLayer; +}; + +class RenderbufferAttachment : public FramebufferAttachment +{ + public: + RenderbufferAttachment(Renderbuffer *renderbuffer); + + virtual ~RenderbufferAttachment(); + + rx::RenderTarget *getRenderTarget(); + rx::RenderTarget *getDepthStencil(); + rx::TextureStorage *getTextureStorage(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual GLenum getActualFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; + + virtual GLuint id() const; + virtual GLenum type() const; + virtual GLint mipLevel() const; + virtual GLint layer() const; + virtual unsigned int getTextureSerial() const; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment); + + BindingPointer<Renderbuffer> mRenderbuffer; +}; + +} + +#endif // LIBGLESV2_FRAMEBUFFERATTACHMENT_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/HandleAllocator.h b/src/3rdparty/angle/src/libGLESv2/HandleAllocator.h index a92e1684d4..bbded02f99 100644 --- a/src/3rdparty/angle/src/libGLESv2/HandleAllocator.h +++ b/src/3rdparty/angle/src/libGLESv2/HandleAllocator.h @@ -10,8 +10,7 @@ #ifndef LIBGLESV2_HANDLEALLOCATOR_H_ #define LIBGLESV2_HANDLEALLOCATOR_H_ -#define GL_APICALL -#include <GLES2/gl2.h> +#include "angle_gl.h" #include <vector> diff --git a/src/3rdparty/angle/src/libGLESv2/Program.cpp b/src/3rdparty/angle/src/libGLESv2/Program.cpp index c38aa5a61a..8a9fb04800 100644 --- a/src/3rdparty/angle/src/libGLESv2/Program.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Program.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -95,32 +95,36 @@ void InfoLog::append(const char *format, ...) return; } - char info[1024]; - va_list vararg; va_start(vararg, format); - vsnprintf(info, sizeof(info), format, vararg); + size_t infoLength = vsnprintf(NULL, 0, format, vararg); va_end(vararg); - size_t infoLength = strlen(info); + char *logPointer = NULL; if (!mInfoLog) { mInfoLog = new char[infoLength + 2]; - strcpy(mInfoLog, info); - strcpy(mInfoLog + infoLength, "\n"); + logPointer = mInfoLog; } else { - size_t logLength = strlen(mInfoLog); - char *newLog = new char[logLength + infoLength + 2]; + size_t currentlogLength = strlen(mInfoLog); + char *newLog = new char[currentlogLength + infoLength + 2]; strcpy(newLog, mInfoLog); - strcpy(newLog + logLength, info); - strcpy(newLog + logLength + infoLength, "\n"); delete[] mInfoLog; mInfoLog = newLog; + + logPointer = mInfoLog + currentlogLength; } + + va_start(vararg, format); + vsnprintf(logPointer, infoLength, format, vararg); + va_end(vararg); + + logPointer[infoLength] = 0; + strcpy(logPointer + infoLength, "\n"); } void InfoLog::reset() @@ -141,6 +145,8 @@ Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle mLinked = false; mRefCount = 0; mRenderer = renderer; + + resetUniformBlockBindings(); } Program::~Program() @@ -243,9 +249,11 @@ bool Program::link() unlink(false); mInfoLog.reset(); + resetUniformBlockBindings(); mProgramBinary.set(new ProgramBinary(mRenderer)); - mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader); + mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader, + mTransformFeedbackVaryings, mTransformFeedbackBufferMode); return mLinked; } @@ -290,7 +298,7 @@ bool Program::isLinked() return mLinked; } -ProgramBinary* Program::getProgramBinary() +ProgramBinary* Program::getProgramBinary() const { return mProgramBinary.get(); } @@ -522,4 +530,132 @@ bool Program::isValidated() const } } +GLint Program::getActiveUniformBlockCount() +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return static_cast<GLint>(programBinary->getActiveUniformBlockCount()); + } + else + { + return 0; + } +} + +GLint Program::getActiveUniformBlockMaxLength() +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return static_cast<GLint>(programBinary->getActiveUniformBlockMaxLength()); + } + else + { + return 0; + } +} + +void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding) +{ + mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding; +} + +GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const +{ + return mUniformBlockBindings[uniformBlockIndex]; +} + +void Program::resetUniformBlockBindings() +{ + for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++) + { + mUniformBlockBindings[blockId] = 0; + } +} + +void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode) +{ + mTransformFeedbackVaryings.resize(count); + for (GLsizei i = 0; i < count; i++) + { + mTransformFeedbackVaryings[i] = varyings[i]; + } + + mTransformFeedbackBufferMode = bufferMode; +} + +void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary && index < programBinary->getTransformFeedbackVaryingCount()) + { + const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(index); + GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length())); + if (length) + { + *length = lastNameIdx; + } + if (size) + { + *size = varying.size; + } + if (type) + { + *type = varying.type; + } + if (name) + { + memcpy(name, varying.name.c_str(), lastNameIdx); + name[lastNameIdx] = '\0'; + } + } +} + +GLsizei Program::getTransformFeedbackVaryingCount() const +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return static_cast<GLsizei>(programBinary->getTransformFeedbackVaryingCount()); + } + else + { + return 0; + } +} + +GLsizei Program::getTransformFeedbackVaryingMaxLength() const +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + GLsizei maxSize = 0; + for (size_t i = 0; i < programBinary->getTransformFeedbackVaryingCount(); i++) + { + const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(i); + maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1)); + } + + return maxSize; + } + else + { + return 0; + } +} + +GLenum Program::getTransformFeedbackBufferMode() const +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return programBinary->getTransformFeedbackBufferMode(); + } + else + { + return mTransformFeedbackBufferMode; + } +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/Program.h b/src/3rdparty/angle/src/libGLESv2/Program.h index a9db83403d..ce821a470b 100644 --- a/src/3rdparty/angle/src/libGLESv2/Program.h +++ b/src/3rdparty/angle/src/libGLESv2/Program.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -16,6 +16,7 @@ #include "common/angleutils.h" #include "common/RefCountObject.h" #include "libGLESv2/Constants.h" +#include "libGLESv2/ProgramBinary.h" namespace rx { @@ -27,7 +28,6 @@ namespace gl class ResourceManager; class FragmentShader; class VertexShader; -class ProgramBinary; class Shader; extern const char * const g_fakepath; @@ -78,7 +78,7 @@ class Program bool link(); bool isLinked(); bool setProgramBinary(const void *binary, GLsizei length); - ProgramBinary *getProgramBinary(); + ProgramBinary *getProgramBinary() const; int getInfoLogLength() const; void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog); @@ -92,6 +92,18 @@ class Program GLint getActiveUniformCount(); GLint getActiveUniformMaxLength(); + GLint getActiveUniformBlockCount(); + GLint getActiveUniformBlockMaxLength(); + + void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding); + GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const; + + void setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode); + void getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const; + GLsizei getTransformFeedbackVaryingCount() const; + GLsizei getTransformFeedbackVaryingMaxLength() const; + GLenum getTransformFeedbackBufferMode() const; + void addRef(); void release(); unsigned int getRefCount() const; @@ -107,12 +119,18 @@ class Program DISALLOW_COPY_AND_ASSIGN(Program); void unlink(bool destroy = false); + void resetUniformBlockBindings(); FragmentShader *mFragmentShader; VertexShader *mVertexShader; AttributeBindings mAttributeBindings; + GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS]; + + std::vector<std::string> mTransformFeedbackVaryings; + GLuint mTransformFeedbackBufferMode; + BindingPointer<ProgramBinary> mProgramBinary; bool mLinked; bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp index 13c515a594..9fad5fbfc5 100644 --- a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp +++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,50 +10,182 @@ #include "libGLESv2/BinaryStream.h" #include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/Renderbuffer.h" #include "libGLESv2/renderer/ShaderExecutable.h" #include "common/debug.h" #include "common/version.h" -#include "utilities.h" +#include "common/utilities.h" #include "libGLESv2/main.h" #include "libGLESv2/Shader.h" #include "libGLESv2/Program.h" #include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/VertexDataManager.h" +#include "libGLESv2/renderer/d3d/VertexDataManager.h" +#include "libGLESv2/Context.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/DynamicHLSL.h" +#include "common/blocklayout.h" #undef near #undef far namespace gl { -std::string str(int i) + +namespace +{ + +TextureType GetTextureType(GLenum samplerType) { - char buffer[20]; - snprintf(buffer, sizeof(buffer), "%d", i); - return buffer; + switch (samplerType) + { + case GL_SAMPLER_2D: + case GL_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_SAMPLER_2D_SHADOW: + return TEXTURE_2D; + case GL_SAMPLER_3D: + case GL_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_3D: + return TEXTURE_3D; + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_SHADOW: + return TEXTURE_CUBE; + case GL_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + return TEXTURE_CUBE; + case GL_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + return TEXTURE_2D_ARRAY; + default: UNREACHABLE(); + } + + return TEXTURE_2D; } -static rx::D3DWorkaroundType DiscardWorkaround(bool usesDiscard) +unsigned int ParseAndStripArrayIndex(std::string* name) { - return (usesDiscard ? rx::ANGLE_D3D_WORKAROUND_SM3_OPTIMIZER : rx::ANGLE_D3D_WORKAROUND_NONE); + unsigned int subscript = GL_INVALID_INDEX; + + // Strip any trailing array operator and retrieve the subscript + size_t open = name->find_last_of('['); + size_t close = name->find_last_of(']'); + if (open != std::string::npos && close == name->length() - 1) + { + subscript = atoi(name->substr(open + 1).c_str()); + name->erase(open); + } + + return subscript; } -UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index) +void GetInputLayoutFromShader(const std::vector<sh::Attribute> &shaderAttributes, VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]) +{ + size_t layoutIndex = 0; + for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) + { + ASSERT(layoutIndex < MAX_VERTEX_ATTRIBS); + + const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex]; + + if (shaderAttr.type != GL_NONE) + { + GLenum transposedType = TransposeMatrixType(shaderAttr.type); + + for (size_t rowIndex = 0; static_cast<int>(rowIndex) < VariableRowCount(transposedType); rowIndex++, layoutIndex++) + { + VertexFormat *defaultFormat = &inputLayout[layoutIndex]; + + defaultFormat->mType = VariableComponentType(transposedType); + defaultFormat->mNormalized = false; + defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool + defaultFormat->mComponents = VariableColumnCount(transposedType); + } + } + } +} + +} + +VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index) : name(name), element(element), index(index) { } -unsigned int ProgramBinary::mCurrentSerial = 1; +ProgramBinary::VertexExecutable::VertexExecutable(const VertexFormat inputLayout[], + const GLenum signature[], + rx::ShaderExecutable *shaderExecutable) + : mShaderExecutable(shaderExecutable) +{ + for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + mInputs[attributeIndex] = inputLayout[attributeIndex]; + mSignature[attributeIndex] = signature[attributeIndex]; + } +} -ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial()) +ProgramBinary::VertexExecutable::~VertexExecutable() { - mPixelExecutable = NULL; - mVertexExecutable = NULL; - mGeometryExecutable = NULL; + SafeDelete(mShaderExecutable); +} - mValidated = false; +bool ProgramBinary::VertexExecutable::matchesSignature(const GLenum signature[]) const +{ + for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (mSignature[attributeIndex] != signature[attributeIndex]) + { + return false; + } + } + + return true; +} + +ProgramBinary::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature, rx::ShaderExecutable *shaderExecutable) + : mOutputSignature(outputSignature), + mShaderExecutable(shaderExecutable) +{ +} + +ProgramBinary::PixelExecutable::~PixelExecutable() +{ + SafeDelete(mShaderExecutable); +} +LinkedVarying::LinkedVarying() +{ +} + +LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName, + unsigned int semanticIndex, unsigned int semanticIndexCount) + : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount) +{ +} + +unsigned int ProgramBinary::mCurrentSerial = 1; + +ProgramBinary::ProgramBinary(rx::Renderer *renderer) + : RefCountObject(0), + mRenderer(renderer), + mDynamicHLSL(NULL), + mVertexWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE), + mPixelWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE), + mGeometryExecutable(NULL), + mUsedVertexSamplerRange(0), + mUsedPixelSamplerRange(0), + mUsesPointSize(false), + mShaderVersion(100), + mDirtySamplerMapping(true), + mVertexUniformStorage(NULL), + mFragmentUniformStorage(NULL), + mValidated(false), + mSerial(issueSerial()) +{ for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) { mSemanticIndex[index] = -1; @@ -69,27 +201,13 @@ ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefC mSamplersVS[index].active = false; } - mUsedVertexSamplerRange = 0; - mUsedPixelSamplerRange = 0; - mUsesPointSize = false; + mDynamicHLSL = new DynamicHLSL(renderer); } ProgramBinary::~ProgramBinary() { - delete mPixelExecutable; - mPixelExecutable = NULL; - - delete mVertexExecutable; - mVertexExecutable = NULL; - - delete mGeometryExecutable; - mGeometryExecutable = NULL; - - while (!mUniforms.empty()) - { - delete mUniforms.back(); - mUniforms.pop_back(); - } + reset(); + SafeDelete(mDynamicHLSL); } unsigned int ProgramBinary::getSerial() const @@ -97,22 +215,108 @@ unsigned int ProgramBinary::getSerial() const return mSerial; } +int ProgramBinary::getShaderVersion() const +{ + return mShaderVersion; +} + unsigned int ProgramBinary::issueSerial() { return mCurrentSerial++; } -rx::ShaderExecutable *ProgramBinary::getPixelExecutable() +rx::ShaderExecutable *ProgramBinary::getPixelExecutableForFramebuffer(const Framebuffer *fbo) { - return mPixelExecutable; + std::vector<GLenum> outputs(IMPLEMENTATION_MAX_DRAW_BUFFERS); + for (size_t outputIndex = 0; outputIndex < IMPLEMENTATION_MAX_DRAW_BUFFERS; outputIndex++) + { + if (fbo->getColorbuffer(outputIndex) != NULL) + { + // Always output floats for now + outputs[outputIndex] = GL_FLOAT; + } + else + { + outputs[outputIndex] = GL_NONE; + } + } + + return getPixelExecutableForOutputLayout(outputs); } -rx::ShaderExecutable *ProgramBinary::getVertexExecutable() +rx::ShaderExecutable *ProgramBinary::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature) { - return mVertexExecutable; + for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) + { + if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature)) + { + return mPixelExecutables[executableIndex]->shaderExecutable(); + } + } + + std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth, + outputSignature); + + // Generate new pixel executable + InfoLog tempInfoLog; + rx::ShaderExecutable *pixelExecutable = mRenderer->compileToExecutable(tempInfoLog, finalPixelHLSL.c_str(), rx::SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mPixelWorkarounds); + + if (!pixelExecutable) + { + std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3); + tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]); + } + else + { + mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable)); + } + + return pixelExecutable; } -rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() +rx::ShaderExecutable *ProgramBinary::getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]) +{ + GLenum signature[MAX_VERTEX_ATTRIBS]; + mDynamicHLSL->getInputLayoutSignature(inputLayout, signature); + + for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) + { + if (mVertexExecutables[executableIndex]->matchesSignature(signature)) + { + return mVertexExecutables[executableIndex]->shaderExecutable(); + } + } + + // Generate new dynamic layout with attribute conversions + std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes); + + // Generate new vertex executable + InfoLog tempInfoLog; + rx::ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(tempInfoLog, finalVertexHLSL.c_str(), + rx::SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mVertexWorkarounds); + + if (!vertexExecutable) + { + std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3); + tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]); + } + else + { + mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable)); + } + + return vertexExecutable; +} + +rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() const { return mGeometryExecutable; } @@ -136,7 +340,7 @@ GLuint ProgramBinary::getAttributeLocation(const char *name) int ProgramBinary::getSemanticIndex(int attributeIndex) { ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS); - + return mSemanticIndex[attributeIndex]; } @@ -179,7 +383,7 @@ GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerInd switch (type) { case SAMPLER_PIXEL: - ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0])); + ASSERT(samplerIndex < ArraySize(mSamplersPS)); if (mSamplersPS[samplerIndex].active) { @@ -187,7 +391,7 @@ GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerInd } break; case SAMPLER_VERTEX: - ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0])); + ASSERT(samplerIndex < ArraySize(mSamplersVS)); if (mSamplersVS[samplerIndex].active) { @@ -212,11 +416,11 @@ TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int switch (type) { case SAMPLER_PIXEL: - ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0])); + ASSERT(samplerIndex < ArraySize(mSamplersPS)); ASSERT(mSamplersPS[samplerIndex].active); return mSamplersPS[samplerIndex].textureType; case SAMPLER_VERTEX: - ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0])); + ASSERT(samplerIndex < ArraySize(mSamplersVS)); ASSERT(mSamplersVS[samplerIndex].active); return mSamplersVS[samplerIndex].textureType; default: UNREACHABLE(); @@ -227,402 +431,352 @@ TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int GLint ProgramBinary::getUniformLocation(std::string name) { - unsigned int subscript = 0; - - // Strip any trailing array operator and retrieve the subscript - size_t open = name.find_last_of('['); - size_t close = name.find_last_of(']'); - if (open != std::string::npos && close == name.length() - 1) - { - subscript = atoi(name.substr(open + 1).c_str()); - name.erase(open); - } + unsigned int subscript = ParseAndStripArrayIndex(&name); unsigned int numUniforms = mUniformIndex.size(); for (unsigned int location = 0; location < numUniforms; location++) { - if (mUniformIndex[location].name == name && - mUniformIndex[location].element == subscript) + if (mUniformIndex[location].name == name) { - return location; + const int index = mUniformIndex[location].index; + const bool isArray = mUniforms[index]->isArray(); + + if ((isArray && mUniformIndex[location].element == subscript) || + (subscript == GL_INVALID_INDEX)) + { + return location; + } } } return -1; } -bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) +GLuint ProgramBinary::getUniformIndex(std::string name) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - int elementCount = targetUniform->elementCount(); - - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + unsigned int subscript = ParseAndStripArrayIndex(&name); - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - - if (targetUniform->type == GL_FLOAT) + // The app is not allowed to specify array indices other than 0 for arrays of basic types + if (subscript != 0 && subscript != GL_INVALID_INDEX) { - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - target[0] = v[0]; - target[1] = 0; - target[2] = 0; - target[3] = 0; - target += 4; - v += 1; - } + return GL_INVALID_INDEX; } - else if (targetUniform->type == GL_BOOL) - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - for (int i = 0; i < count; i++) + unsigned int numUniforms = mUniforms.size(); + for (unsigned int index = 0; index < numUniforms; index++) + { + if (mUniforms[index]->name == name) { - boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[1] = GL_FALSE; - boolParams[2] = GL_FALSE; - boolParams[3] = GL_FALSE; - boolParams += 4; - v += 1; + if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX) + { + return index; + } } } - else - { - return false; - } - return true; + return GL_INVALID_INDEX; } -bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +GLuint ProgramBinary::getUniformBlockIndex(std::string name) { - if (location < 0 || location >= (int)mUniformIndex.size()) + unsigned int subscript = ParseAndStripArrayIndex(&name); + + unsigned int numUniformBlocks = mUniformBlocks.size(); + for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++) { - return false; + const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex]; + if (uniformBlock.name == name) + { + const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0); + if (subscript == uniformBlock.elementIndex || arrayElementZero) + { + return blockIndex; + } + } } - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - int elementCount = targetUniform->elementCount(); + return GL_INVALID_INDEX; +} - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION +UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex) +{ + ASSERT(blockIndex < mUniformBlocks.size()); + return mUniformBlocks[blockIndex]; +} - count = std::min(elementCount - (int)mUniformIndex[location].element, count); +GLint ProgramBinary::getFragDataLocation(const char *name) const +{ + std::string baseName(name); + unsigned int arrayIndex; + arrayIndex = ParseAndStripArrayIndex(&baseName); - if (targetUniform->type == GL_FLOAT_VEC2) + for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++) { - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + const VariableLocation &outputVariable = locationIt->second; - for (int i = 0; i < count; i++) + if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element)) { - target[0] = v[0]; - target[1] = v[1]; - target[2] = 0; - target[3] = 0; - target += 4; - v += 2; + return static_cast<GLint>(locationIt->first); } } - else if (targetUniform->type == GL_BOOL_VEC2) - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - for (int i = 0; i < count; i++) - { - boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[2] = GL_FALSE; - boolParams[3] = GL_FALSE; - boolParams += 4; - v += 2; - } - } - else - { - return false; - } + return -1; +} - return true; +size_t ProgramBinary::getTransformFeedbackVaryingCount() const +{ + return mTransformFeedbackLinkedVaryings.size(); } -bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } + return mTransformFeedbackLinkedVaryings[idx]; +} - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; +GLenum ProgramBinary::getTransformFeedbackBufferMode() const +{ + return mTransformFeedbackBufferMode; +} - int elementCount = targetUniform->elementCount(); +template <typename T> +static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag) +{ + ASSERT(dest != NULL); + ASSERT(dirtyFlag != NULL); - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0); + *dest = source; +} + +template <typename T> +void ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType) +{ + const int components = VariableComponentCount(targetUniformType); + const GLenum targetBoolType = VariableBoolVectorType(targetUniformType); + + LinkedUniform *targetUniform = getUniformByLocation(location); + + int elementCount = targetUniform->elementCount(); count = std::min(elementCount - (int)mUniformIndex[location].element, count); - if (targetUniform->type == GL_FLOAT_VEC3) + if (targetUniform->type == targetUniformType) { - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4; for (int i = 0; i < count; i++) { - target[0] = v[0]; - target[1] = v[1]; - target[2] = v[2]; - target[3] = 0; + for (int c = 0; c < components; c++) + { + SetIfDirty(target + c, v[c], &targetUniform->dirty); + } + for (int c = components; c < 4; c++) + { + SetIfDirty(target + c, T(0), &targetUniform->dirty); + } target += 4; - v += 3; + v += components; } } - else if (targetUniform->type == GL_BOOL_VEC3) + else if (targetUniform->type == targetBoolType) { GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; for (int i = 0; i < count; i++) { - boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[3] = GL_FALSE; + for (int c = 0; c < components; c++) + { + SetIfDirty(boolParams + c, (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty); + } + for (int c = components; c < 4; c++) + { + SetIfDirty(boolParams + c, GL_FALSE, &targetUniform->dirty); + } boolParams += 4; - v += 3; + v += components; } } - else - { - return false; - } - - return true; + else UNREACHABLE(); } -bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +void ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } + setUniform(location, count, v, GL_FLOAT); +} - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; +void ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC2); +} - int elementCount = targetUniform->elementCount(); +void ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC3); +} - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION +void ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC4); +} - count = std::min(elementCount - (int)mUniformIndex[location].element, count); +template<typename T> +bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) +{ + bool dirty = false; + int copyWidth = std::min(targetHeight, srcWidth); + int copyHeight = std::min(targetWidth, srcHeight); - if (targetUniform->type == GL_FLOAT_VEC4) + for (int x = 0; x < copyWidth; x++) { - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) + for (int y = 0; y < copyHeight; y++) { - target[0] = v[0]; - target[1] = v[1]; - target[2] = v[2]; - target[3] = v[3]; - target += 4; - v += 4; + SetIfDirty(target + (x * targetWidth + y), static_cast<T>(value[y * srcWidth + x]), &dirty); } } - else if (targetUniform->type == GL_BOOL_VEC4) + // clear unfilled right side + for (int y = 0; y < copyWidth; y++) { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) + for (int x = copyHeight; x < targetWidth; x++) { - boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams[3] = (v[3] == 0.0f) ? GL_FALSE : GL_TRUE; - boolParams += 4; - v += 4; + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); } } - else + // clear unfilled bottom. + for (int y = copyWidth; y < targetHeight; y++) { - return false; + for (int x = 0; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); + } } - return true; + return dirty; } -template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight> -void transposeMatrix(T *target, const GLfloat *value) +template<typename T> +bool expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) { + bool dirty = false; int copyWidth = std::min(targetWidth, srcWidth); int copyHeight = std::min(targetHeight, srcHeight); - for (int x = 0; x < copyWidth; x++) + for (int y = 0; y < copyHeight; y++) { - for (int y = 0; y < copyHeight; y++) + for (int x = 0; x < copyWidth; x++) { - target[x * targetWidth + y] = (T)value[y * srcWidth + x]; + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(value[y * srcWidth + x]), &dirty); } } // clear unfilled right side for (int y = 0; y < copyHeight; y++) { - for (int x = srcWidth; x < targetWidth; x++) + for (int x = copyWidth; x < targetWidth; x++) { - target[y * targetWidth + x] = (T)0; + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); } } // clear unfilled bottom. - for (int y = srcHeight; y < targetHeight; y++) + for (int y = copyHeight; y < targetHeight; y++) { for (int x = 0; x < targetWidth; x++) { - target[y * targetWidth + x] = (T)0; + SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty); } } + + return dirty; } -bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) +template <int cols, int rows> +void ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - if (targetUniform->type != GL_FLOAT_MAT2) - { - return false; - } + LinkedUniform *targetUniform = getUniformByLocation(location); int elementCount = targetUniform->elementCount(); - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8; + const unsigned int targetMatrixStride = (4 * rows); + GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride); for (int i = 0; i < count; i++) { - transposeMatrix<GLfloat,4,2,2,2>(target, value); - target += 8; - value += 4; + // Internally store matrices as transposed versions to accomodate HLSL matrix indexing + if (transpose == GL_FALSE) + { + targetUniform->dirty = transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols) || targetUniform->dirty; + } + else + { + targetUniform->dirty = expandMatrix<GLfloat>(target, value, 4, rows, cols, rows) || targetUniform->dirty; + } + target += targetMatrixStride; + value += cols * rows; } - - return true; } -bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) +void ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - if (targetUniform->type != GL_FLOAT_MAT3) - { - return false; - } - - int elementCount = targetUniform->elementCount(); - - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12; - - for (int i = 0; i < count; i++) - { - transposeMatrix<GLfloat,4,3,3,3>(target, value); - target += 12; - value += 9; - } - - return true; + setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); } - -bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) +void ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; + setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); +} - if (targetUniform->type != GL_FLOAT_MAT4) - { - return false; - } +void ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); +} - int elementCount = targetUniform->elementCount(); +void ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); +} - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION +void ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); +} - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16); +void ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); +} - for (int i = 0; i < count; i++) - { - transposeMatrix<GLfloat,4,4,4,4>(target, value); - target += 16; - value += 16; - } +void ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); +} - return true; +void ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); } -bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) +void ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } + setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3); +} - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; +void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) +{ + LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index]; int elementCount = targetUniform->elementCount(); - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - if (targetUniform->type == GL_INT || - targetUniform->type == GL_SAMPLER_2D || - targetUniform->type == GL_SAMPLER_CUBE) + if (targetUniform->type == GL_INT || IsSampler(targetUniform->type)) { GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; for (int i = 0; i < count; i++) { - target[0] = v[0]; - target[1] = 0; - target[2] = 0; - target[3] = 0; + SetIfDirty(target + 0, v[0], &targetUniform->dirty); + SetIfDirty(target + 1, 0, &targetUniform->dirty); + SetIfDirty(target + 2, 0, &targetUniform->dirty); + SetIfDirty(target + 3, 0, &targetUniform->dirty); target += 4; v += 1; } @@ -633,317 +787,157 @@ bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) for (int i = 0; i < count; i++) { - boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; - boolParams[1] = GL_FALSE; - boolParams[2] = GL_FALSE; - boolParams[3] = GL_FALSE; + SetIfDirty(boolParams + 0, (v[0] == 0) ? GL_FALSE : GL_TRUE, &targetUniform->dirty); + SetIfDirty(boolParams + 1, GL_FALSE, &targetUniform->dirty); + SetIfDirty(boolParams + 2, GL_FALSE, &targetUniform->dirty); + SetIfDirty(boolParams + 3, GL_FALSE, &targetUniform->dirty); boolParams += 4; v += 1; } } - else + else UNREACHABLE(); + + // Set a special flag if we change a sampler uniform + if (IsSampler(targetUniform->type) && + (memcmp(targetUniform->data, v, sizeof(GLint)) != 0)) { - return false; + mDirtySamplerMapping = true; } - - return true; } -bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) +void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - int elementCount = targetUniform->elementCount(); - - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - - if (targetUniform->type == GL_INT_VEC2) - { - GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - target[0] = v[0]; - target[1] = v[1]; - target[2] = 0; - target[3] = 0; - target += 4; - v += 2; - } - } - else if (targetUniform->type == GL_BOOL_VEC2) - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE; - boolParams[2] = GL_FALSE; - boolParams[3] = GL_FALSE; - boolParams += 4; - v += 2; - } - } - else - { - return false; - } - - return true; + setUniform(location, count, v, GL_INT_VEC2); } -bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) +void ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - int elementCount = targetUniform->elementCount(); - - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - - if (targetUniform->type == GL_INT_VEC3) - { - GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - target[0] = v[0]; - target[1] = v[1]; - target[2] = v[2]; - target[3] = 0; - target += 4; - v += 3; - } - } - else if (targetUniform->type == GL_BOOL_VEC3) - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE; - boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE; - boolParams[3] = GL_FALSE; - boolParams += 4; - v += 3; - } - } - else - { - return false; - } - - return true; + setUniform(location, count, v, GL_INT_VEC3); } -bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) +void ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } - - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; - targetUniform->dirty = true; - - int elementCount = targetUniform->elementCount(); - - if (elementCount == 1 && count > 1) - return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - - if (targetUniform->type == GL_INT_VEC4) - { - GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + setUniform(location, count, v, GL_INT_VEC4); +} - for (int i = 0; i < count; i++) - { - target[0] = v[0]; - target[1] = v[1]; - target[2] = v[2]; - target[3] = v[3]; - target += 4; - v += 4; - } - } - else if (targetUniform->type == GL_BOOL_VEC4) - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; +void ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT); +} - for (int i = 0; i < count; i++) - { - boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE; - boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE; - boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE; - boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE; - boolParams += 4; - v += 4; - } - } - else - { - return false; - } +void ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC2); +} - return true; +void ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC3); } -bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params) +void ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) { - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } + setUniform(location, count, v, GL_UNSIGNED_INT_VEC4); +} - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; +template <typename T> +bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType) +{ + LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index]; // sized queries -- ensure the provided buffer is large enough if (bufSize) { - int requiredBytes = UniformExternalSize(targetUniform->type); + int requiredBytes = VariableExternalSize(targetUniform->type); if (*bufSize < requiredBytes) { return false; } } - switch (targetUniform->type) + if (IsMatrixType(targetUniform->type)) { - case GL_FLOAT_MAT2: - transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); - break; - case GL_FLOAT_MAT3: - transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); - break; - case GL_FLOAT_MAT4: - transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); - break; - default: + const int rows = VariableRowCount(targetUniform->type); + const int cols = VariableColumnCount(targetUniform->type); + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows); + } + else if (uniformType == VariableComponentType(targetUniform->type)) + { + unsigned int size = VariableComponentCount(targetUniform->type); + memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T), + size * sizeof(T)); + } + else + { + unsigned int size = VariableComponentCount(targetUniform->type); + switch (VariableComponentType(targetUniform->type)) { - unsigned int size = UniformComponentCount(targetUniform->type); - - switch (UniformComponentType(targetUniform->type)) + case GL_BOOL: { - case GL_BOOL: - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - for (unsigned int i = 0; i < size; i++) - { - params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f; - } - } - break; - case GL_FLOAT: - memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat), - size * sizeof(GLfloat)); - break; - case GL_INT: + for (unsigned int i = 0; i < size; i++) { - GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = (float)intParams[i]; - } + params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1); } - break; - default: UNREACHABLE(); } - } - } - - return true; -} + break; -bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params) -{ - if (location < 0 || location >= (int)mUniformIndex.size()) - { - return false; - } + case GL_FLOAT: + { + GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; - Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast<T>(floatParams[i]); + } + } + break; - // sized queries -- ensure the provided buffer is large enough - if (bufSize) - { - int requiredBytes = UniformExternalSize(targetUniform->type); - if (*bufSize < requiredBytes) - { - return false; - } - } + case GL_INT: + { + GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - switch (targetUniform->type) - { - case GL_FLOAT_MAT2: - transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); - break; - case GL_FLOAT_MAT3: - transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); - break; - case GL_FLOAT_MAT4: - transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); - break; - default: - { - unsigned int size = VariableColumnCount(targetUniform->type); + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast<T>(intParams[i]); + } + } + break; - switch (UniformComponentType(targetUniform->type)) + case GL_UNSIGNED_INT: { - case GL_BOOL: - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4; - for (unsigned int i = 0; i < size; i++) - { - params[i] = boolParams[i]; - } - } - break; - case GL_FLOAT: + for (unsigned int i = 0; i < size; i++) { - GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = (GLint)floatParams[i]; - } + params[i] = static_cast<T>(uintParams[i]); } - break; - case GL_INT: - memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint), - size * sizeof(GLint)); - break; - default: UNREACHABLE(); } + break; + + default: UNREACHABLE(); } } return true; } +bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params) +{ + return getUniformv(location, bufSize, params, GL_FLOAT); +} + +bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params) +{ + return getUniformv(location, bufSize, params, GL_INT); +} + +bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params) +{ + return getUniformv(location, bufSize, params, GL_UNSIGNED_INT); +} + void ProgramBinary::dirtyAllUniforms() { unsigned int numUniforms = mUniforms.size(); @@ -953,23 +947,28 @@ void ProgramBinary::dirtyAllUniforms() } } -// Applies all the uniforms set for this program object to the renderer -void ProgramBinary::applyUniforms() +void ProgramBinary::updateSamplerMapping() { + if (!mDirtySamplerMapping) + { + return; + } + + mDirtySamplerMapping = false; + // Retrieve sampler uniform values - for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) { - Uniform *targetUniform = *ub; + LinkedUniform *targetUniform = mUniforms[uniformIndex]; if (targetUniform->dirty) { - if (targetUniform->type == GL_SAMPLER_2D || - targetUniform->type == GL_SAMPLER_CUBE) + if (IsSampler(targetUniform->type)) { int count = targetUniform->elementCount(); - GLint (*v)[4] = (GLint(*)[4])targetUniform->data; + GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data); - if (targetUniform->psRegisterIndex >= 0) + if (targetUniform->isReferencedByFragmentShader()) { unsigned int firstIndex = targetUniform->psRegisterIndex; @@ -985,7 +984,7 @@ void ProgramBinary::applyUniforms() } } - if (targetUniform->vsRegisterIndex >= 0) + if (targetUniform->isReferencedByVertexShader()) { unsigned int firstIndex = targetUniform->vsRegisterIndex; @@ -1003,215 +1002,87 @@ void ProgramBinary::applyUniforms() } } } - - mRenderer->applyUniforms(this, &mUniforms); } -// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111 -// Returns the number of used varying registers, or -1 if unsuccesful -int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader) +// Applies all the uniforms set for this program object to the renderer +void ProgramBinary::applyUniforms() { - const int maxVaryingVectors = mRenderer->getMaxVaryingVectors(); + updateSamplerMapping(); - fragmentShader->resetVaryingsRegisterAssignment(); + mRenderer->applyUniforms(*this); - for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) { - int n = VariableRowCount(varying->type) * varying->size; - int m = VariableColumnCount(varying->type); - bool success = false; - - if (m == 2 || m == 3 || m == 4) - { - for (int r = 0; r <= maxVaryingVectors - n && !success; r++) - { - bool available = true; - - for (int y = 0; y < n && available; y++) - { - for (int x = 0; x < m && available; x++) - { - if (packing[r + y][x]) - { - available = false; - } - } - } + mUniforms[uniformIndex]->dirty = false; + } +} - if (available) - { - varying->reg = r; - varying->col = 0; +bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers) +{ + const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL}; + const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL}; - for (int y = 0; y < n; y++) - { - for (int x = 0; x < m; x++) - { - packing[r + y][x] = &*varying; - } - } + const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers(); + const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers(); - success = true; - } - } + ASSERT(boundBuffers.size() == mUniformBlocks.size()); - if (!success && m == 2) - { - for (int r = maxVaryingVectors - n; r >= 0 && !success; r--) - { - bool available = true; - - for (int y = 0; y < n && available; y++) - { - for (int x = 2; x < 4 && available; x++) - { - if (packing[r + y][x]) - { - available = false; - } - } - } - - if (available) - { - varying->reg = r; - varying->col = 2; + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++) + { + UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex); + gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex]; - for (int y = 0; y < n; y++) - { - for (int x = 2; x < 4; x++) - { - packing[r + y][x] = &*varying; - } - } + ASSERT(uniformBlock && uniformBuffer); - success = true; - } - } - } - } - else if (m == 1) + if (uniformBuffer->getSize() < uniformBlock->dataSize) { - int space[4] = {0}; - - for (int y = 0; y < maxVaryingVectors; y++) - { - for (int x = 0; x < 4; x++) - { - space[x] += packing[y][x] ? 0 : 1; - } - } - - int column = 0; - - for (int x = 0; x < 4; x++) - { - if (space[x] >= n && space[x] < space[column]) - { - column = x; - } - } - - if (space[column] >= n) - { - for (int r = 0; r < maxVaryingVectors; r++) - { - if (!packing[r][column]) - { - varying->reg = r; - - for (int y = r; y < r + n; y++) - { - packing[y][column] = &*varying; - } - - break; - } - } - - varying->col = column; - - success = true; - } + // undefined behaviour + return false; } - else UNREACHABLE(); - if (!success) - { - infoLog.append("Could not pack varying %s", varying->name.c_str()); + ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader()); - return -1; + if (uniformBlock->isReferencedByVertexShader()) + { + unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS; + ASSERT(vertexUniformBuffers[registerIndex] == NULL); + ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers()); + vertexUniformBuffers[registerIndex] = uniformBuffer; } - } - - // Return the number of used registers - int registers = 0; - for (int r = 0; r < maxVaryingVectors; r++) - { - if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3]) + if (uniformBlock->isReferencedByFragmentShader()) { - registers++; + unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS; + ASSERT(fragmentUniformBuffers[registerIndex] == NULL); + ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers()); + fragmentUniformBuffers[registerIndex] = uniformBuffer; } } - return registers; + return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers); } -bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4], - std::string& pixelHLSL, std::string& vertexHLSL, - FragmentShader *fragmentShader, VertexShader *vertexShader) +bool ProgramBinary::linkVaryings(InfoLog &infoLog, FragmentShader *fragmentShader, VertexShader *vertexShader) { - if (pixelHLSL.empty() || vertexHLSL.empty()) - { - return false; - } + std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings(); + std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings(); - bool usesMRT = fragmentShader->mUsesMultipleRenderTargets; - bool usesFragColor = fragmentShader->mUsesFragColor; - bool usesFragData = fragmentShader->mUsesFragData; - if (usesFragColor && usesFragData) - { - infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader."); - return false; - } - - // Write the HLSL input/output declarations - const int shaderModel = mRenderer->getMajorShaderModel(); - const int maxVaryingVectors = mRenderer->getMaxVaryingVectors(); - - const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0); - - // The output color is broadcast to all enabled draw buffers when writing to gl_FragColor - const bool broadcast = fragmentShader->mUsesFragColor; - const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1); - - if (registersNeeded > maxVaryingVectors) - { - infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord"); - - return false; - } - - vertexShader->resetVaryingsRegisterAssignment(); - - for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++) + for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++) { + PackedVarying *input = &fragmentVaryings[fragVaryingIndex]; bool matched = false; - for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++) + for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++) { + PackedVarying *output = &vertexVaryings[vertVaryingIndex]; if (output->name == input->name) { - if (output->type != input->type || output->size != input->size) + if (!linkValidateVariables(infoLog, output->name, *input, *output)) { - infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str()); - return false; } - output->reg = input->reg; - output->col = input->col; + output->registerIndex = input->registerIndex; matched = true; break; @@ -1221,664 +1092,463 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying if (!matched) { infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str()); - return false; } } - mUsesPointSize = vertexShader->mUsesPointSize; - std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD"; - std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR"; - std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION"; - std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH"; + return true; +} - // special varyings that use reserved registers - int reservedRegisterIndex = registers; - std::string fragCoordSemantic; - std::string pointCoordSemantic; +bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length) +{ +#ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD + return false; +#else + reset(); - if (fragmentShader->mUsesFragCoord) + BinaryInputStream stream(binary, length); + + int format = stream.readInt<int>(); + if (format != GL_PROGRAM_BINARY_ANGLE) { - fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); + infoLog.append("Invalid program binary format."); + return false; } - if (fragmentShader->mUsesPointCoord) + int majorVersion = stream.readInt<int>(); + int minorVersion = stream.readInt<int>(); + if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION) { - // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords. - // In DX11 we compute this in the GS. - if (shaderModel == 3) - { - pointCoordSemantic = "TEXCOORD0"; - } - else if (shaderModel >= 4) - { - pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); - } + infoLog.append("Invalid program binary version."); + return false; } - vertexHLSL += "struct VS_INPUT\n" - "{\n"; - - int semanticIndex = 0; - for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + unsigned char commitString[ANGLE_COMMIT_HASH_SIZE]; + stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE); + if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0) { - switch (attribute->type) - { - case GL_FLOAT: vertexHLSL += " float "; break; - case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break; - case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break; - case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break; - case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break; - case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break; - case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break; - default: UNREACHABLE(); - } - - vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n"; - - semanticIndex += VariableRowCount(attribute->type); + infoLog.append("Invalid program binary version."); + return false; } - vertexHLSL += "};\n" - "\n" - "struct VS_OUTPUT\n" - "{\n"; - - if (shaderModel < 4) + int compileFlags = stream.readInt<int>(); + if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) { - vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n"; + infoLog.append("Mismatched compilation flags."); + return false; } - for (int r = 0; r < registers; r++) + for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) { - int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1)); - - vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n"; + stream.readInt(&mLinkedAttribute[i].type); + stream.readString(&mLinkedAttribute[i].name); + stream.readInt(&mShaderAttributes[i].type); + stream.readString(&mShaderAttributes[i].name); + stream.readInt(&mSemanticIndex[i]); } - if (fragmentShader->mUsesFragCoord) + initAttributesByLayout(); + + for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) { - vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; + stream.readBool(&mSamplersPS[i].active); + stream.readInt(&mSamplersPS[i].logicalTextureUnit); + stream.readInt(&mSamplersPS[i].textureType); } - if (vertexShader->mUsesPointSize && shaderModel >= 3) + for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i) { - vertexHLSL += " float gl_PointSize : PSIZE;\n"; + stream.readBool(&mSamplersVS[i].active); + stream.readInt(&mSamplersVS[i].logicalTextureUnit); + stream.readInt(&mSamplersVS[i].textureType); } - if (shaderModel >= 4) + stream.readInt(&mUsedVertexSamplerRange); + stream.readInt(&mUsedPixelSamplerRange); + stream.readBool(&mUsesPointSize); + stream.readInt(&mShaderVersion); + + const unsigned int uniformCount = stream.readInt<unsigned int>(); + if (stream.error()) { - vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n"; + infoLog.append("Invalid program binary."); + return false; } - vertexHLSL += "};\n" - "\n" - "VS_OUTPUT main(VS_INPUT input)\n" - "{\n"; - - for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + mUniforms.resize(uniformCount); + for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) { - vertexHLSL += " " + decorateAttribute(attribute->name) + " = "; + GLenum type = stream.readInt<GLenum>(); + GLenum precision = stream.readInt<GLenum>(); + std::string name = stream.readString(); + unsigned int arraySize = stream.readInt<unsigned int>(); + int blockIndex = stream.readInt<int>(); - if (VariableRowCount(attribute->type) > 1) // Matrix - { - vertexHLSL += "transpose"; - } + int offset = stream.readInt<int>(); + int arrayStride = stream.readInt<int>(); + int matrixStride = stream.readInt<int>(); + bool isRowMajorMatrix = stream.readBool(); - vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n"; - } + const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix); - if (shaderModel >= 4) - { - vertexHLSL += "\n" - " gl_main();\n" - "\n" - " VS_OUTPUT output;\n" - " output.gl_Position.x = gl_Position.x;\n" - " output.gl_Position.y = -gl_Position.y;\n" - " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" - " output.gl_Position.w = gl_Position.w;\n"; - } - else - { - vertexHLSL += "\n" - " gl_main();\n" - "\n" - " VS_OUTPUT output;\n" - " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n" - " output.gl_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n" - " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" - " output.gl_Position.w = gl_Position.w;\n"; - } + LinkedUniform *uniform = new LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo); - if (vertexShader->mUsesPointSize && shaderModel >= 3) - { - vertexHLSL += " output.gl_PointSize = gl_PointSize;\n"; + stream.readInt(&uniform->psRegisterIndex); + stream.readInt(&uniform->vsRegisterIndex); + stream.readInt(&uniform->registerCount); + stream.readInt(&uniform->registerElement); + + mUniforms[uniformIndex] = uniform; } - if (fragmentShader->mUsesFragCoord) + unsigned int uniformBlockCount = stream.readInt<unsigned int>(); + if (stream.error()) { - vertexHLSL += " output.gl_FragCoord = gl_Position;\n"; + infoLog.append("Invalid program binary."); + return false; } - for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++) + mUniformBlocks.resize(uniformBlockCount); + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) { - if (varying->reg >= 0) - { - for (int i = 0; i < varying->size; i++) - { - int rows = VariableRowCount(varying->type); - - for (int j = 0; j < rows; j++) - { - int r = varying->reg + i * rows + j; - vertexHLSL += " output.v" + str(r); - - bool sharedRegister = false; // Register used by multiple varyings - - for (int x = 0; x < 4; x++) - { - if (packing[r][x] && packing[r][x] != packing[r][0]) - { - sharedRegister = true; - break; - } - } + std::string name = stream.readString(); + unsigned int elementIndex = stream.readInt<unsigned int>(); + unsigned int dataSize = stream.readInt<unsigned int>(); - if(sharedRegister) - { - vertexHLSL += "."; - - for (int x = 0; x < 4; x++) - { - if (packing[r][x] == &*varying) - { - switch(x) - { - case 0: vertexHLSL += "x"; break; - case 1: vertexHLSL += "y"; break; - case 2: vertexHLSL += "z"; break; - case 3: vertexHLSL += "w"; break; - } - } - } - } - - vertexHLSL += " = " + varying->name; - - if (varying->array) - { - vertexHLSL += "[" + str(i) + "]"; - } - - if (rows > 1) - { - vertexHLSL += "[" + str(j) + "]"; - } - - vertexHLSL += ";\n"; - } - } - } - } + UniformBlock *uniformBlock = new UniformBlock(name, elementIndex, dataSize); - vertexHLSL += "\n" - " return output;\n" - "}\n"; + stream.readInt(&uniformBlock->psRegisterIndex); + stream.readInt(&uniformBlock->vsRegisterIndex); - pixelHLSL += "struct PS_INPUT\n" - "{\n"; - - for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) - { - if (varying->reg >= 0) + unsigned int numMembers = stream.readInt<unsigned int>(); + uniformBlock->memberUniformIndexes.resize(numMembers); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) { - for (int i = 0; i < varying->size; i++) - { - int rows = VariableRowCount(varying->type); - for (int j = 0; j < rows; j++) - { - std::string n = str(varying->reg + i * rows + j); - pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n"; - } - } + stream.readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]); } - else UNREACHABLE(); + + mUniformBlocks[uniformBlockIndex] = uniformBlock; } - if (fragmentShader->mUsesFragCoord) + const unsigned int uniformIndexCount = stream.readInt<unsigned int>(); + if (stream.error()) { - pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; + infoLog.append("Invalid program binary."); + return false; } - - if (fragmentShader->mUsesPointCoord && shaderModel >= 3) + + mUniformIndex.resize(uniformIndexCount); + for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++) { - pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n"; + stream.readString(&mUniformIndex[uniformIndexIndex].name); + stream.readInt(&mUniformIndex[uniformIndexIndex].element); + stream.readInt(&mUniformIndex[uniformIndexIndex].index); } - // Must consume the PSIZE element if the geometry shader is not active - // We won't know if we use a GS until we draw - if (vertexShader->mUsesPointSize && shaderModel >= 4) + stream.readInt(&mTransformFeedbackBufferMode); + const unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>(); + mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount); + for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++) { - pixelHLSL += " float gl_PointSize : PSIZE;\n"; + LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex]; + + stream.readString(&varying.name); + stream.readInt(&varying.type); + stream.readInt(&varying.size); + stream.readString(&varying.semanticName); + stream.readInt(&varying.semanticIndex); + stream.readInt(&varying.semanticIndexCount); } - if (fragmentShader->mUsesFragCoord) + stream.readString(&mVertexHLSL); + + stream.readInt(&mVertexWorkarounds); + + const unsigned int vertexShaderCount = stream.readInt<unsigned int>(); + for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++) { - if (shaderModel >= 4) + VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]; + + for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++) { - pixelHLSL += " float4 dx_VPos : SV_Position;\n"; + VertexFormat *vertexInput = &inputLayout[inputIndex]; + stream.readInt(&vertexInput->mType); + stream.readInt(&vertexInput->mNormalized); + stream.readInt(&vertexInput->mComponents); + stream.readBool(&vertexInput->mPureInteger); } - else if (shaderModel >= 3) + + unsigned int vertexShaderSize = stream.readInt<unsigned int>(); + const unsigned char *vertexShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset(); + rx::ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction), + vertexShaderSize, rx::SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); + if (!shaderExecutable) { - pixelHLSL += " float2 dx_VPos : VPOS;\n"; + infoLog.append("Could not create vertex shader."); + return false; } - } - pixelHLSL += "};\n" - "\n" - "struct PS_OUTPUT\n" - "{\n"; + // generated converted input layout + GLenum signature[MAX_VERTEX_ATTRIBS]; + mDynamicHLSL->getInputLayoutSignature(inputLayout, signature); - for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++) - { - pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n"; - } + // add new binary + mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable)); - if (fragmentShader->mUsesFragDepth) - { - pixelHLSL += " float gl_Depth : " + depthSemantic + ";\n"; + stream.skip(vertexShaderSize); } - pixelHLSL += "};\n" - "\n"; + stream.readString(&mPixelHLSL); + stream.readInt(&mPixelWorkarounds); + stream.readBool(&mUsesFragDepth); - if (fragmentShader->mUsesFrontFacing) + const size_t pixelShaderKeySize = stream.readInt<unsigned int>(); + mPixelShaderKey.resize(pixelShaderKeySize); + for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize; pixelShaderKeyIndex++) { - if (shaderModel >= 4) - { - pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n" - "{\n"; - } - else - { - pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n" - "{\n"; - } - } - else - { - pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n" - "{\n"; + stream.readInt(&mPixelShaderKey[pixelShaderKeyIndex].type); + stream.readString(&mPixelShaderKey[pixelShaderKeyIndex].name); + stream.readString(&mPixelShaderKey[pixelShaderKeyIndex].source); + stream.readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex); } - if (fragmentShader->mUsesFragCoord) + const size_t pixelShaderCount = stream.readInt<unsigned int>(); + for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++) { - pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"; - - if (shaderModel >= 4) + const size_t outputCount = stream.readInt<unsigned int>(); + std::vector<GLenum> outputs(outputCount); + for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++) { - pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n" - " gl_FragCoord.y = input.dx_VPos.y;\n"; + stream.readInt(&outputs[outputIndex]); } - else if (shaderModel >= 3) - { - pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n" - " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n"; - } - else + + const size_t pixelShaderSize = stream.readInt<unsigned int>(); + const unsigned char *pixelShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset(); + rx::ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, + rx::SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); + if (!shaderExecutable) { - // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport() - pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n" - " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n"; + infoLog.append("Could not create pixel shader."); + return false; } - - pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n" - " gl_FragCoord.w = rhw;\n"; - } - if (fragmentShader->mUsesPointCoord && shaderModel >= 3) - { - pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n"; - pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n"; - } + // add new binary + mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable)); - if (fragmentShader->mUsesFrontFacing) - { - if (shaderModel <= 3) - { - pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n"; - } - else - { - pixelHLSL += " gl_FrontFacing = isFrontFace;\n"; - } + stream.skip(pixelShaderSize); } - for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) + unsigned int geometryShaderSize = stream.readInt<unsigned int>(); + + if (geometryShaderSize > 0) { - if (varying->reg >= 0) + const char *geometryShaderFunction = (const char*) binary + stream.offset(); + mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction), + geometryShaderSize, rx::SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); + if (!mGeometryExecutable) { - for (int i = 0; i < varying->size; i++) - { - int rows = VariableRowCount(varying->type); - for (int j = 0; j < rows; j++) - { - std::string n = str(varying->reg + i * rows + j); - pixelHLSL += " " + varying->name; - - if (varying->array) - { - pixelHLSL += "[" + str(i) + "]"; - } - - if (rows > 1) - { - pixelHLSL += "[" + str(j) + "]"; - } - - switch (VariableColumnCount(varying->type)) - { - case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break; - case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break; - case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break; - case 4: pixelHLSL += " = input.v" + n + ";\n"; break; - default: UNREACHABLE(); - } - } - } + infoLog.append("Could not create geometry shader."); + return false; } - else UNREACHABLE(); + stream.skip(geometryShaderSize); } - pixelHLSL += "\n" - " gl_main();\n" - "\n" - " PS_OUTPUT output;\n"; - - for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++) - { - unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex; + const char *ptr = (const char*) binary + stream.offset(); - pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n"; - } + const GUID *binaryIdentifier = (const GUID *) ptr; + ptr += sizeof(GUID); - if (fragmentShader->mUsesFragDepth) + GUID identifier = mRenderer->getAdapterIdentifier(); + if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0) { - pixelHLSL += " output.gl_Depth = gl_Depth;\n"; + infoLog.append("Invalid program binary."); + return false; } - pixelHLSL += "\n" - " return output;\n" - "}\n"; + initializeUniformStorage(); return true; +#endif // #ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD } -bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length) +bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length) { - BinaryInputStream stream(binary, length); - - int format = 0; - stream.read(&format); - if (format != GL_PROGRAM_BINARY_ANGLE) - { - infoLog.append("Invalid program binary format."); - return false; - } - - int majorVersion = 0; - int minorVersion = 0; - stream.read(&majorVersion); - stream.read(&minorVersion); - if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION) - { - infoLog.append("Invalid program binary version."); - return false; - } - -#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY) - unsigned char commitString[ANGLE_COMMIT_HASH_SIZE]; - stream.read(commitString, ANGLE_COMMIT_HASH_SIZE); - if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0) - { - infoLog.append("Invalid program binary version."); - return false; - } + BinaryOutputStream stream; - int compileFlags = 0; - stream.read(&compileFlags); - if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) - { - infoLog.append("Mismatched compilation flags."); - return false; - } -#endif + stream.writeInt(GL_PROGRAM_BINARY_ANGLE); + stream.writeInt(ANGLE_MAJOR_VERSION); + stream.writeInt(ANGLE_MINOR_VERSION); + stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE); + stream.writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL); - for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) + for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) { - stream.read(&mLinkedAttribute[i].type); - std::string name; - stream.read(&name); - mLinkedAttribute[i].name = name; - stream.read(&mSemanticIndex[i]); + stream.writeInt(mLinkedAttribute[i].type); + stream.writeString(mLinkedAttribute[i].name); + stream.writeInt(mShaderAttributes[i].type); + stream.writeString(mShaderAttributes[i].name); + stream.writeInt(mSemanticIndex[i]); } - initAttributesByLayout(); - for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) { - stream.read(&mSamplersPS[i].active); - stream.read(&mSamplersPS[i].logicalTextureUnit); - - int textureType; - stream.read(&textureType); - mSamplersPS[i].textureType = (TextureType) textureType; + stream.writeInt(mSamplersPS[i].active); + stream.writeInt(mSamplersPS[i].logicalTextureUnit); + stream.writeInt(mSamplersPS[i].textureType); } for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i) { - stream.read(&mSamplersVS[i].active); - stream.read(&mSamplersVS[i].logicalTextureUnit); - - int textureType; - stream.read(&textureType); - mSamplersVS[i].textureType = (TextureType) textureType; + stream.writeInt(mSamplersVS[i].active); + stream.writeInt(mSamplersVS[i].logicalTextureUnit); + stream.writeInt(mSamplersVS[i].textureType); } - stream.read(&mUsedVertexSamplerRange); - stream.read(&mUsedPixelSamplerRange); - stream.read(&mUsesPointSize); + stream.writeInt(mUsedVertexSamplerRange); + stream.writeInt(mUsedPixelSamplerRange); + stream.writeInt(mUsesPointSize); + stream.writeInt(mShaderVersion); - size_t size; - stream.read(&size); - if (stream.error()) + stream.writeInt(mUniforms.size()); + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) { - infoLog.append("Invalid program binary."); - return false; - } - - mUniforms.resize(size); - for (unsigned int i = 0; i < size; ++i) - { - GLenum type; - GLenum precision; - std::string name; - unsigned int arraySize; + const LinkedUniform &uniform = *mUniforms[uniformIndex]; - stream.read(&type); - stream.read(&precision); - stream.read(&name); - stream.read(&arraySize); + stream.writeInt(uniform.type); + stream.writeInt(uniform.precision); + stream.writeString(uniform.name); + stream.writeInt(uniform.arraySize); + stream.writeInt(uniform.blockIndex); - mUniforms[i] = new Uniform(type, precision, name, arraySize); - - stream.read(&mUniforms[i]->psRegisterIndex); - stream.read(&mUniforms[i]->vsRegisterIndex); - stream.read(&mUniforms[i]->registerCount); - } + stream.writeInt(uniform.blockInfo.offset); + stream.writeInt(uniform.blockInfo.arrayStride); + stream.writeInt(uniform.blockInfo.matrixStride); + stream.writeInt(uniform.blockInfo.isRowMajorMatrix); - stream.read(&size); - if (stream.error()) - { - infoLog.append("Invalid program binary."); - return false; + stream.writeInt(uniform.psRegisterIndex); + stream.writeInt(uniform.vsRegisterIndex); + stream.writeInt(uniform.registerCount); + stream.writeInt(uniform.registerElement); } - mUniformIndex.resize(size); - for (unsigned int i = 0; i < size; ++i) + stream.writeInt(mUniformBlocks.size()); + for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex) { - stream.read(&mUniformIndex[i].name); - stream.read(&mUniformIndex[i].element); - stream.read(&mUniformIndex[i].index); - } + const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex]; - unsigned int pixelShaderSize; - stream.read(&pixelShaderSize); + stream.writeString(uniformBlock.name); + stream.writeInt(uniformBlock.elementIndex); + stream.writeInt(uniformBlock.dataSize); - unsigned int vertexShaderSize; - stream.read(&vertexShaderSize); - - unsigned int geometryShaderSize; - stream.read(&geometryShaderSize); - - const char *ptr = (const char*) binary + stream.offset(); - -#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY) - const GUID *binaryIdentifier = (const GUID *) ptr; - ptr += sizeof(GUID); + stream.writeInt(uniformBlock.memberUniformIndexes.size()); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) + { + stream.writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]); + } - GUID identifier = mRenderer->getAdapterIdentifier(); - if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0) - { - infoLog.append("Invalid program binary."); - return false; + stream.writeInt(uniformBlock.psRegisterIndex); + stream.writeInt(uniformBlock.vsRegisterIndex); } -#endif - - const char *pixelShaderFunction = ptr; - ptr += pixelShaderSize; - - const char *vertexShaderFunction = ptr; - ptr += vertexShaderSize; - const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL; - ptr += geometryShaderSize; - - mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction), - pixelShaderSize, rx::SHADER_PIXEL); - if (!mPixelExecutable) + stream.writeInt(mUniformIndex.size()); + for (size_t i = 0; i < mUniformIndex.size(); ++i) { - infoLog.append("Could not create pixel shader."); - return false; + stream.writeString(mUniformIndex[i].name); + stream.writeInt(mUniformIndex[i].element); + stream.writeInt(mUniformIndex[i].index); } - mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction), - vertexShaderSize, rx::SHADER_VERTEX); - if (!mVertexExecutable) + stream.writeInt(mTransformFeedbackBufferMode); + stream.writeInt(mTransformFeedbackLinkedVaryings.size()); + for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++) { - infoLog.append("Could not create vertex shader."); - delete mPixelExecutable; - mPixelExecutable = NULL; - return false; + const LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i]; + + stream.writeString(varying.name); + stream.writeInt(varying.type); + stream.writeInt(varying.size); + stream.writeString(varying.semanticName); + stream.writeInt(varying.semanticIndex); + stream.writeInt(varying.semanticIndexCount); } - if (geometryShaderFunction != NULL && geometryShaderSize > 0) + stream.writeString(mVertexHLSL); + stream.writeInt(mVertexWorkarounds); + + stream.writeInt(mVertexExecutables.size()); + for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++) { - mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction), - geometryShaderSize, rx::SHADER_GEOMETRY); - if (!mGeometryExecutable) + VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex]; + + for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) { - infoLog.append("Could not create geometry shader."); - delete mPixelExecutable; - mPixelExecutable = NULL; - delete mVertexExecutable; - mVertexExecutable = NULL; - return false; + const VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex]; + stream.writeInt(vertexInput.mType); + stream.writeInt(vertexInput.mNormalized); + stream.writeInt(vertexInput.mComponents); + stream.writeInt(vertexInput.mPureInteger); } - } - else - { - mGeometryExecutable = NULL; - } - return true; -} - -bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length) -{ - BinaryOutputStream stream; + size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength(); + stream.writeInt(vertexShaderSize); - stream.write(GL_PROGRAM_BINARY_ANGLE); - stream.write(ANGLE_MAJOR_VERSION); - stream.write(ANGLE_MINOR_VERSION); -#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY) - stream.write(ANGLE_COMMIT_HASH, ANGLE_COMMIT_HASH_SIZE); - stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL); -#endif - for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) - { - stream.write(mLinkedAttribute[i].type); - stream.write(mLinkedAttribute[i].name); - stream.write(mSemanticIndex[i]); + const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction(); + stream.writeBytes(vertexBlob, vertexShaderSize); } - for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) + stream.writeString(mPixelHLSL); + stream.writeInt(mPixelWorkarounds); + stream.writeInt(mUsesFragDepth); + + stream.writeInt(mPixelShaderKey.size()); + for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < mPixelShaderKey.size(); pixelShaderKeyIndex++) { - stream.write(mSamplersPS[i].active); - stream.write(mSamplersPS[i].logicalTextureUnit); - stream.write((int) mSamplersPS[i].textureType); + const PixelShaderOuputVariable &variable = mPixelShaderKey[pixelShaderKeyIndex]; + stream.writeInt(variable.type); + stream.writeString(variable.name); + stream.writeString(variable.source); + stream.writeInt(variable.outputIndex); } - for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i) + stream.writeInt(mPixelExecutables.size()); + for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++) { - stream.write(mSamplersVS[i].active); - stream.write(mSamplersVS[i].logicalTextureUnit); - stream.write((int) mSamplersVS[i].textureType); - } + PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex]; - stream.write(mUsedVertexSamplerRange); - stream.write(mUsedPixelSamplerRange); - stream.write(mUsesPointSize); + const std::vector<GLenum> outputs = pixelExecutable->outputSignature(); + stream.writeInt(outputs.size()); + for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++) + { + stream.writeInt(outputs[outputIndex]); + } - stream.write(mUniforms.size()); - for (unsigned int i = 0; i < mUniforms.size(); ++i) - { - stream.write(mUniforms[i]->type); - stream.write(mUniforms[i]->precision); - stream.write(mUniforms[i]->name); - stream.write(mUniforms[i]->arraySize); + size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength(); + stream.writeInt(pixelShaderSize); - stream.write(mUniforms[i]->psRegisterIndex); - stream.write(mUniforms[i]->vsRegisterIndex); - stream.write(mUniforms[i]->registerCount); + const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction(); + stream.writeBytes(pixelBlob, pixelShaderSize); } - stream.write(mUniformIndex.size()); - for (unsigned int i = 0; i < mUniformIndex.size(); ++i) + size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0; + stream.writeInt(geometryShaderSize); + + if (mGeometryExecutable != NULL && geometryShaderSize > 0) { - stream.write(mUniformIndex[i].name); - stream.write(mUniformIndex[i].element); - stream.write(mUniformIndex[i].index); + const uint8_t *geometryBlob = mGeometryExecutable->getFunction(); + stream.writeBytes(geometryBlob, geometryShaderSize); } - UINT pixelShaderSize = mPixelExecutable->getLength(); - stream.write(pixelShaderSize); - - UINT vertexShaderSize = mVertexExecutable->getLength(); - stream.write(vertexShaderSize); - - UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0; - stream.write(geometryShaderSize); - -#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY) GUID identifier = mRenderer->getAdapterIdentifier(); -#endif GLsizei streamLength = stream.length(); const void *streamData = stream.data(); - GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize; + GLsizei totalLength = streamLength + sizeof(GUID); if (totalLength > bufSize) { if (length) @@ -1896,22 +1566,8 @@ bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length) memcpy(ptr, streamData, streamLength); ptr += streamLength; -#if !defined(ANGLE_ENABLE_UNIVERSAL_BINARY) memcpy(ptr, &identifier, sizeof(GUID)); ptr += sizeof(GUID); -#endif - - memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize); - ptr += pixelShaderSize; - - memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize); - ptr += vertexShaderSize; - - if (mGeometryExecutable != NULL && geometryShaderSize > 0) - { - memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize); - ptr += geometryShaderSize; - } ASSERT(ptr - totalLength == binary); } @@ -1937,7 +1593,8 @@ GLint ProgramBinary::getLength() } } -bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader) +bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader, + const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode) { if (!fragmentShader || !fragmentShader->isCompiled()) { @@ -1949,19 +1606,37 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin return false; } - std::string pixelHLSL = fragmentShader->getHLSL(); - std::string vertexHLSL = vertexShader->getHLSL(); + reset(); + + mTransformFeedbackBufferMode = transformFeedbackBufferMode; + + mShaderVersion = vertexShader->getShaderVersion(); + + mPixelHLSL = fragmentShader->getHLSL(); + mPixelWorkarounds = fragmentShader->getD3DWorkarounds(); + + mVertexHLSL = vertexShader->getHLSL(); + mVertexWorkarounds = vertexShader->getD3DWorkarounds(); // Map the varyings to the register file - const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL}; - int registers = packVaryings(infoLog, packing, fragmentShader); + VaryingPacking packing = { NULL }; + int registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShader, vertexShader, transformFeedbackVaryings); if (registers < 0) { return false; } - if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader)) + if (!linkVaryings(infoLog, fragmentShader, vertexShader)) + { + return false; + } + + mUsesPointSize = vertexShader->usesPointSize(); + std::vector<LinkedVarying> linkedVaryings; + if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, registers, packing, mPixelHLSL, mVertexHLSL, + fragmentShader, vertexShader, transformFeedbackVaryings, + &linkedVaryings, &mOutputVariables, &mPixelShaderKey, &mUsesFragDepth)) { return false; } @@ -1973,41 +1648,59 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin success = false; } - if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms())) + if (!linkUniforms(infoLog, *vertexShader, *fragmentShader)) { success = false; } // special case for gl_DepthRange, the only built-in uniform (also a struct) - if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange) + if (vertexShader->usesDepthRange() || fragmentShader->usesDepthRange()) { - mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0)); - mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0)); - mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0)); + const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo(); + + mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo)); + mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo)); + mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo)); + } + + if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader)) + { + success = false; + } + + if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings, + transformFeedbackBufferMode, &mTransformFeedbackLinkedVaryings)) + { + success = false; } if (success) { - mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX, DiscardWorkaround(vertexShader->mUsesDiscardRewriting)); - mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL, DiscardWorkaround(fragmentShader->mUsesDiscardRewriting)); + VertexFormat defaultInputLayout[MAX_VERTEX_ATTRIBS]; + GetInputLayoutFromShader(vertexShader->activeAttributes(), defaultInputLayout); + rx::ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout); + + std::vector<GLenum> defaultPixelOutput(IMPLEMENTATION_MAX_DRAW_BUFFERS); + for (size_t i = 0; i < defaultPixelOutput.size(); i++) + { + defaultPixelOutput[i] = (i == 0) ? GL_FLOAT : GL_NONE; + } + rx::ShaderExecutable *defaultPixelExecutable = getPixelExecutableForOutputLayout(defaultPixelOutput); if (usesGeometryShader()) { - std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader); - mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY, rx::ANGLE_D3D_WORKAROUND_NONE); + std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShader, vertexShader); + mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + rx::ANGLE_D3D_WORKAROUND_NONE); } - if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable)) + if (!defaultVertexExecutable || !defaultPixelExecutable || (usesGeometryShader() && !mGeometryExecutable)) { infoLog.append("Failed to create D3D shaders."); success = false; - - delete mVertexExecutable; - mVertexExecutable = NULL; - delete mPixelExecutable; - mPixelExecutable = NULL; - delete mGeometryExecutable; - mGeometryExecutable = NULL; + reset(); } } @@ -2018,62 +1711,75 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader) { unsigned int usedLocations = 0; + const std::vector<sh::Attribute> &activeAttributes = vertexShader->activeAttributes(); // Link attributes that have a binding location - for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++) { - int location = attributeBindings.getAttributeBinding(attribute->name); - - if (location != -1) // Set by glBindAttribLocation - { - if (!mLinkedAttribute[location].name.empty()) - { - // Multiple active attributes bound to the same location; not an error - } + const sh::Attribute &attribute = activeAttributes[attributeIndex]; + const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location; - mLinkedAttribute[location] = *attribute; + mShaderAttributes[attributeIndex] = attribute; - int rows = VariableRowCount(attribute->type); + if (location != -1) // Set by glBindAttribLocation or by location layout qualifier + { + const int rows = VariableRegisterCount(attribute.type); if (rows + location > MAX_VERTEX_ATTRIBS) { - infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location); + infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location); return false; } - for (int i = 0; i < rows; i++) + for (int row = 0; row < rows; row++) { - usedLocations |= 1 << (location + i); + const int rowLocation = location + row; + sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation]; + + // In GLSL 3.00, attribute aliasing produces a link error + // In GLSL 1.00, attribute aliasing is allowed + if (mShaderVersion >= 300) + { + if (!linkedAttribute.name.empty()) + { + infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation); + return false; + } + } + + linkedAttribute = attribute; + usedLocations |= 1 << rowLocation; } } } // Link attributes that don't have a binding location - for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++) { - int location = attributeBindings.getAttributeBinding(attribute->name); + const sh::Attribute &attribute = activeAttributes[attributeIndex]; + const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location; - if (location == -1) // Not set by glBindAttribLocation + if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier { - int rows = VariableRowCount(attribute->type); + int rows = VariableRegisterCount(attribute.type); int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS); if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS) { - infoLog.append("Too many active attributes (%s)", attribute->name.c_str()); + infoLog.append("Too many active attributes (%s)", attribute.name.c_str()); return false; // Fail to link } - mLinkedAttribute[availableIndex] = *attribute; + mLinkedAttribute[availableIndex] = attribute; } } for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; ) { int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name); - int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1); + int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type); for (int r = 0; r < rows; r++) { @@ -2086,19 +1792,51 @@ bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &at return true; } -bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms) +bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, + const sh::ShaderVariable &fragmentVariable, bool validatePrecision) { - for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++) + if (vertexVariable.type != fragmentVariable.type) + { + infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + if (vertexVariable.arraySize != fragmentVariable.arraySize) { - if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog)) + infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + if (validatePrecision && vertexVariable.precision != fragmentVariable.precision) + { + infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + + return true; +} + +template <class ShaderVarType> +bool ProgramBinary::linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar) +{ + if (vertexVar.fields.size() != fragmentVar.fields.size()) + { + infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", varName.c_str()); + return false; + } + const unsigned int numMembers = vertexVar.fields.size(); + for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++) + { + const ShaderVarType &vertexMember = vertexVar.fields[memberIndex]; + const ShaderVarType &fragmentMember = fragmentVar.fields[memberIndex]; + + if (vertexMember.name != fragmentMember.name) { + infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')", + memberIndex, varName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str()); return false; } - } - for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++) - { - if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog)) + const std::string memberName = varName.substr(0, varName.length()-1) + "." + vertexVar.name + "'"; + if (!linkValidateVariables(infoLog, memberName, vertexMember, fragmentMember)) { return false; } @@ -2107,274 +1845,571 @@ bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &ver return true; } -bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog) +bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform) { - if (constant.type == GL_SAMPLER_2D || - constant.type == GL_SAMPLER_CUBE) + if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true)) { - unsigned int samplerIndex = constant.registerIndex; - - do - { - if (shader == GL_VERTEX_SHADER) - { - if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits()) - { - mSamplersVS[samplerIndex].active = true; - mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D; - mSamplersVS[samplerIndex].logicalTextureUnit = 0; - mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange); - } - else - { - infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits()); - return false; - } - } - else if (shader == GL_FRAGMENT_SHADER) - { - if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) - { - mSamplersPS[samplerIndex].active = true; - mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D; - mSamplersPS[samplerIndex].logicalTextureUnit = 0; - mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange); - } - else - { - infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS); - return false; - } - } - else UNREACHABLE(); + return false; + } - samplerIndex++; - } - while (samplerIndex < constant.registerIndex + constant.arraySize); + if (!linkValidateFields<sh::Uniform>(infoLog, uniformName, vertexUniform, fragmentUniform)) + { + return false; } - Uniform *uniform = NULL; - GLint location = getUniformLocation(constant.name); + return true; +} - if (location >= 0) // Previously defined, type and precision must match +bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying) +{ + if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false)) { - uniform = mUniforms[mUniformIndex[location].index]; + return false; + } - if (uniform->type != constant.type) - { - infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str()); - return false; - } + if (vertexVarying.interpolation != fragmentVarying.interpolation) + { + infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str()); + return false; + } - if (uniform->precision != constant.precision) - { - infoLog.append("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str()); - return false; - } + if (!linkValidateFields<sh::Varying>(infoLog, varyingName, vertexVarying, fragmentVarying)) + { + return false; } - else + + return true; +} + +bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform) +{ + if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true)) { - uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize); + return false; } - if (!uniform) + if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix) { + infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str()); return false; } - if (shader == GL_FRAGMENT_SHADER) + if (!linkValidateFields<sh::InterfaceBlockField>(infoLog, uniformName, vertexUniform, fragmentUniform)) { - uniform->psRegisterIndex = constant.registerIndex; + return false; } - else if (shader == GL_VERTEX_SHADER) + + return true; +} + +bool ProgramBinary::linkUniforms(InfoLog &infoLog, const VertexShader &vertexShader, const FragmentShader &fragmentShader) +{ + const std::vector<sh::Uniform> &vertexUniforms = vertexShader.getUniforms(); + const std::vector<sh::Uniform> &fragmentUniforms = fragmentShader.getUniforms(); + + // Check that uniforms defined in the vertex and fragment shaders are identical + typedef std::map<std::string, const sh::Uniform*> UniformMap; + UniformMap linkedUniforms; + + for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++) { - uniform->vsRegisterIndex = constant.registerIndex; + const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex]; + linkedUniforms[vertexUniform.name] = &vertexUniform; + } + + for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++) + { + const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex]; + UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name); + if (entry != linkedUniforms.end()) + { + const sh::Uniform &vertexUniform = *entry->second; + const std::string &uniformName = "uniform '" + vertexUniform.name + "'"; + if (!linkValidateVariables(infoLog, uniformName, vertexUniform, fragmentUniform)) + { + return false; + } + } } - else UNREACHABLE(); - if (location >= 0) + for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++) { - return uniform->type == constant.type; + const sh::Uniform &uniform = vertexUniforms[uniformIndex]; + defineUniformBase(GL_VERTEX_SHADER, uniform, vertexShader.getUniformRegister(uniform.name)); } - mUniforms.push_back(uniform); - unsigned int uniformIndex = mUniforms.size() - 1; + for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++) + { + const sh::Uniform &uniform = fragmentUniforms[uniformIndex]; + defineUniformBase(GL_FRAGMENT_SHADER, uniform, fragmentShader.getUniformRegister(uniform.name)); + } - for (unsigned int i = 0; i < uniform->elementCount(); i++) + if (!indexUniforms(infoLog)) { - mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex)); + return false; } - if (shader == GL_VERTEX_SHADER) + initializeUniformStorage(); + + return true; +} + +void ProgramBinary::defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister) +{ + ShShaderOutput outputType = Shader::getCompilerOutputType(shader); + sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType)); + encoder.skipRegisters(uniformRegister); + + defineUniform(shader, uniform, uniform.name, &encoder); +} + +void ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &uniform, + const std::string &fullName, sh::HLSLBlockEncoder *encoder) +{ + if (uniform.isStruct()) + { + for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++) + { + const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); + + encoder->enterAggregateType(); + + for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++) + { + const sh::Uniform &field = uniform.fields[fieldIndex]; + const std::string &fieldFullName = (fullName + elementString + "." + field.name); + + defineUniform(shader, field, fieldFullName, encoder); + } + + encoder->exitAggregateType(); + } + } + else // Not a struct + { + // Arrays are treated as aggregate types + if (uniform.isArray()) + { + encoder->enterAggregateType(); + } + + LinkedUniform *linkedUniform = getUniformByName(fullName); + + if (!linkedUniform) + { + linkedUniform = new LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize, + -1, sh::BlockMemberInfo::getDefaultBlockInfo()); + ASSERT(linkedUniform); + linkedUniform->registerElement = encoder->getCurrentElement(); + mUniforms.push_back(linkedUniform); + } + + ASSERT(linkedUniform->registerElement == encoder->getCurrentElement()); + + if (shader == GL_FRAGMENT_SHADER) + { + linkedUniform->psRegisterIndex = encoder->getCurrentRegister(); + } + else if (shader == GL_VERTEX_SHADER) + { + linkedUniform->vsRegisterIndex = encoder->getCurrentRegister(); + } + else UNREACHABLE(); + + // Advance the uniform offset, to track registers allocation for structs + encoder->encodeType(uniform.type, uniform.arraySize, false); + + // Arrays are treated as aggregate types + if (uniform.isArray()) + { + encoder->exitAggregateType(); + } + } +} + +bool ProgramBinary::indexSamplerUniform(const LinkedUniform &uniform, InfoLog &infoLog) +{ + ASSERT(IsSampler(uniform.type)); + ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX); + + if (uniform.vsRegisterIndex != GL_INVALID_INDEX) { - if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors()) + if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS, + &mUsedVertexSamplerRange, mRenderer->getMaxVertexTextureImageUnits())) + { + infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", + mRenderer->getMaxVertexTextureImageUnits()); + return false; + } + + unsigned int maxVertexVectors = mRenderer->getReservedVertexUniformVectors() + + mRenderer->getMaxVertexUniformVectors(); + if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors) { - infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors()); + infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", + mRenderer->getMaxVertexUniformVectors()); return false; } } - else if (shader == GL_FRAGMENT_SHADER) + + if (uniform.psRegisterIndex != GL_INVALID_INDEX) { - if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors()) + if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS, + &mUsedPixelSamplerRange, MAX_TEXTURE_IMAGE_UNITS)) { - infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors()); + infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", + MAX_TEXTURE_IMAGE_UNITS); + return false; + } + + unsigned int maxFragmentVectors = mRenderer->getReservedFragmentUniformVectors() + + mRenderer->getMaxFragmentUniformVectors(); + if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors) + { + infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", + mRenderer->getMaxFragmentUniformVectors()); return false; } } - else UNREACHABLE(); return true; } -std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const +bool ProgramBinary::indexUniforms(InfoLog &infoLog) { - // for now we only handle point sprite emulation - ASSERT(usesPointSpriteEmulation()); - return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader); + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const LinkedUniform &uniform = *mUniforms[uniformIndex]; + + if (IsSampler(uniform.type)) + { + if (!indexSamplerUniform(uniform, infoLog)) + { + return false; + } + } + + for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++) + { + mUniformIndex.push_back(VariableLocation(uniform.name, arrayElementIndex, uniformIndex)); + } + } + + return true; } -std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const +bool ProgramBinary::assignSamplers(unsigned int startSamplerIndex, + GLenum samplerType, + unsigned int samplerCount, + Sampler *outArray, + GLuint *usedRange, + unsigned int limit) { - ASSERT(registers >= 0); - ASSERT(vertexShader->mUsesPointSize); - ASSERT(mRenderer->getMajorShaderModel() >= 4); + unsigned int samplerIndex = startSamplerIndex; - std::string geomHLSL; + do + { + if (samplerIndex < limit) + { + outArray[samplerIndex].active = true; + outArray[samplerIndex].textureType = GetTextureType(samplerType); + outArray[samplerIndex].logicalTextureUnit = 0; + *usedRange = std::max(samplerIndex + 1, *usedRange); + } + else + { + return false; + } - std::string varyingSemantic = "TEXCOORD"; + samplerIndex++; + } while (samplerIndex < startSamplerIndex + samplerCount); - std::string fragCoordSemantic; - std::string pointCoordSemantic; + return true; +} - int reservedRegisterIndex = registers; +bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock) +{ + const char* blockName = vertexInterfaceBlock.name.c_str(); - if (fragmentShader->mUsesFragCoord) + // validate blocks for the same member types + if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size()) { - fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); + infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName); + return false; } - if (fragmentShader->mUsesPointCoord) + if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize) { - pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); + infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName); + return false; } - geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n" - "\n" - "struct GS_INPUT\n" - "{\n"; - - for (int r = 0; r < registers; r++) + if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout) { - int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1)); - - geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n"; + infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName); + return false; } - if (fragmentShader->mUsesFragCoord) + const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size(); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++) { - geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; + const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex]; + const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex]; + + if (vertexMember.name != fragmentMember.name) + { + infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')", + blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str()); + return false; + } + + std::string uniformName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'"; + if (!linkValidateVariables(infoLog, uniformName, vertexMember, fragmentMember)) + { + return false; + } } - geomHLSL += " float gl_PointSize : PSIZE;\n" - " float4 gl_Position : SV_Position;\n" - "};\n" - "\n" - "struct GS_OUTPUT\n" - "{\n"; + return true; +} + +bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const VertexShader &vertexShader, + const FragmentShader &fragmentShader) +{ + const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks(); + const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks(); + + // Check that interface blocks defined in the vertex and fragment shaders are identical + typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap; + UniformBlockMap linkedUniformBlocks; - for (int r = 0; r < registers; r++) + for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) { - int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1)); + const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex]; + linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock; + } - geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n"; + for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex]; + UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name); + if (entry != linkedUniformBlocks.end()) + { + const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second; + if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock)) + { + return false; + } + } } - if (fragmentShader->mUsesFragCoord) + for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) { - geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n"; + if (!defineUniformBlock(infoLog, vertexShader, vertexInterfaceBlocks[blockIndex])) + { + return false; + } } - if (fragmentShader->mUsesPointCoord) + for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) { - geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n"; + if (!defineUniformBlock(infoLog, fragmentShader, fragmentInterfaceBlocks[blockIndex])) + { + return false; + } } - geomHLSL += " float gl_PointSize : PSIZE;\n" - " float4 gl_Position : SV_Position;\n" - "};\n" - "\n" - "static float2 pointSpriteCorners[] = \n" - "{\n" - " float2( 0.5f, -0.5f),\n" - " float2( 0.5f, 0.5f),\n" - " float2(-0.5f, -0.5f),\n" - " float2(-0.5f, 0.5f)\n" - "};\n" - "\n" - "static float2 pointSpriteTexcoords[] = \n" - "{\n" - " float2(1.0f, 1.0f),\n" - " float2(1.0f, 0.0f),\n" - " float2(0.0f, 1.0f),\n" - " float2(0.0f, 0.0f)\n" - "};\n" - "\n" - "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n" - "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n" - "\n" - "[maxvertexcount(4)]\n" - "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n" - "{\n" - " GS_OUTPUT output = (GS_OUTPUT)0;\n" - " output.gl_PointSize = input[0].gl_PointSize;\n"; + return true; +} + +bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings, + const std::vector<std::string> &transformFeedbackVaryingNames, + GLenum transformFeedbackBufferMode, + std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings) const +{ + size_t totalComponents = 0; + const size_t maxSeparateComponents = mRenderer->getMaxTransformFeedbackSeparateComponents(); + const size_t maxInterleavedComponents = mRenderer->getMaxTransformFeedbackInterleavedComponents(); - for (int r = 0; r < registers; r++) + // Gather the linked varyings that are used for transform feedback, they should all exist. + outTransformFeedbackLinkedVaryings->clear(); + for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++) { - geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n"; + bool found = false; + for (size_t j = 0; j < linkedVaryings.size(); j++) + { + if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name) + { + for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++) + { + if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name) + { + infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str()); + return false; + } + } + + size_t componentCount = linkedVaryings[j].semanticIndexCount * 4; + if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS && + componentCount > maxSeparateComponents) + { + infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).", + linkedVaryings[j].name.c_str(), componentCount, maxSeparateComponents); + return false; + } + + totalComponents += componentCount; + + outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]); + found = true; + break; + } + } + + // All transform feedback varyings are expected to exist since packVaryings checks for them. + ASSERT(found); } - if (fragmentShader->mUsesFragCoord) + if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > maxInterleavedComponents) { - geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n"; + infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).", + totalComponents, maxInterleavedComponents); + return false; } - geomHLSL += " \n" - " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n" - " float4 gl_Position = input[0].gl_Position;\n" - " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * gl_Position.w;\n"; + return true; +} - for (int corner = 0; corner < 4; corner++) +void ProgramBinary::defineUniformBlockMembers(const std::vector<sh::InterfaceBlockField> &fields, const std::string &prefix, int blockIndex, + sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes) +{ + for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++) { - geomHLSL += " \n" - " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n"; + const sh::InterfaceBlockField &field = fields[uniformIndex]; + const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); - if (fragmentShader->mUsesPointCoord) + if (field.isStruct()) { - geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n"; + for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) + { + encoder->enterAggregateType(); + + const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : ""); + defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes); + + encoder->exitAggregateType(); + } } + else + { + sh::BlockMemberInfo memberInfo = encoder->encodeInterfaceBlockField(field); + + LinkedUniform *newUniform = new LinkedUniform(field.type, field.precision, fieldName, field.arraySize, + blockIndex, memberInfo); - geomHLSL += " outStream.Append(output);\n"; + // add to uniform list, but not index, since uniform block uniforms have no location + blockUniformIndexes->push_back(mUniforms.size()); + mUniforms.push_back(newUniform); + } } +} + +bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, const Shader &shader, const sh::InterfaceBlock &interfaceBlock) +{ + // create uniform block entries if they do not exist + if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX) + { + std::vector<unsigned int> blockUniformIndexes; + const unsigned int blockIndex = mUniformBlocks.size(); + + // define member uniforms + sh::BlockLayoutEncoder *encoder = NULL; + + if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD) + { + encoder = new sh::Std140BlockEncoder; + } + else + { + encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED); + } + ASSERT(encoder); + + defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes); - geomHLSL += " \n" - " outStream.RestartStrip();\n" - "}\n"; + size_t dataSize = encoder->getBlockSize(); - return geomHLSL; + // create all the uniform blocks + if (interfaceBlock.arraySize > 0) + { + for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++) + { + UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize); + newUniformBlock->memberUniformIndexes = blockUniformIndexes; + mUniformBlocks.push_back(newUniformBlock); + } + } + else + { + UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize); + newUniformBlock->memberUniformIndexes = blockUniformIndexes; + mUniformBlocks.push_back(newUniformBlock); + } + } + + // Assign registers to the uniform blocks + const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name); + const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize); + ASSERT(blockIndex != GL_INVALID_INDEX); + ASSERT(blockIndex + elementCount <= mUniformBlocks.size()); + + unsigned int interfaceBlockRegister = shader.getInterfaceBlockRegister(interfaceBlock.name); + + for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++) + { + UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement]; + ASSERT(uniformBlock->name == interfaceBlock.name); + + if (!assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(), + interfaceBlockRegister + uniformBlockElement)) + { + return false; + } + } + + return true; } -// This method needs to match OutputHLSL::decorate -std::string ProgramBinary::decorateAttribute(const std::string &name) +bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex) { - if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0) + if (shader == GL_VERTEX_SHADER) { - return "_" + name; + uniformBlock->vsRegisterIndex = registerIndex; + unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers(); + + if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks) + { + infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks); + return false; + } } - - return name; + else if (shader == GL_FRAGMENT_SHADER) + { + uniformBlock->psRegisterIndex = registerIndex; + unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers(); + + if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks) + { + infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", maximumBlocks); + return false; + } + } + else UNREACHABLE(); + + return true; } -bool ProgramBinary::isValidated() const +bool ProgramBinary::isValidated() const { return mValidated; } @@ -2500,6 +2535,141 @@ GLint ProgramBinary::getActiveUniformMaxLength() const return maxLength; } +GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const +{ + const gl::LinkedUniform& uniform = *mUniforms[index]; + + switch (pname) + { + case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type); + case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount()); + case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0)); + case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex; + + case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset; + case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride; + case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride; + case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix); + + default: + UNREACHABLE(); + break; + } + return 0; +} + +bool ProgramBinary::isValidUniformLocation(GLint location) const +{ + ASSERT(rx::IsIntegerCastSafe<GLint>(mUniformIndex.size())); + return (location >= 0 && location < static_cast<GLint>(mUniformIndex.size())); +} + +LinkedUniform *ProgramBinary::getUniformByLocation(GLint location) const +{ + ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformIndex.size()); + return mUniforms[mUniformIndex[location].index]; +} + +LinkedUniform *ProgramBinary::getUniformByName(const std::string &name) const +{ + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + if (mUniforms[uniformIndex]->name == name) + { + return mUniforms[uniformIndex]; + } + } + + return NULL; +} + +void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const +{ + ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount() + + const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex]; + + if (bufSize > 0) + { + std::string string = uniformBlock.name; + + if (uniformBlock.isArrayElement()) + { + string += ArrayString(uniformBlock.elementIndex); + } + + strncpy(uniformBlockName, string.c_str(), bufSize); + uniformBlockName[bufSize - 1] = '\0'; + + if (length) + { + *length = strlen(uniformBlockName); + } + } +} + +void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const +{ + ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount() + + const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex]; + + switch (pname) + { + case GL_UNIFORM_BLOCK_DATA_SIZE: + *params = static_cast<GLint>(uniformBlock.dataSize); + break; + case GL_UNIFORM_BLOCK_NAME_LENGTH: + *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0)); + break; + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size()); + break; + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + { + for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) + { + params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]); + } + } + break; + case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader()); + break; + case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: + *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader()); + break; + default: UNREACHABLE(); + } +} + +GLuint ProgramBinary::getActiveUniformBlockCount() const +{ + return mUniformBlocks.size(); +} + +GLuint ProgramBinary::getActiveUniformBlockMaxLength() const +{ + unsigned int maxLength = 0; + + unsigned int numUniformBlocks = mUniformBlocks.size(); + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++) + { + const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex]; + if (!uniformBlock.name.empty()) + { + const unsigned int length = uniformBlock.name.length() + 1; + + // Counting in "[0]". + const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0); + + maxLength = std::max(length + arrayLength, maxLength); + } + } + + return maxLength; +} + void ProgramBinary::validate(InfoLog &infoLog) { applyUniforms(); @@ -2518,6 +2688,7 @@ bool ProgramBinary::validateSamplers(InfoLog *infoLog) // if any two active samplers in a program are of different types, but refer to the same // texture image unit, and this is the current program, then ValidateProgram will fail, and // DrawArrays and DrawElements will issue the INVALID_OPERATION error. + updateSamplerMapping(); const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits(); TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS]; @@ -2532,7 +2703,7 @@ bool ProgramBinary::validateSamplers(InfoLog *infoLog) if (mSamplersPS[i].active) { unsigned int unit = mSamplersPS[i].logicalTextureUnit; - + if (unit >= maxCombinedTextureImageUnits) { if (infoLog) @@ -2567,7 +2738,7 @@ bool ProgramBinary::validateSamplers(InfoLog *infoLog) if (mSamplersVS[i].active) { unsigned int unit = mSamplersVS[i].logicalTextureUnit; - + if (unit >= maxCombinedTextureImageUnits) { if (infoLog) @@ -2648,4 +2819,71 @@ void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MA } } +void ProgramBinary::initializeUniformStorage() +{ + // Compute total default block size + unsigned int vertexRegisters = 0; + unsigned int fragmentRegisters = 0; + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const LinkedUniform &uniform = *mUniforms[uniformIndex]; + + if (!IsSampler(uniform.type)) + { + if (uniform.isReferencedByVertexShader()) + { + vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount); + } + if (uniform.isReferencedByFragmentShader()) + { + fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount); + } + } + } + + mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u); + mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u); +} + +void ProgramBinary::reset() +{ + mVertexHLSL.clear(); + mVertexWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE; + SafeDeleteContainer(mVertexExecutables); + + mPixelHLSL.clear(); + mPixelWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE; + mUsesFragDepth = false; + mPixelShaderKey.clear(); + SafeDeleteContainer(mPixelExecutables); + + SafeDelete(mGeometryExecutable); + + mTransformFeedbackBufferMode = GL_NONE; + mTransformFeedbackLinkedVaryings.clear(); + + for (size_t i = 0; i < ArraySize(mSamplersPS); i++) + { + mSamplersPS[i] = Sampler(); + } + for (size_t i = 0; i < ArraySize(mSamplersVS); i++) + { + mSamplersVS[i] = Sampler(); + } + mUsedVertexSamplerRange = 0; + mUsedPixelSamplerRange = 0; + mUsesPointSize = false; + mShaderVersion = 0; + mDirtySamplerMapping = true; + + SafeDeleteContainer(mUniforms); + SafeDeleteContainer(mUniformBlocks); + mUniformIndex.clear(); + mOutputVariables.clear(); + SafeDelete(mVertexUniformStorage); + SafeDelete(mFragmentUniformStorage); + + mValidated = false; +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h index d6320863f2..f0fc431021 100644 --- a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h +++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,25 +10,31 @@ #ifndef LIBGLESV2_PROGRAM_BINARY_H_ #define LIBGLESV2_PROGRAM_BINARY_H_ -#define GL_APICALL -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> +#include "angle_gl.h" #include <string> #include <vector> #include "common/RefCountObject.h" #include "angletypes.h" -#include "libGLESv2/mathutil.h" +#include "common/mathutil.h" #include "libGLESv2/Uniform.h" #include "libGLESv2/Shader.h" #include "libGLESv2/Constants.h" +#include "libGLESv2/renderer/d3d/VertexDataManager.h" +#include "libGLESv2/DynamicHLSL.h" + +namespace sh +{ +class HLSLBlockEncoder; +} namespace rx { class ShaderExecutable; class Renderer; struct TranslatedAttribute; +class UniformStorage; } namespace gl @@ -37,22 +43,41 @@ class FragmentShader; class VertexShader; class InfoLog; class AttributeBindings; -struct Varying; +class Buffer; +class Framebuffer; // Struct used for correlating uniforms/elements of uniform arrays to handles -struct UniformLocation +struct VariableLocation { - UniformLocation() + VariableLocation() { } - UniformLocation(const std::string &name, unsigned int element, unsigned int index); + VariableLocation(const std::string &name, unsigned int element, unsigned int index); std::string name; unsigned int element; unsigned int index; }; +struct LinkedVarying +{ + LinkedVarying(); + LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName, + unsigned int semanticIndex, unsigned int semanticIndexCount); + + // Original GL name + std::string name; + + GLenum type; + GLsizei size; + + // DirectX semantic information + std::string semanticName; + unsigned int semanticIndex; + unsigned int semanticIndexCount; +}; + // This is the result of linking a program. It is the state that would be passed to ProgramBinary. class ProgramBinary : public RefCountObject { @@ -60,9 +85,10 @@ class ProgramBinary : public RefCountObject explicit ProgramBinary(rx::Renderer *renderer); ~ProgramBinary(); - rx::ShaderExecutable *getPixelExecutable(); - rx::ShaderExecutable *getVertexExecutable(); - rx::ShaderExecutable *getGeometryExecutable(); + rx::ShaderExecutable *getPixelExecutableForFramebuffer(const Framebuffer *fbo); + rx::ShaderExecutable *getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputLayout); + rx::ShaderExecutable *getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]); + rx::ShaderExecutable *getGeometryExecutable() const; GLuint getAttributeLocation(const char *name); int getSemanticIndex(int attributeIndex); @@ -75,29 +101,44 @@ class ProgramBinary : public RefCountObject bool usesGeometryShader() const; GLint getUniformLocation(std::string name); - bool setUniform1fv(GLint location, GLsizei count, const GLfloat *v); - bool setUniform2fv(GLint location, GLsizei count, const GLfloat *v); - bool setUniform3fv(GLint location, GLsizei count, const GLfloat *v); - bool setUniform4fv(GLint location, GLsizei count, const GLfloat *v); - bool setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value); - bool setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value); - bool setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value); - bool setUniform1iv(GLint location, GLsizei count, const GLint *v); - bool setUniform2iv(GLint location, GLsizei count, const GLint *v); - bool setUniform3iv(GLint location, GLsizei count, const GLint *v); - bool setUniform4iv(GLint location, GLsizei count, const GLint *v); + GLuint getUniformIndex(std::string name); + GLuint getUniformBlockIndex(std::string name); + void setUniform1fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform2fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform3fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform4fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform1iv(GLint location, GLsizei count, const GLint *v); + void setUniform2iv(GLint location, GLsizei count, const GLint *v); + void setUniform3iv(GLint location, GLsizei count, const GLint *v); + void setUniform4iv(GLint location, GLsizei count, const GLint *v); + void setUniform1uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform2uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform3uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform4uiv(GLint location, GLsizei count, const GLuint *v); + void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); bool getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params); bool getUniformiv(GLint location, GLsizei *bufSize, GLint *params); + bool getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params); void dirtyAllUniforms(); void applyUniforms(); + bool applyUniformBuffers(const std::vector<Buffer*> boundBuffers); bool load(InfoLog &infoLog, const void *binary, GLsizei length); bool save(void* binary, GLsizei bufSize, GLsizei *length); GLint getLength(); - bool link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader); + bool link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader, + const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode); void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders); void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const; @@ -107,62 +148,165 @@ class ProgramBinary : public RefCountObject void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const; GLint getActiveUniformCount() const; GLint getActiveUniformMaxLength() const; + GLint getActiveUniformi(GLuint index, GLenum pname) const; + bool isValidUniformLocation(GLint location) const; + LinkedUniform *getUniformByLocation(GLint location) const; + LinkedUniform *getUniformByName(const std::string &name) const; + + void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const; + void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const; + GLuint getActiveUniformBlockCount() const; + GLuint getActiveUniformBlockMaxLength() const; + UniformBlock *getUniformBlockByIndex(GLuint blockIndex); + + GLint getFragDataLocation(const char *name) const; + + size_t getTransformFeedbackVaryingCount() const; + const LinkedVarying &getTransformFeedbackVarying(size_t idx) const; + GLenum getTransformFeedbackBufferMode() const; void validate(InfoLog &infoLog); bool validateSamplers(InfoLog *infoLog); bool isValidated() const; + void updateSamplerMapping(); unsigned int getSerial() const; + int getShaderVersion() const; void initAttributesByLayout(); - void sortAttributesByLayout(rx::TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const; + void sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const; - static std::string decorateAttribute(const std::string &name); // Prepend an underscore + const std::vector<LinkedUniform*> &getUniforms() const { return mUniforms; } + const rx::UniformStorage &getVertexUniformStorage() const { return *mVertexUniformStorage; } + const rx::UniformStorage &getFragmentUniformStorage() const { return *mFragmentUniformStorage; } private: DISALLOW_COPY_AND_ASSIGN(ProgramBinary); - int packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader); - bool linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4], - std::string& pixelHLSL, std::string& vertexHLSL, - FragmentShader *fragmentShader, VertexShader *vertexShader); + struct Sampler + { + Sampler(); + + bool active; + GLint logicalTextureUnit; + TextureType textureType; + }; + void reset(); + + bool linkVaryings(InfoLog &infoLog, FragmentShader *fragmentShader, VertexShader *vertexShader); bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader); - bool linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms); - bool defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog); - - std::string generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const; - std::string generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const; + template <class ShaderVarType> + bool linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar); + bool linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, const sh::ShaderVariable &fragmentVariable, bool validatePrecision); + + bool linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform); + bool linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying); + bool linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform); + bool linkUniforms(InfoLog &infoLog, const VertexShader &vertexShader, const FragmentShader &fragmentShader); + void defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister); + void defineUniform(GLenum shader, const sh::Uniform &uniform, const std::string &fullName, sh::HLSLBlockEncoder *encoder); + bool indexSamplerUniform(const LinkedUniform &uniform, InfoLog &infoLog); + bool indexUniforms(InfoLog &infoLog); + static bool assignSamplers(unsigned int startSamplerIndex, GLenum samplerType, unsigned int samplerCount, + Sampler *outArray, GLuint *usedRange, unsigned int limit); + bool areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock); + bool linkUniformBlocks(InfoLog &infoLog, const VertexShader &vertexShader, const FragmentShader &fragmentShader); + bool gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings, + const std::vector<std::string> &transformFeedbackVaryingNames, + GLenum transformFeedbackBufferMode, + std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings) const; + void defineUniformBlockMembers(const std::vector<sh::InterfaceBlockField> &fields, const std::string &prefix, int blockIndex, + sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes); + bool defineUniformBlock(InfoLog &infoLog, const Shader &shader, const sh::InterfaceBlock &interfaceBlock); + bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex); + void defineOutputVariables(FragmentShader *fragmentShader); + void initializeUniformStorage(); + + template <typename T> + void setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType); + + template <int cols, int rows> + void setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType); + + template <typename T> + bool getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType); + + class VertexExecutable + { + public: + VertexExecutable(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS], + const GLenum signature[MAX_VERTEX_ATTRIBS], + rx::ShaderExecutable *shaderExecutable); + ~VertexExecutable(); + + bool matchesSignature(const GLenum convertedLayout[MAX_VERTEX_ATTRIBS]) const; + + const VertexFormat *inputs() const { return mInputs; } + const GLenum *signature() const { return mSignature; } + rx::ShaderExecutable *shaderExecutable() const { return mShaderExecutable; } + + private: + VertexFormat mInputs[MAX_VERTEX_ATTRIBS]; + GLenum mSignature[MAX_VERTEX_ATTRIBS]; + rx::ShaderExecutable *mShaderExecutable; + }; + + class PixelExecutable + { + public: + PixelExecutable(const std::vector<GLenum> &outputSignature, rx::ShaderExecutable *shaderExecutable); + ~PixelExecutable(); + + // FIXME(geofflang): Work around NVIDIA driver bug by repacking buffers + bool matchesSignature(const std::vector<GLenum> &signature) const { return true; /* mOutputSignature == signature; */ } + + const std::vector<GLenum> &outputSignature() const { return mOutputSignature; } + rx::ShaderExecutable *shaderExecutable() const { return mShaderExecutable; } + + private: + std::vector<GLenum> mOutputSignature; + rx::ShaderExecutable *mShaderExecutable; + }; rx::Renderer *const mRenderer; + DynamicHLSL *mDynamicHLSL; + + std::string mVertexHLSL; + rx::D3DWorkaroundType mVertexWorkarounds; + std::vector<VertexExecutable *> mVertexExecutables; + + std::string mPixelHLSL; + rx::D3DWorkaroundType mPixelWorkarounds; + bool mUsesFragDepth; + std::vector<PixelShaderOuputVariable> mPixelShaderKey; + std::vector<PixelExecutable *> mPixelExecutables; - rx::ShaderExecutable *mPixelExecutable; - rx::ShaderExecutable *mVertexExecutable; rx::ShaderExecutable *mGeometryExecutable; - Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS]; + sh::Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS]; + sh::Attribute mShaderAttributes[MAX_VERTEX_ATTRIBS]; int mSemanticIndex[MAX_VERTEX_ATTRIBS]; int mAttributesByLayout[MAX_VERTEX_ATTRIBS]; - struct Sampler - { - Sampler(); - - bool active; - GLint logicalTextureUnit; - TextureType textureType; - }; + GLenum mTransformFeedbackBufferMode; + std::vector<LinkedVarying> mTransformFeedbackLinkedVaryings; Sampler mSamplersPS[MAX_TEXTURE_IMAGE_UNITS]; Sampler mSamplersVS[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; GLuint mUsedVertexSamplerRange; GLuint mUsedPixelSamplerRange; bool mUsesPointSize; + int mShaderVersion; + bool mDirtySamplerMapping; - UniformArray mUniforms; - typedef std::vector<UniformLocation> UniformIndex; - UniformIndex mUniformIndex; + std::vector<LinkedUniform*> mUniforms; + std::vector<UniformBlock*> mUniformBlocks; + std::vector<VariableLocation> mUniformIndex; + std::map<int, VariableLocation> mOutputVariables; + rx::UniformStorage *mVertexUniformStorage; + rx::UniformStorage *mFragmentUniformStorage; bool mValidated; @@ -171,6 +315,7 @@ class ProgramBinary : public RefCountObject static unsigned int issueSerial(); static unsigned int mCurrentSerial; }; + } #endif // LIBGLESV2_PROGRAM_BINARY_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Query.cpp b/src/3rdparty/angle/src/libGLESv2/Query.cpp index bd987954f1..6546d06c34 100644 --- a/src/3rdparty/angle/src/libGLESv2/Query.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Query.cpp @@ -49,4 +49,9 @@ GLenum Query::getType() const return mQuery->getType(); } +bool Query::isStarted() const +{ + return mQuery->isStarted(); +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/Query.h b/src/3rdparty/angle/src/libGLESv2/Query.h index e9b95b729b..a4726a8e73 100644 --- a/src/3rdparty/angle/src/libGLESv2/Query.h +++ b/src/3rdparty/angle/src/libGLESv2/Query.h @@ -9,8 +9,7 @@ #ifndef LIBGLESV2_QUERY_H_ #define LIBGLESV2_QUERY_H_ -#define GL_APICALL -#include <GLES2/gl2.h> +#include "angle_gl.h" #include "common/angleutils.h" #include "common/RefCountObject.h" @@ -37,6 +36,7 @@ class Query : public RefCountObject GLboolean isResultAvailable(); GLenum getType() const; + bool isStarted() const; private: DISALLOW_COPY_AND_ASSIGN(Query); diff --git a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp index 98d33ec6c3..d4bfaf27a1 100644 --- a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp @@ -14,308 +14,96 @@ #include "libGLESv2/Texture.h" #include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/utilities.h" +#include "common/utilities.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/FramebufferAttachment.h" namespace gl { unsigned int RenderbufferStorage::mCurrentSerial = 1; -RenderbufferInterface::RenderbufferInterface() +Renderbuffer::Renderbuffer(GLuint id, RenderbufferStorage *newStorage) + : RefCountObject(id), + mStorage(newStorage) { + ASSERT(mStorage); } -// The default case for classes inherited from RenderbufferInterface is not to -// need to do anything upon the reference count to the parent Renderbuffer incrementing -// or decrementing. -void RenderbufferInterface::addProxyRef(const Renderbuffer *proxy) -{ -} - -void RenderbufferInterface::releaseProxy(const Renderbuffer *proxy) -{ -} - -GLuint RenderbufferInterface::getRedSize() const -{ - return gl::GetRedSize(getActualFormat()); -} - -GLuint RenderbufferInterface::getGreenSize() const -{ - return gl::GetGreenSize(getActualFormat()); -} - -GLuint RenderbufferInterface::getBlueSize() const -{ - return gl::GetBlueSize(getActualFormat()); -} - -GLuint RenderbufferInterface::getAlphaSize() const -{ - return gl::GetAlphaSize(getActualFormat()); -} - -GLuint RenderbufferInterface::getDepthSize() const -{ - return gl::GetDepthSize(getActualFormat()); -} - -GLuint RenderbufferInterface::getStencilSize() const -{ - return gl::GetStencilSize(getActualFormat()); -} - -///// RenderbufferTexture2D Implementation //////// - -RenderbufferTexture2D::RenderbufferTexture2D(Texture2D *texture, GLenum target) : mTarget(target) -{ - mTexture2D.set(texture); -} - -RenderbufferTexture2D::~RenderbufferTexture2D() -{ - mTexture2D.set(NULL); -} - -// Textures need to maintain their own reference count for references via -// Renderbuffers acting as proxies. Here, we notify the texture of a reference. -void RenderbufferTexture2D::addProxyRef(const Renderbuffer *proxy) -{ - mTexture2D->addProxyRef(proxy); -} - -void RenderbufferTexture2D::releaseProxy(const Renderbuffer *proxy) -{ - mTexture2D->releaseProxy(proxy); -} - -rx::RenderTarget *RenderbufferTexture2D::getRenderTarget() -{ - return mTexture2D->getRenderTarget(mTarget); -} - -rx::RenderTarget *RenderbufferTexture2D::getDepthStencil() -{ - return mTexture2D->getDepthStencil(mTarget); -} - -GLsizei RenderbufferTexture2D::getWidth() const -{ - return mTexture2D->getWidth(0); -} - -GLsizei RenderbufferTexture2D::getHeight() const -{ - return mTexture2D->getHeight(0); -} - -GLenum RenderbufferTexture2D::getInternalFormat() const -{ - return mTexture2D->getInternalFormat(0); -} - -GLenum RenderbufferTexture2D::getActualFormat() const -{ - return mTexture2D->getActualFormat(0); -} - -GLsizei RenderbufferTexture2D::getSamples() const -{ - return 0; -} - -unsigned int RenderbufferTexture2D::getSerial() const -{ - return mTexture2D->getRenderTargetSerial(mTarget); -} - -unsigned int RenderbufferTexture2D::getTextureSerial() const -{ - return mTexture2D->getTextureSerial(); -} - -///// RenderbufferTextureCubeMap Implementation //////// - -RenderbufferTextureCubeMap::RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target) : mTarget(target) -{ - mTextureCubeMap.set(texture); -} - -RenderbufferTextureCubeMap::~RenderbufferTextureCubeMap() -{ - mTextureCubeMap.set(NULL); -} - -// Textures need to maintain their own reference count for references via -// Renderbuffers acting as proxies. Here, we notify the texture of a reference. -void RenderbufferTextureCubeMap::addProxyRef(const Renderbuffer *proxy) -{ - mTextureCubeMap->addProxyRef(proxy); -} - -void RenderbufferTextureCubeMap::releaseProxy(const Renderbuffer *proxy) -{ - mTextureCubeMap->releaseProxy(proxy); -} - -rx::RenderTarget *RenderbufferTextureCubeMap::getRenderTarget() -{ - return mTextureCubeMap->getRenderTarget(mTarget); -} - -rx::RenderTarget *RenderbufferTextureCubeMap::getDepthStencil() -{ - return NULL; -} - -GLsizei RenderbufferTextureCubeMap::getWidth() const -{ - return mTextureCubeMap->getWidth(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); -} - -GLsizei RenderbufferTextureCubeMap::getHeight() const -{ - return mTextureCubeMap->getHeight(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); -} - -GLenum RenderbufferTextureCubeMap::getInternalFormat() const -{ - return mTextureCubeMap->getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); -} - -GLenum RenderbufferTextureCubeMap::getActualFormat() const -{ - return mTextureCubeMap->getActualFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); -} - -GLsizei RenderbufferTextureCubeMap::getSamples() const -{ - return 0; -} - -unsigned int RenderbufferTextureCubeMap::getSerial() const -{ - return mTextureCubeMap->getRenderTargetSerial(mTarget); -} - -unsigned int RenderbufferTextureCubeMap::getTextureSerial() const -{ - return mTextureCubeMap->getTextureSerial(); -} - -////// Renderbuffer Implementation ////// - -Renderbuffer::Renderbuffer(rx::Renderer *renderer, GLuint id, RenderbufferInterface *instance) : RefCountObject(id) -{ - ASSERT(instance != NULL); - mInstance = instance; -} - -Renderbuffer::~Renderbuffer() -{ - delete mInstance; -} - -// The RenderbufferInterface contained in this Renderbuffer may need to maintain -// its own reference count, so we pass it on here. -void Renderbuffer::addRef() const -{ - mInstance->addProxyRef(this); - - RefCountObject::addRef(); -} - -void Renderbuffer::release() const +void Renderbuffer::setStorage(RenderbufferStorage *newStorage) { - mInstance->releaseProxy(this); + ASSERT(newStorage); - RefCountObject::release(); + SafeDelete(mStorage); + mStorage = newStorage; } -rx::RenderTarget *Renderbuffer::getRenderTarget() +RenderbufferStorage *Renderbuffer::getStorage() { - return mInstance->getRenderTarget(); -} - -rx::RenderTarget *Renderbuffer::getDepthStencil() -{ - return mInstance->getDepthStencil(); + ASSERT(mStorage); + return mStorage; } GLsizei Renderbuffer::getWidth() const { - return mInstance->getWidth(); + ASSERT(mStorage); + return mStorage->getWidth(); } GLsizei Renderbuffer::getHeight() const { - return mInstance->getHeight(); + ASSERT(mStorage); + return mStorage->getHeight(); } GLenum Renderbuffer::getInternalFormat() const { - return mInstance->getInternalFormat(); + ASSERT(mStorage); + return mStorage->getInternalFormat(); } GLenum Renderbuffer::getActualFormat() const { - return mInstance->getActualFormat(); + ASSERT(mStorage); + return mStorage->getActualFormat(); +} + +GLsizei Renderbuffer::getSamples() const +{ + ASSERT(mStorage); + return mStorage->getSamples(); } GLuint Renderbuffer::getRedSize() const { - return mInstance->getRedSize(); + return gl::GetRedBits(getActualFormat()); } GLuint Renderbuffer::getGreenSize() const { - return mInstance->getGreenSize(); + return gl::GetGreenBits(getActualFormat()); } GLuint Renderbuffer::getBlueSize() const { - return mInstance->getBlueSize(); + return gl::GetBlueBits(getActualFormat()); } GLuint Renderbuffer::getAlphaSize() const { - return mInstance->getAlphaSize(); + return gl::GetAlphaBits(getActualFormat()); } GLuint Renderbuffer::getDepthSize() const { - return mInstance->getDepthSize(); + return gl::GetDepthBits(getActualFormat()); } GLuint Renderbuffer::getStencilSize() const { - return mInstance->getStencilSize(); -} - -GLsizei Renderbuffer::getSamples() const -{ - return mInstance->getSamples(); -} - -unsigned int Renderbuffer::getSerial() const -{ - return mInstance->getSerial(); -} - -unsigned int Renderbuffer::getTextureSerial() const -{ - return mInstance->getTextureSerial(); + return gl::GetStencilBits(getActualFormat()); } -void Renderbuffer::setStorage(RenderbufferStorage *newStorage) -{ - ASSERT(newStorage != NULL); - - delete mInstance; - mInstance = newStorage; -} - -RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerial()) +RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerials(1)) { mWidth = 0; mHeight = 0; @@ -368,16 +156,21 @@ unsigned int RenderbufferStorage::getSerial() const return mSerial; } -unsigned int RenderbufferStorage::issueSerial() +unsigned int RenderbufferStorage::issueSerials(GLuint count) { - return mCurrentSerial++; + unsigned int firstSerial = mCurrentSerial; + mCurrentSerial += count; + return firstSerial; } -unsigned int RenderbufferStorage::issueCubeSerials() +bool RenderbufferStorage::isTexture() const { - unsigned int firstSerial = mCurrentSerial; - mCurrentSerial += 6; - return firstSerial; + return false; +} + +unsigned int RenderbufferStorage::getTextureSerial() const +{ + return -1; } Colorbuffer::Colorbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain) @@ -396,7 +189,7 @@ Colorbuffer::Colorbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain) Colorbuffer::Colorbuffer(rx::Renderer *renderer, int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL) { - mRenderTarget = renderer->createRenderTarget(width, height, format, samples, false); + mRenderTarget = renderer->createRenderTarget(width, height, format, samples); if (mRenderTarget) { @@ -418,12 +211,7 @@ Colorbuffer::~Colorbuffer() rx::RenderTarget *Colorbuffer::getRenderTarget() { - if (mRenderTarget) - { - return mRenderTarget; - } - - return NULL; + return mRenderTarget; } DepthStencilbuffer::DepthStencilbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain) @@ -442,7 +230,7 @@ DepthStencilbuffer::DepthStencilbuffer(rx::Renderer *renderer, rx::SwapChain *sw DepthStencilbuffer::DepthStencilbuffer(rx::Renderer *renderer, int width, int height, GLsizei samples) { - mDepthStencil = renderer->createRenderTarget(width, height, GL_DEPTH24_STENCIL8_OES, samples, true); + mDepthStencil = renderer->createRenderTarget(width, height, GL_DEPTH24_STENCIL8_OES, samples); mWidth = mDepthStencil->getWidth(); mHeight = mDepthStencil->getHeight(); @@ -461,12 +249,7 @@ DepthStencilbuffer::~DepthStencilbuffer() rx::RenderTarget *DepthStencilbuffer::getDepthStencil() { - if (mDepthStencil) - { - return mDepthStencil; - } - - return NULL; + return mDepthStencil; } Depthbuffer::Depthbuffer(rx::Renderer *renderer, int width, int height, GLsizei samples) : DepthStencilbuffer(renderer, width, height, samples) diff --git a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h index d46fd44557..e2d0c6b0fd 100644 --- a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h +++ b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h @@ -12,8 +12,7 @@ #ifndef LIBGLESV2_RENDERBUFFER_H_ #define LIBGLESV2_RENDERBUFFER_H_ -#define GL_APICALL -#include <GLES2/gl2.h> +#include "angle_gl.h" #include "common/angleutils.h" #include "common/RefCountObject.h" @@ -23,35 +22,32 @@ namespace rx class Renderer; class SwapChain; class RenderTarget; +class TextureStorage; } namespace gl { -class Texture2D; -class TextureCubeMap; -class Renderbuffer; -class Colorbuffer; -class DepthStencilbuffer; +class RenderbufferStorage; +class FramebufferAttachment; -class RenderbufferInterface +// A GL renderbuffer object is usually used as a depth or stencil buffer attachment +// for a framebuffer object. The renderbuffer itself is a distinct GL object, see +// FramebufferAttachment and Framebuffer for how they are applied to an FBO via an +// attachment point. + +class Renderbuffer : public RefCountObject { public: - RenderbufferInterface(); - - virtual ~RenderbufferInterface() {}; - - virtual void addProxyRef(const Renderbuffer *proxy); - virtual void releaseProxy(const Renderbuffer *proxy); - - virtual rx::RenderTarget *getRenderTarget() = 0; - virtual rx::RenderTarget *getDepthStencil() = 0; + Renderbuffer(GLuint id, RenderbufferStorage *newStorage); - virtual GLsizei getWidth() const = 0; - virtual GLsizei getHeight() const = 0; - virtual GLenum getInternalFormat() const = 0; - virtual GLenum getActualFormat() const = 0; - virtual GLsizei getSamples() const = 0; + void setStorage(RenderbufferStorage *newStorage); + RenderbufferStorage *getStorage(); + GLsizei getWidth() const; + GLsizei getHeight() const; + GLenum getInternalFormat() const; + GLenum getActualFormat() const; + GLsizei getSamples() const; GLuint getRedSize() const; GLuint getGreenSize() const; GLuint getBlueSize() const; @@ -59,75 +55,14 @@ class RenderbufferInterface GLuint getDepthSize() const; GLuint getStencilSize() const; - virtual unsigned int getSerial() const = 0; - virtual unsigned int getTextureSerial() const = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(RenderbufferInterface); -}; - -class RenderbufferTexture2D : public RenderbufferInterface -{ - public: - RenderbufferTexture2D(Texture2D *texture, GLenum target); - - virtual ~RenderbufferTexture2D(); - - void addProxyRef(const Renderbuffer *proxy); - void releaseProxy(const Renderbuffer *proxy); - - rx::RenderTarget *getRenderTarget(); - rx::RenderTarget *getDepthStencil(); - - virtual GLsizei getWidth() const; - virtual GLsizei getHeight() const; - virtual GLenum getInternalFormat() const; - virtual GLenum getActualFormat() const; - virtual GLsizei getSamples() const; - - virtual unsigned int getSerial() const; - virtual unsigned int getTextureSerial() const; - private: - DISALLOW_COPY_AND_ASSIGN(RenderbufferTexture2D); - - BindingPointer <Texture2D> mTexture2D; - GLenum mTarget; -}; - -class RenderbufferTextureCubeMap : public RenderbufferInterface -{ - public: - RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target); - - virtual ~RenderbufferTextureCubeMap(); - - void addProxyRef(const Renderbuffer *proxy); - void releaseProxy(const Renderbuffer *proxy); - - rx::RenderTarget *getRenderTarget(); - rx::RenderTarget *getDepthStencil(); - - virtual GLsizei getWidth() const; - virtual GLsizei getHeight() const; - virtual GLenum getInternalFormat() const; - virtual GLenum getActualFormat() const; - virtual GLsizei getSamples() const; - - virtual unsigned int getSerial() const; - virtual unsigned int getTextureSerial() const; - - private: - DISALLOW_COPY_AND_ASSIGN(RenderbufferTextureCubeMap); - - BindingPointer <TextureCubeMap> mTextureCubeMap; - GLenum mTarget; + RenderbufferStorage *mStorage; }; // A class derived from RenderbufferStorage is created whenever glRenderbufferStorage // is called. The specific concrete type depends on whether the internal format is // colour depth, stencil or packed depth/stencil. -class RenderbufferStorage : public RenderbufferInterface +class RenderbufferStorage { public: RenderbufferStorage(); @@ -144,10 +79,11 @@ class RenderbufferStorage : public RenderbufferInterface virtual GLsizei getSamples() const; virtual unsigned int getSerial() const; - virtual unsigned int getTextureSerial() const { return 0; } - static unsigned int issueSerial(); - static unsigned int issueCubeSerials(); + virtual bool isTexture() const; + virtual unsigned int getTextureSerial() const; + + static unsigned int issueSerials(GLuint count); protected: GLsizei mWidth; @@ -164,49 +100,6 @@ class RenderbufferStorage : public RenderbufferInterface static unsigned int mCurrentSerial; }; -// Renderbuffer implements the GL renderbuffer object. -// It's only a proxy for a RenderbufferInterface instance; the internal object -// can change whenever glRenderbufferStorage is called. -class Renderbuffer : public RefCountObject -{ - public: - Renderbuffer(rx::Renderer *renderer, GLuint id, RenderbufferInterface *storage); - - virtual ~Renderbuffer(); - - // These functions from RefCountObject are overloaded here because - // Textures need to maintain their own count of references to them via - // Renderbuffers/RenderbufferTextures. These functions invoke those - // reference counting functions on the RenderbufferInterface. - void addRef() const; - void release() const; - - rx::RenderTarget *getRenderTarget(); - rx::RenderTarget *getDepthStencil(); - - GLsizei getWidth() const; - GLsizei getHeight() const; - GLenum getInternalFormat() const; - GLenum getActualFormat() const; - GLuint getRedSize() const; - GLuint getGreenSize() const; - GLuint getBlueSize() const; - GLuint getAlphaSize() const; - GLuint getDepthSize() const; - GLuint getStencilSize() const; - GLsizei getSamples() const; - - unsigned int getSerial() const; - unsigned int getTextureSerial() const; - - void setStorage(RenderbufferStorage *newStorage); - - private: - DISALLOW_COPY_AND_ASSIGN(Renderbuffer); - - RenderbufferInterface *mInstance; -}; - class Colorbuffer : public RenderbufferStorage { public: @@ -261,6 +154,7 @@ class Stencilbuffer : public DepthStencilbuffer private: DISALLOW_COPY_AND_ASSIGN(Stencilbuffer); }; + } #endif // LIBGLESV2_RENDERBUFFER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp b/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp index 58dd44fd95..3606532404 100644 --- a/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp +++ b/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -15,6 +15,9 @@ #include "libGLESv2/Renderbuffer.h" #include "libGLESv2/Shader.h" #include "libGLESv2/Texture.h" +#include "libGLESv2/Sampler.h" +#include "libGLESv2/Fence.h" +#include "libGLESv2/renderer/Renderer.h" namespace gl { @@ -50,6 +53,16 @@ ResourceManager::~ResourceManager() { deleteTexture(mTextureMap.begin()->first); } + + while (!mSamplerMap.empty()) + { + deleteSampler(mSamplerMap.begin()->first); + } + + while (!mFenceSyncMap.empty()) + { + deleteFenceSync(mFenceSyncMap.begin()->first); + } } void ResourceManager::addRef() @@ -123,6 +136,26 @@ GLuint ResourceManager::createRenderbuffer() return handle; } +// Returns an unused sampler name +GLuint ResourceManager::createSampler() +{ + GLuint handle = mSamplerHandleAllocator.allocate(); + + mSamplerMap[handle] = NULL; + + return handle; +} + +// Returns the next unused fence name, and allocates the fence +GLuint ResourceManager::createFenceSync() +{ + GLuint handle = mFenceSyncHandleAllocator.allocate(); + + mFenceSyncMap[handle] = new FenceSync(mRenderer, handle); + + return handle; +} + void ResourceManager::deleteBuffer(GLuint buffer) { BufferMap::iterator bufferObject = mBufferMap.find(buffer); @@ -197,6 +230,30 @@ void ResourceManager::deleteRenderbuffer(GLuint renderbuffer) } } +void ResourceManager::deleteSampler(GLuint sampler) +{ + auto samplerObject = mSamplerMap.find(sampler); + + if (samplerObject != mSamplerMap.end()) + { + mSamplerHandleAllocator.release(samplerObject->first); + if (samplerObject->second) samplerObject->second->release(); + mSamplerMap.erase(samplerObject); + } +} + +void ResourceManager::deleteFenceSync(GLuint fenceSync) +{ + auto fenceObjectIt = mFenceSyncMap.find(fenceSync); + + if (fenceObjectIt != mFenceSyncMap.end()) + { + mFenceSyncHandleAllocator.release(fenceObjectIt->first); + if (fenceObjectIt->second) fenceObjectIt->second->release(); + mFenceSyncMap.erase(fenceObjectIt); + } +} + Buffer *ResourceManager::getBuffer(unsigned int handle) { BufferMap::iterator buffer = mBufferMap.find(handle); @@ -269,6 +326,34 @@ Renderbuffer *ResourceManager::getRenderbuffer(unsigned int handle) } } +Sampler *ResourceManager::getSampler(unsigned int handle) +{ + auto sampler = mSamplerMap.find(handle); + + if (sampler == mSamplerMap.end()) + { + return NULL; + } + else + { + return sampler->second; + } +} + +FenceSync *ResourceManager::getFenceSync(unsigned int handle) +{ + auto fenceObjectIt = mFenceSyncMap.find(handle); + + if (fenceObjectIt == mFenceSyncMap.end()) + { + return NULL; + } + else + { + return fenceObjectIt->second; + } +} + void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer) { mRenderbufferMap[handle] = buffer; @@ -278,7 +363,7 @@ void ResourceManager::checkBufferAllocation(unsigned int buffer) { if (buffer != 0 && !getBuffer(buffer)) { - Buffer *bufferObject = new Buffer(mRenderer, buffer); + Buffer *bufferObject = new Buffer(mRenderer->createBuffer(), buffer); mBufferMap[buffer] = bufferObject; bufferObject->addRef(); } @@ -292,11 +377,19 @@ void ResourceManager::checkTextureAllocation(GLuint texture, TextureType type) if (type == TEXTURE_2D) { - textureObject = new Texture2D(mRenderer, texture); + textureObject = new Texture2D(mRenderer->createTexture2D(), texture); } else if (type == TEXTURE_CUBE) { - textureObject = new TextureCubeMap(mRenderer, texture); + textureObject = new TextureCubeMap(mRenderer->createTextureCube(), texture); + } + else if (type == TEXTURE_3D) + { + textureObject = new Texture3D(mRenderer->createTexture3D(), texture); + } + else if (type == TEXTURE_2D_ARRAY) + { + textureObject = new Texture2DArray(mRenderer->createTexture2DArray(), texture); } else { @@ -313,10 +406,25 @@ void ResourceManager::checkRenderbufferAllocation(GLuint renderbuffer) { if (renderbuffer != 0 && !getRenderbuffer(renderbuffer)) { - Renderbuffer *renderbufferObject = new Renderbuffer(mRenderer, renderbuffer, new Colorbuffer(mRenderer, 0, 0, GL_RGBA4, 0)); + Renderbuffer *renderbufferObject = new Renderbuffer(renderbuffer, new Colorbuffer(mRenderer, 0, 0, GL_RGBA4, 0)); mRenderbufferMap[renderbuffer] = renderbufferObject; renderbufferObject->addRef(); } } +void ResourceManager::checkSamplerAllocation(GLuint sampler) +{ + if (sampler != 0 && !getSampler(sampler)) + { + Sampler *samplerObject = new Sampler(sampler); + mSamplerMap[sampler] = samplerObject; + samplerObject->addRef(); + } +} + +bool ResourceManager::isSampler(GLuint sampler) +{ + return mSamplerMap.find(sampler) != mSamplerMap.end(); +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/ResourceManager.h b/src/3rdparty/angle/src/libGLESv2/ResourceManager.h index e99c77c35d..d646c0d3cf 100644 --- a/src/3rdparty/angle/src/libGLESv2/ResourceManager.h +++ b/src/3rdparty/angle/src/libGLESv2/ResourceManager.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,14 +10,9 @@ #ifndef LIBGLESV2_RESOURCEMANAGER_H_ #define LIBGLESV2_RESOURCEMANAGER_H_ -#define GL_APICALL -#include <GLES2/gl2.h> +#include "angle_gl.h" -#ifdef _MSC_VER -#include <hash_map> -#else #include <unordered_map> -#endif #include "common/angleutils.h" #include "libGLESv2/angletypes.h" @@ -35,6 +30,8 @@ class Shader; class Program; class Texture; class Renderbuffer; +class Sampler; +class FenceSync; class ResourceManager { @@ -50,24 +47,33 @@ class ResourceManager GLuint createProgram(); GLuint createTexture(); GLuint createRenderbuffer(); + GLuint createSampler(); + GLuint createFenceSync(); void deleteBuffer(GLuint buffer); void deleteShader(GLuint shader); void deleteProgram(GLuint program); void deleteTexture(GLuint texture); void deleteRenderbuffer(GLuint renderbuffer); + void deleteSampler(GLuint sampler); + void deleteFenceSync(GLuint fenceSync); Buffer *getBuffer(GLuint handle); Shader *getShader(GLuint handle); Program *getProgram(GLuint handle); Texture *getTexture(GLuint handle); Renderbuffer *getRenderbuffer(GLuint handle); + Sampler *getSampler(GLuint handle); + FenceSync *getFenceSync(GLuint handle); void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer); void checkBufferAllocation(unsigned int buffer); void checkTextureAllocation(GLuint texture, TextureType type); void checkRenderbufferAllocation(GLuint renderbuffer); + void checkSamplerAllocation(GLuint sampler); + + bool isSampler(GLuint sampler); private: DISALLOW_COPY_AND_ASSIGN(ResourceManager); @@ -75,32 +81,32 @@ class ResourceManager std::size_t mRefCount; rx::Renderer *mRenderer; -#ifndef HASH_MAP -# ifdef _MSC_VER -# define HASH_MAP stdext::hash_map -# else -# define HASH_MAP std::unordered_map -# endif -#endif - - typedef HASH_MAP<GLuint, Buffer*> BufferMap; + typedef std::unordered_map<GLuint, Buffer*> BufferMap; BufferMap mBufferMap; HandleAllocator mBufferHandleAllocator; - typedef HASH_MAP<GLuint, Shader*> ShaderMap; + typedef std::unordered_map<GLuint, Shader*> ShaderMap; ShaderMap mShaderMap; - typedef HASH_MAP<GLuint, Program*> ProgramMap; + typedef std::unordered_map<GLuint, Program*> ProgramMap; ProgramMap mProgramMap; HandleAllocator mProgramShaderHandleAllocator; - typedef HASH_MAP<GLuint, Texture*> TextureMap; + typedef std::unordered_map<GLuint, Texture*> TextureMap; TextureMap mTextureMap; HandleAllocator mTextureHandleAllocator; - typedef HASH_MAP<GLuint, Renderbuffer*> RenderbufferMap; + typedef std::unordered_map<GLuint, Renderbuffer*> RenderbufferMap; RenderbufferMap mRenderbufferMap; HandleAllocator mRenderbufferHandleAllocator; + + typedef std::unordered_map<GLuint, Sampler*> SamplerMap; + SamplerMap mSamplerMap; + HandleAllocator mSamplerHandleAllocator; + + typedef std::unordered_map<GLuint, FenceSync*> FenceMap; + FenceMap mFenceSyncMap; + HandleAllocator mFenceSyncHandleAllocator; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/Sampler.cpp b/src/3rdparty/angle/src/libGLESv2/Sampler.cpp new file mode 100644 index 0000000000..ed6e29f89e --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Sampler.cpp @@ -0,0 +1,44 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Sampler.cpp : Implements the Sampler class, which represents a GLES 3 +// sampler object. Sampler objects store some state needed to sample textures. + +#include "libGLESv2/Sampler.h" +#include "libGLESv2/angletypes.h" + +namespace gl +{ + +Sampler::Sampler(GLuint id) + : RefCountObject(id), + mMinFilter(GL_NEAREST_MIPMAP_LINEAR), + mMagFilter(GL_LINEAR), + mWrapS(GL_REPEAT), + mWrapT(GL_REPEAT), + mWrapR(GL_REPEAT), + mMinLod(-1000.0f), + mMaxLod(1000.0f), + mComparisonMode(GL_NONE), + mComparisonFunc(GL_LEQUAL) +{ +} + +void Sampler::getState(SamplerState *samplerState) const +{ + samplerState->minFilter = mMinFilter; + samplerState->magFilter = mMagFilter; + samplerState->wrapS = mWrapS; + samplerState->wrapT = mWrapT; + samplerState->wrapR = mWrapR; + samplerState->minLod = mMinLod; + samplerState->maxLod = mMaxLod; + samplerState->compareMode = mComparisonMode; + samplerState->compareFunc = mComparisonFunc; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Sampler.h b/src/3rdparty/angle/src/libGLESv2/Sampler.h new file mode 100644 index 0000000000..257bc25d22 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Sampler.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Sampler.h : Defines the Sampler class, which represents a GLES 3 +// sampler object. Sampler objects store some state needed to sample textures. + +#ifndef LIBGLESV2_SAMPLER_H_ +#define LIBGLESV2_SAMPLER_H_ + +#include "common/RefCountObject.h" + +namespace gl +{ +struct SamplerState; + +class Sampler : public RefCountObject +{ + public: + Sampler(GLuint id); + + void setMinFilter(GLenum minFilter) { mMinFilter = minFilter; } + void setMagFilter(GLenum magFilter) { mMagFilter = magFilter; } + void setWrapS(GLenum wrapS) { mWrapS = wrapS; } + void setWrapT(GLenum wrapT) { mWrapT = wrapT; } + void setWrapR(GLenum wrapR) { mWrapR = wrapR; } + void setMinLod(GLfloat minLod) { mMinLod = minLod; } + void setMaxLod(GLfloat maxLod) { mMaxLod = maxLod; } + void setComparisonMode(GLenum comparisonMode) { mComparisonMode = comparisonMode; } + void setComparisonFunc(GLenum comparisonFunc) { mComparisonFunc = comparisonFunc; } + + GLenum getMinFilter() const { return mMinFilter; } + GLenum getMagFilter() const { return mMagFilter; } + GLenum getWrapS() const { return mWrapS; } + GLenum getWrapT() const { return mWrapT; } + GLenum getWrapR() const { return mWrapR; } + GLfloat getMinLod() const { return mMinLod; } + GLfloat getMaxLod() const { return mMaxLod; } + GLenum getComparisonMode() const { return mComparisonMode; } + GLenum getComparisonFunc() const { return mComparisonFunc; } + + void getState(SamplerState *samplerState) const; + + private: + GLenum mMinFilter; + GLenum mMagFilter; + GLenum mWrapS; + GLenum mWrapT; + GLenum mWrapR; + GLfloat mMinLod; + GLfloat mMaxLod; + GLenum mComparisonMode; + GLenum mComparisonFunc; +}; + +} + +#endif // LIBGLESV2_SAMPLER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.cpp b/src/3rdparty/angle/src/libGLESv2/Shader.cpp index f6a2f03dfc..eda0298e87 100644 --- a/src/3rdparty/angle/src/libGLESv2/Shader.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Shader.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -12,7 +12,7 @@ #include "libGLESv2/Shader.h" #include "GLSLANG/ShaderLang.h" -#include "libGLESv2/utilities.h" +#include "common/utilities.h" #include "libGLESv2/renderer/Renderer.h" #include "libGLESv2/Constants.h" #include "libGLESv2/ResourceManager.h" @@ -25,22 +25,16 @@ void *Shader::mVertexCompiler = NULL; Shader::Shader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle) : mHandle(handle), mRenderer(renderer), mResourceManager(manager) { - mSource = NULL; - mHlsl = NULL; - mInfoLog = NULL; - uncompile(); initializeCompiler(); mRefCount = 0; mDeleteStatus = false; + mShaderVersion = 100; } Shader::~Shader() { - delete[] mSource; - delete[] mHlsl; - delete[] mInfoLog; } GLuint Shader::getHandle() const @@ -48,69 +42,31 @@ GLuint Shader::getHandle() const return mHandle; } -void Shader::setSource(GLsizei count, const char **string, const GLint *length) +void Shader::setSource(GLsizei count, const char *const *string, const GLint *length) { - delete[] mSource; - int totalLength = 0; + std::ostringstream stream; for (int i = 0; i < count; i++) { - if (length && length[i] >= 0) - { - totalLength += length[i]; - } - else - { - totalLength += (int)strlen(string[i]); - } + stream << string[i]; } - mSource = new char[totalLength + 1]; - char *code = mSource; - - for (int i = 0; i < count; i++) - { - int stringLength; - - if (length && length[i] >= 0) - { - stringLength = length[i]; - } - else - { - stringLength = (int)strlen(string[i]); - } - - strncpy(code, string[i], stringLength); - code += stringLength; - } - - mSource[totalLength] = '\0'; + mSource = stream.str(); } int Shader::getInfoLogLength() const { - if (!mInfoLog) - { - return 0; - } - else - { - return strlen(mInfoLog) + 1; - } + return mInfoLog.empty() ? 0 : (mInfoLog.length() + 1); } -void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) +void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const { int index = 0; if (bufSize > 0) { - if (mInfoLog) - { - index = std::min(bufSize - 1, (int)strlen(mInfoLog)); - memcpy(infoLog, mInfoLog, index); - } + index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length())); + memcpy(infoLog, mInfoLog.c_str(), index); infoLog[index] = '\0'; } @@ -123,39 +79,22 @@ void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) int Shader::getSourceLength() const { - if (!mSource) - { - return 0; - } - else - { - return strlen(mSource) + 1; - } + return mSource.empty() ? 0 : (mSource.length() + 1); } int Shader::getTranslatedSourceLength() const { - if (!mHlsl) - { - return 0; - } - else - { - return strlen(mHlsl) + 1; - } + return mHlsl.empty() ? 0 : (mHlsl.length() + 1); } -void Shader::getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer) +void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer) const { int index = 0; if (bufSize > 0) { - if (source) - { - index = std::min(bufSize - 1, (int)strlen(source)); - memcpy(buffer, source, index); - } + index = std::min(bufSize - 1, static_cast<GLsizei>(source.length())); + memcpy(buffer, source.c_str(), index); buffer[index] = '\0'; } @@ -166,27 +105,49 @@ void Shader::getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char } } -void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) +void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const { getSourceImpl(mSource, bufSize, length, buffer); } -void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) +void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const { getSourceImpl(mHlsl, bufSize, length, buffer); } -const sh::ActiveUniforms &Shader::getUniforms() +unsigned int Shader::getUniformRegister(const std::string &uniformName) const +{ + ASSERT(mUniformRegisterMap.count(uniformName) > 0); + return mUniformRegisterMap.find(uniformName)->second; +} + +unsigned int Shader::getInterfaceBlockRegister(const std::string &blockName) const +{ + ASSERT(mInterfaceBlockRegisterMap.count(blockName) > 0); + return mInterfaceBlockRegisterMap.find(blockName)->second; +} + +const std::vector<sh::Uniform> &Shader::getUniforms() const { return mActiveUniforms; } -bool Shader::isCompiled() +const std::vector<sh::InterfaceBlock> &Shader::getInterfaceBlocks() const +{ + return mActiveInterfaceBlocks; +} + +std::vector<PackedVarying> &Shader::getVaryings() +{ + return mVaryings; +} + +bool Shader::isCompiled() const { - return mHlsl != NULL; + return !mHlsl.empty(); } -const char *Shader::getHLSL() +const std::string &Shader::getHLSL() const { return mHlsl; } @@ -235,6 +196,10 @@ void Shader::initializeCompiler() ShBuiltInResources resources; ShInitBuiltInResources(&resources); + // TODO(geofflang): use context's caps + const gl::Caps &caps = mRenderer->getRendererCaps(); + const gl::Extensions &extensions = mRenderer->getRendererExtensions(); + resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS; resources.MaxVertexUniformVectors = mRenderer->getMaxVertexUniformVectors(); resources.MaxVaryingVectors = mRenderer->getMaxVaryingVectors(); @@ -242,15 +207,21 @@ void Shader::initializeCompiler() resources.MaxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits(); resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS; resources.MaxFragmentUniformVectors = mRenderer->getMaxFragmentUniformVectors(); - resources.MaxDrawBuffers = mRenderer->getMaxRenderTargets(); - resources.OES_standard_derivatives = mRenderer->getDerivativeInstructionSupport(); - resources.EXT_draw_buffers = mRenderer->getMaxRenderTargets() > 1; + resources.MaxDrawBuffers = caps.maxDrawBuffers; + resources.OES_standard_derivatives = extensions.standardDerivatives; + resources.EXT_draw_buffers = extensions.drawBuffers; + resources.EXT_shader_texture_lod = 1; // resources.OES_EGL_image_external = mRenderer->getShareHandleSupport() ? 1 : 0; // TODO: commented out until the extension is actually supported. resources.FragmentPrecisionHigh = 1; // Shader Model 2+ always supports FP24 (s16e7) which corresponds to highp resources.EXT_frag_depth = 1; // Shader Model 2+ always supports explicit depth output - - mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, hlslVersion, &resources); - mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, hlslVersion, &resources); + // GLSL ES 3.0 constants + resources.MaxVertexOutputVectors = mRenderer->getMaxVaryingVectors(); + resources.MaxFragmentInputVectors = mRenderer->getMaxVaryingVectors(); + resources.MinProgramTexelOffset = -8; // D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE + resources.MaxProgramTexelOffset = 7; // D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE + + mFragmentCompiler = ShConstructCompiler(GL_FRAGMENT_SHADER, SH_GLES2_SPEC, hlslVersion, &resources); + mVertexCompiler = ShConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC, hlslVersion, &resources); } } } @@ -266,57 +237,37 @@ void Shader::releaseCompiler() ShFinalize(); } -void Shader::parseVaryings() +void Shader::parseVaryings(void *compiler) { - if (mHlsl) + if (!mHlsl.empty()) { - const char *input = strstr(mHlsl, "// Varyings") + 12; + std::vector<sh::Varying> *activeVaryings; + ShGetInfoPointer(compiler, SH_ACTIVE_VARYINGS_ARRAY, reinterpret_cast<void**>(&activeVaryings)); - while(true) + for (size_t varyingIndex = 0; varyingIndex < activeVaryings->size(); varyingIndex++) { - char varyingType[256]; - char varyingName[256]; - - int matches = sscanf(input, "static %255s %255s", varyingType, varyingName); - - if (matches != 2) - { - break; - } - - char *array = strstr(varyingName, "["); - int size = 1; - - if (array) - { - size = atoi(array + 1); - *array = '\0'; - } - - mVaryings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL)); - - input = strstr(input, ";") + 2; + mVaryings.push_back(PackedVarying((*activeVaryings)[varyingIndex])); } - mUsesMultipleRenderTargets = strstr(mHlsl, "GL_USES_MRT") != NULL; - mUsesFragColor = strstr(mHlsl, "GL_USES_FRAG_COLOR") != NULL; - mUsesFragData = strstr(mHlsl, "GL_USES_FRAG_DATA") != NULL; - mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL; - mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL; - mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL; - mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL; - mUsesDepthRange = strstr(mHlsl, "GL_USES_DEPTH_RANGE") != NULL; - mUsesFragDepth = strstr(mHlsl, "GL_USES_FRAG_DEPTH") != NULL; - mUsesDiscardRewriting = strstr(mHlsl, "ANGLE_USES_DISCARD_REWRITING") != NULL; + mUsesMultipleRenderTargets = mHlsl.find("GL_USES_MRT") != std::string::npos; + mUsesFragColor = mHlsl.find("GL_USES_FRAG_COLOR") != std::string::npos; + mUsesFragData = mHlsl.find("GL_USES_FRAG_DATA") != std::string::npos; + mUsesFragCoord = mHlsl.find("GL_USES_FRAG_COORD") != std::string::npos; + mUsesFrontFacing = mHlsl.find("GL_USES_FRONT_FACING") != std::string::npos; + mUsesPointSize = mHlsl.find("GL_USES_POINT_SIZE") != std::string::npos; + mUsesPointCoord = mHlsl.find("GL_USES_POINT_COORD") != std::string::npos; + mUsesDepthRange = mHlsl.find("GL_USES_DEPTH_RANGE") != std::string::npos; + mUsesFragDepth = mHlsl.find("GL_USES_FRAG_DEPTH") != std::string::npos; + mUsesDiscardRewriting = mHlsl.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos; + mUsesNestedBreak = mHlsl.find("ANGLE_USES_NESTED_BREAK") != std::string::npos; } } void Shader::resetVaryingsRegisterAssignment() { - for (VaryingList::iterator var = mVaryings.begin(); var != mVaryings.end(); var++) + for (unsigned int varyingIndex = 0; varyingIndex < mVaryings.size(); varyingIndex++) { - var->reg = -1; - var->col = -1; + mVaryings[varyingIndex].resetRegisterAssignment(); } } @@ -324,10 +275,8 @@ void Shader::resetVaryingsRegisterAssignment() void Shader::uncompile() { // set by compileToHLSL - delete[] mHlsl; - mHlsl = NULL; - delete[] mInfoLog; - mInfoLog = NULL; + mHlsl.clear(); + mInfoLog.clear(); // set by parseVaryings mVaryings.clear(); @@ -341,20 +290,16 @@ void Shader::uncompile() mUsesPointCoord = false; mUsesDepthRange = false; mUsesFragDepth = false; + mShaderVersion = 100; mUsesDiscardRewriting = false; + mUsesNestedBreak = false; mActiveUniforms.clear(); + mActiveInterfaceBlocks.clear(); } void Shader::compileToHLSL(void *compiler) { - // ensure we don't pass a NULL source to the compiler - const char *source = "\0"; - if (mSource) - { - source = mSource; - } - // ensure the compiler is loaded initializeCompiler(); @@ -363,164 +308,163 @@ void Shader::compileToHLSL(void *compiler) if (perfActive()) { sourcePath = getTempPath(); - writeFile(sourcePath.c_str(), source, strlen(source)); + writeFile(sourcePath.c_str(), mSource.c_str(), mSource.length()); compileOptions |= SH_LINE_DIRECTIVES; } int result; if (sourcePath.empty()) { - result = ShCompile(compiler, &source, 1, compileOptions); + const char* sourceStrings[] = + { + mSource.c_str(), + }; + + result = ShCompile(compiler, sourceStrings, ArraySize(sourceStrings), compileOptions); } else { - const char* sourceStrings[2] = + const char* sourceStrings[] = { sourcePath.c_str(), - source + mSource.c_str(), }; - result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH); + result = ShCompile(compiler, sourceStrings, ArraySize(sourceStrings), compileOptions | SH_SOURCE_PATH); } - if (result) + size_t shaderVersion = 100; + ShGetInfo(compiler, SH_SHADER_VERSION, &shaderVersion); + + mShaderVersion = static_cast<int>(shaderVersion); + + if (shaderVersion == 300 && mRenderer->getCurrentClientVersion() < 3) + { + mInfoLog = "GLSL ES 3.00 is not supported by OpenGL ES 2.0 contexts"; + TRACE("\n%s", mInfoLog.c_str()); + } + else if (result) { size_t objCodeLen = 0; ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen); - mHlsl = new char[objCodeLen]; - ShGetObjectCode(compiler, mHlsl); + + char* outputHLSL = new char[objCodeLen]; + ShGetObjectCode(compiler, outputHLSL); + +#ifdef _DEBUG + std::ostringstream hlslStream; + hlslStream << "// GLSL\n"; + hlslStream << "//\n"; + + size_t curPos = 0; + while (curPos != std::string::npos) + { + size_t nextLine = mSource.find("\n", curPos); + size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1); + + hlslStream << "// " << mSource.substr(curPos, len); + + curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1); + } + hlslStream << "\n\n"; + hlslStream << outputHLSL; + mHlsl = hlslStream.str(); +#else + mHlsl = outputHLSL; +#endif + + delete[] outputHLSL; void *activeUniforms; ShGetInfoPointer(compiler, SH_ACTIVE_UNIFORMS_ARRAY, &activeUniforms); - mActiveUniforms = *(sh::ActiveUniforms*)activeUniforms; + mActiveUniforms = *(std::vector<sh::Uniform>*)activeUniforms; + + for (size_t uniformIndex = 0; uniformIndex < mActiveUniforms.size(); uniformIndex++) + { + const sh::Uniform &uniform = mActiveUniforms[uniformIndex]; + + unsigned int index = -1; + bool result = ShGetUniformRegister(compiler, uniform.name.c_str(), &index); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(result); + + mUniformRegisterMap[uniform.name] = index; + } + + void *activeInterfaceBlocks; + ShGetInfoPointer(compiler, SH_ACTIVE_INTERFACE_BLOCKS_ARRAY, &activeInterfaceBlocks); + mActiveInterfaceBlocks = *(std::vector<sh::InterfaceBlock>*)activeInterfaceBlocks; + + for (size_t blockIndex = 0; blockIndex < mActiveInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &interfaceBlock = mActiveInterfaceBlocks[blockIndex]; + + unsigned int index = -1; + bool result = ShGetInterfaceBlockRegister(compiler, interfaceBlock.name.c_str(), &index); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(result); + + mInterfaceBlockRegisterMap[interfaceBlock.name] = index; + } } else { size_t infoLogLen = 0; ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen); - mInfoLog = new char[infoLogLen]; - ShGetInfoLog(compiler, mInfoLog); - TRACE("\n%s", mInfoLog); + char* infoLog = new char[infoLogLen]; + ShGetInfoLog(compiler, infoLog); + mInfoLog = infoLog; + + TRACE("\n%s", mInfoLog.c_str()); } } -GLenum Shader::parseType(const std::string &type) +rx::D3DWorkaroundType Shader::getD3DWorkarounds() const { - if (type == "float") - { - return GL_FLOAT; - } - else if (type == "float2") + if (mUsesDiscardRewriting) { - return GL_FLOAT_VEC2; + // ANGLE issue 486: + // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by disabling optimization + return rx::ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION; } - else if (type == "float3") - { - return GL_FLOAT_VEC3; - } - else if (type == "float4") - { - return GL_FLOAT_VEC4; - } - else if (type == "float2x2") - { - return GL_FLOAT_MAT2; - } - else if (type == "float3x3") - { - return GL_FLOAT_MAT3; - } - else if (type == "float4x4") + + if (mUsesNestedBreak) { - return GL_FLOAT_MAT4; + // ANGLE issue 603: + // Work-around a D3D9 compiler bug that presents itself when using break in a nested loop, by maximizing optimization + // We want to keep the use of ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION minimal to prevent hangs, so usesDiscard takes precedence + return rx::ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION; } - else UNREACHABLE(); - return GL_NONE; + return rx::ANGLE_D3D_WORKAROUND_NONE; } // true if varying x has a higher priority in packing than y -bool Shader::compareVarying(const Varying &x, const Varying &y) +bool Shader::compareVarying(const PackedVarying &x, const PackedVarying &y) { - if(x.type == y.type) + if (x.type == y.type) { - return x.size > y.size; + return x.arraySize > y.arraySize; } - switch (x.type) + // Special case for handling structs: we sort these to the end of the list + if (x.type == GL_STRUCT_ANGLEX) { - case GL_FLOAT_MAT4: return true; - case GL_FLOAT_MAT2: - switch(y.type) - { - case GL_FLOAT_MAT4: return false; - case GL_FLOAT_MAT2: return true; - case GL_FLOAT_VEC4: return true; - case GL_FLOAT_MAT3: return true; - case GL_FLOAT_VEC3: return true; - case GL_FLOAT_VEC2: return true; - case GL_FLOAT: return true; - default: UNREACHABLE(); - } - break; - case GL_FLOAT_VEC4: - switch(y.type) - { - case GL_FLOAT_MAT4: return false; - case GL_FLOAT_MAT2: return false; - case GL_FLOAT_VEC4: return true; - case GL_FLOAT_MAT3: return true; - case GL_FLOAT_VEC3: return true; - case GL_FLOAT_VEC2: return true; - case GL_FLOAT: return true; - default: UNREACHABLE(); - } - break; - case GL_FLOAT_MAT3: - switch(y.type) - { - case GL_FLOAT_MAT4: return false; - case GL_FLOAT_MAT2: return false; - case GL_FLOAT_VEC4: return false; - case GL_FLOAT_MAT3: return true; - case GL_FLOAT_VEC3: return true; - case GL_FLOAT_VEC2: return true; - case GL_FLOAT: return true; - default: UNREACHABLE(); - } - break; - case GL_FLOAT_VEC3: - switch(y.type) - { - case GL_FLOAT_MAT4: return false; - case GL_FLOAT_MAT2: return false; - case GL_FLOAT_VEC4: return false; - case GL_FLOAT_MAT3: return false; - case GL_FLOAT_VEC3: return true; - case GL_FLOAT_VEC2: return true; - case GL_FLOAT: return true; - default: UNREACHABLE(); - } - break; - case GL_FLOAT_VEC2: - switch(y.type) - { - case GL_FLOAT_MAT4: return false; - case GL_FLOAT_MAT2: return false; - case GL_FLOAT_VEC4: return false; - case GL_FLOAT_MAT3: return false; - case GL_FLOAT_VEC3: return false; - case GL_FLOAT_VEC2: return true; - case GL_FLOAT: return true; - default: UNREACHABLE(); - } - break; - case GL_FLOAT: return false; - default: UNREACHABLE(); + return false; } - return false; + if (y.type == GL_STRUCT_ANGLEX) + { + return true; + } + + return gl::VariableSortOrder(x.type) <= gl::VariableSortOrder(y.type); +} + +int Shader::getShaderVersion() const +{ + return mShaderVersion; } VertexShader::VertexShader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle) @@ -532,7 +476,7 @@ VertexShader::~VertexShader() { } -GLenum VertexShader::getType() +GLenum VertexShader::getType() const { return GL_VERTEX_SHADER; } @@ -542,7 +486,7 @@ void VertexShader::uncompile() Shader::uncompile(); // set by ParseAttributes - mAttributes.clear(); + mActiveAttributes.clear(); } void VertexShader::compile() @@ -551,7 +495,7 @@ void VertexShader::compile() compileToHLSL(mVertexCompiler); parseAttributes(); - parseVaryings(); + parseVaryings(mVertexCompiler); } int VertexShader::getSemanticIndex(const std::string &attributeName) @@ -559,14 +503,16 @@ int VertexShader::getSemanticIndex(const std::string &attributeName) if (!attributeName.empty()) { int semanticIndex = 0; - for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++) + for (unsigned int attributeIndex = 0; attributeIndex < mActiveAttributes.size(); attributeIndex++) { - if (attribute->name == attributeName) + const sh::ShaderVariable &attribute = mActiveAttributes[attributeIndex]; + + if (attribute.name == attributeName) { return semanticIndex; } - semanticIndex += VariableRowCount(attribute->type); + semanticIndex += VariableRegisterCount(attribute.type); } } @@ -575,27 +521,12 @@ int VertexShader::getSemanticIndex(const std::string &attributeName) void VertexShader::parseAttributes() { - const char *hlsl = getHLSL(); - if (hlsl) + const std::string &hlsl = getHLSL(); + if (!hlsl.empty()) { - const char *input = strstr(hlsl, "// Attributes") + 14; - - while(true) - { - char attributeType[256]; - char attributeName[256]; - - int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName); - - if (matches != 2) - { - break; - } - - mAttributes.push_back(Attribute(parseType(attributeType), attributeName)); - - input = strstr(input, ";") + 2; - } + void *activeAttributes; + ShGetInfoPointer(mVertexCompiler, SH_ACTIVE_ATTRIBUTES_ARRAY, &activeAttributes); + mActiveAttributes = *(std::vector<sh::Attribute>*)activeAttributes; } } @@ -608,7 +539,7 @@ FragmentShader::~FragmentShader() { } -GLenum FragmentShader::getType() +GLenum FragmentShader::getType() const { return GL_FRAGMENT_SHADER; } @@ -618,7 +549,45 @@ void FragmentShader::compile() uncompile(); compileToHLSL(mFragmentCompiler); - parseVaryings(); - mVaryings.sort(compareVarying); + parseVaryings(mFragmentCompiler); + std::sort(mVaryings.begin(), mVaryings.end(), compareVarying); + + const std::string &hlsl = getHLSL(); + if (!hlsl.empty()) + { + void *activeOutputVariables; + ShGetInfoPointer(mFragmentCompiler, SH_ACTIVE_OUTPUT_VARIABLES_ARRAY, &activeOutputVariables); + mActiveOutputVariables = *(std::vector<sh::Attribute>*)activeOutputVariables; + } +} + +void FragmentShader::uncompile() +{ + Shader::uncompile(); + + mActiveOutputVariables.clear(); +} + +const std::vector<sh::Attribute> &FragmentShader::getOutputVariables() const +{ + return mActiveOutputVariables; } + +ShShaderOutput Shader::getCompilerOutputType(GLenum shader) +{ + void *compiler = NULL; + + switch (shader) + { + case GL_VERTEX_SHADER: compiler = mVertexCompiler; break; + case GL_FRAGMENT_SHADER: compiler = mFragmentCompiler; break; + default: UNREACHABLE(); return SH_HLSL9_OUTPUT; + } + + size_t outputType = 0; + ShGetInfo(compiler, SH_OUTPUT_TYPE, &outputType); + + return static_cast<ShShaderOutput>(outputType); +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.h b/src/3rdparty/angle/src/libGLESv2/Shader.h index 2015addd11..a40f415c1e 100644 --- a/src/3rdparty/angle/src/libGLESv2/Shader.h +++ b/src/3rdparty/angle/src/libGLESv2/Shader.h @@ -12,14 +12,15 @@ #ifndef LIBGLESV2_SHADER_H_ #define LIBGLESV2_SHADER_H_ -#define GL_APICALL -#include <GLES2/gl2.h> +#include "angle_gl.h" #include <string> #include <list> #include <vector> -#include "compiler/translator/Uniform.h" +#include "common/shadervars.h" #include "common/angleutils.h" +#include "libGLESv2/angletypes.h" +#include "GLSLANG/ShaderLang.h" namespace rx { @@ -30,73 +31,81 @@ namespace gl { class ResourceManager; -struct Varying +struct PackedVarying : public sh::Varying { - Varying(GLenum type, const std::string &name, int size, bool array) - : type(type), name(name), size(size), array(array), reg(-1), col(-1) - { - } + unsigned int registerIndex; // Assigned during link - GLenum type; - std::string name; - int size; // Number of 'type' elements - bool array; + PackedVarying(const sh::Varying &varying) + : sh::Varying(varying), + registerIndex(GL_INVALID_INDEX) + {} - int reg; // First varying register, assigned during link - int col; // First register element, assigned during link -}; + bool registerAssigned() const { return registerIndex != GL_INVALID_INDEX; } -typedef std::list<Varying> VaryingList; + void resetRegisterAssignment() + { + registerIndex = GL_INVALID_INDEX; + } +}; class Shader { - friend class ProgramBinary; + friend class DynamicHLSL; public: Shader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle); virtual ~Shader(); - virtual GLenum getType() = 0; + virtual GLenum getType() const = 0; GLuint getHandle() const; void deleteSource(); - void setSource(GLsizei count, const char **string, const GLint *length); + void setSource(GLsizei count, const char *const *string, const GLint *length); int getInfoLogLength() const; - void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog); + void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const; int getSourceLength() const; - void getSource(GLsizei bufSize, GLsizei *length, char *buffer); + void getSource(GLsizei bufSize, GLsizei *length, char *buffer) const; int getTranslatedSourceLength() const; - void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer); - const sh::ActiveUniforms &getUniforms(); + void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const; + const std::vector<sh::Uniform> &getUniforms() const; + const std::vector<sh::InterfaceBlock> &getInterfaceBlocks() const; + std::vector<PackedVarying> &getVaryings(); virtual void compile() = 0; virtual void uncompile(); - bool isCompiled(); - const char *getHLSL(); + bool isCompiled() const; + const std::string &getHLSL() const; void addRef(); void release(); unsigned int getRefCount() const; bool isFlaggedForDeletion() const; void flagForDeletion(); + int getShaderVersion() const; + void resetVaryingsRegisterAssignment(); static void releaseCompiler(); + static ShShaderOutput getCompilerOutputType(GLenum shader); + unsigned int getUniformRegister(const std::string &uniformName) const; + unsigned int getInterfaceBlockRegister(const std::string &blockName) const; + + bool usesDepthRange() const { return mUsesDepthRange; } + bool usesPointSize() const { return mUsesPointSize; } + rx::D3DWorkaroundType getD3DWorkarounds() const; protected: - void parseVaryings(); - void resetVaryingsRegisterAssignment(); + void parseVaryings(void *compiler); void compileToHLSL(void *compiler); - void getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer); + void getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer) const; - static GLenum parseType(const std::string &type); - static bool compareVarying(const Varying &x, const Varying &y); + static bool compareVarying(const PackedVarying &x, const PackedVarying &y); const rx::Renderer *const mRenderer; - VaryingList mVaryings; + std::vector<PackedVarying> mVaryings; bool mUsesMultipleRenderTargets; bool mUsesFragColor; @@ -107,7 +116,9 @@ class Shader bool mUsesPointCoord; bool mUsesDepthRange; bool mUsesFragDepth; + int mShaderVersion; bool mUsesDiscardRewriting; + bool mUsesNestedBreak; static void *mFragmentCompiler; static void *mVertexCompiler; @@ -121,50 +132,39 @@ class Shader unsigned int mRefCount; // Number of program objects this shader is attached to bool mDeleteStatus; // Flag to indicate that the shader can be deleted when no longer in use - char *mSource; - char *mHlsl; - char *mInfoLog; - sh::ActiveUniforms mActiveUniforms; + std::string mSource; + std::string mHlsl; + std::string mInfoLog; + std::vector<sh::Uniform> mActiveUniforms; + std::vector<sh::InterfaceBlock> mActiveInterfaceBlocks; + std::map<std::string, unsigned int> mUniformRegisterMap; + std::map<std::string, unsigned int> mInterfaceBlockRegisterMap; ResourceManager *mResourceManager; }; -struct Attribute -{ - Attribute() : type(GL_NONE), name("") - { - } - - Attribute(GLenum type, const std::string &name) : type(type), name(name) - { - } - - GLenum type; - std::string name; -}; - -typedef std::vector<Attribute> AttributeArray; - class VertexShader : public Shader { - friend class ProgramBinary; + friend class DynamicHLSL; public: VertexShader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle); ~VertexShader(); - virtual GLenum getType(); + virtual GLenum getType() const; virtual void compile(); virtual void uncompile(); int getSemanticIndex(const std::string &attributeName); + const std::vector<sh::Attribute> &activeAttributes() const { return mActiveAttributes; } + private: DISALLOW_COPY_AND_ASSIGN(VertexShader); void parseAttributes(); - AttributeArray mAttributes; + std::vector<sh::Attribute> mActiveAttributes; }; class FragmentShader : public Shader @@ -174,11 +174,15 @@ class FragmentShader : public Shader ~FragmentShader(); - virtual GLenum getType(); + virtual GLenum getType() const; virtual void compile(); + virtual void uncompile(); + const std::vector<sh::Attribute> &getOutputVariables() const; private: DISALLOW_COPY_AND_ASSIGN(FragmentShader); + + std::vector<sh::Attribute> mActiveOutputVariables; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/State.cpp b/src/3rdparty/angle/src/libGLESv2/State.cpp new file mode 100644 index 0000000000..b552701727 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/State.cpp @@ -0,0 +1,1415 @@ +#include "precompiled.h" +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// State.cpp: Implements the State class, encapsulating raw GL state. + +#include "libGLESv2/State.h" + +#include "libGLESv2/Context.h" +#include "libGLESv2/VertexArray.h" +#include "libGLESv2/Query.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" +#include "libGLESv2/renderer/RenderTarget.h" +#include "libGLESv2/formatutils.h" + +namespace gl +{ +State::State() +{ + mContext = NULL; + + setClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + mDepthClearValue = 1.0f; + mStencilClearValue = 0; + + mRasterizer.rasterizerDiscard = false; + mRasterizer.cullFace = false; + mRasterizer.cullMode = GL_BACK; + mRasterizer.frontFace = GL_CCW; + mRasterizer.polygonOffsetFill = false; + mRasterizer.polygonOffsetFactor = 0.0f; + mRasterizer.polygonOffsetUnits = 0.0f; + mRasterizer.pointDrawMode = false; + mRasterizer.multiSample = false; + mScissorTest = false; + mScissor.x = 0; + mScissor.y = 0; + mScissor.width = 0; + mScissor.height = 0; + + mBlend.blend = false; + mBlend.sourceBlendRGB = GL_ONE; + mBlend.sourceBlendAlpha = GL_ONE; + mBlend.destBlendRGB = GL_ZERO; + mBlend.destBlendAlpha = GL_ZERO; + mBlend.blendEquationRGB = GL_FUNC_ADD; + mBlend.blendEquationAlpha = GL_FUNC_ADD; + mBlend.sampleAlphaToCoverage = false; + mBlend.dither = true; + + mBlendColor.red = 0; + mBlendColor.green = 0; + mBlendColor.blue = 0; + mBlendColor.alpha = 0; + + mDepthStencil.depthTest = false; + mDepthStencil.depthFunc = GL_LESS; + mDepthStencil.depthMask = true; + mDepthStencil.stencilTest = false; + mDepthStencil.stencilFunc = GL_ALWAYS; + mDepthStencil.stencilMask = -1; + mDepthStencil.stencilWritemask = -1; + mDepthStencil.stencilBackFunc = GL_ALWAYS; + mDepthStencil.stencilBackMask = - 1; + mDepthStencil.stencilBackWritemask = -1; + mDepthStencil.stencilFail = GL_KEEP; + mDepthStencil.stencilPassDepthFail = GL_KEEP; + mDepthStencil.stencilPassDepthPass = GL_KEEP; + mDepthStencil.stencilBackFail = GL_KEEP; + mDepthStencil.stencilBackPassDepthFail = GL_KEEP; + mDepthStencil.stencilBackPassDepthPass = GL_KEEP; + + mStencilRef = 0; + mStencilBackRef = 0; + + mSampleCoverage = false; + mSampleCoverageValue = 1.0f; + mSampleCoverageInvert = false; + mGenerateMipmapHint = GL_DONT_CARE; + mFragmentShaderDerivativeHint = GL_DONT_CARE; + + mLineWidth = 1.0f; + + mViewport.x = 0; + mViewport.y = 0; + mViewport.width = 0; + mViewport.height = 0; + mNearZ = 0.0f; + mFarZ = 1.0f; + + mBlend.colorMaskRed = true; + mBlend.colorMaskGreen = true; + mBlend.colorMaskBlue = true; + mBlend.colorMaskAlpha = true; + + const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + for (int attribIndex = 0; attribIndex < MAX_VERTEX_ATTRIBS; attribIndex++) + { + mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues); + } + + for (unsigned int textureUnit = 0; textureUnit < ArraySize(mSamplers); textureUnit++) + { + mSamplers[textureUnit].set(NULL); + } + + mActiveSampler = 0; + + mActiveQueries[GL_ANY_SAMPLES_PASSED].set(NULL); + mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(NULL); + mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(NULL); + + mCurrentProgramId = 0; + mCurrentProgramBinary.set(NULL); + + mReadFramebuffer = NULL; + mDrawFramebuffer = NULL; +} + +State::~State() +{ + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) + { + for (int sampler = 0; sampler < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; sampler++) + { + mSamplerTexture[type][sampler].set(NULL); + } + } + + const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + for (int attribIndex = 0; attribIndex < MAX_VERTEX_ATTRIBS; attribIndex++) + { + mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues); + } + + mArrayBuffer.set(NULL); + mRenderbuffer.set(NULL); + + mTransformFeedback.set(NULL); + + for (State::ActiveQueryMap::iterator i = mActiveQueries.begin(); i != mActiveQueries.end(); i++) + { + i->second.set(NULL); + } + + mGenericUniformBuffer.set(NULL); + for (int i = 0; i < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; i++) + { + mUniformBuffers[i].set(NULL); + } + + mGenericTransformFeedbackBuffer.set(NULL); + for (int i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + mTransformFeedbackBuffers[i].set(NULL); + } + + mCopyReadBuffer.set(NULL); + mCopyWriteBuffer.set(NULL); + + mPack.pixelBuffer.set(NULL); + mUnpack.pixelBuffer.set(NULL); +} + +const RasterizerState &State::getRasterizerState() const +{ + return mRasterizer; +} + +const BlendState &State::getBlendState() const +{ + return mBlend; +} + +const DepthStencilState &State::getDepthStencilState() const +{ + return mDepthStencil; +} + +void State::setClearColor(float red, float green, float blue, float alpha) +{ + mColorClearValue.red = red; + mColorClearValue.green = green; + mColorClearValue.blue = blue; + mColorClearValue.alpha = alpha; +} + +void State::setClearDepth(float depth) +{ + mDepthClearValue = depth; +} + +void State::setClearStencil(int stencil) +{ + mStencilClearValue = stencil; +} + +ClearParameters State::getClearParameters(GLbitfield mask) const +{ + ClearParameters clearParams = { 0 }; + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = false; + } + clearParams.colorFClearValue = mColorClearValue; + clearParams.colorClearType = GL_FLOAT; + clearParams.colorMaskRed = mBlend.colorMaskRed; + clearParams.colorMaskGreen = mBlend.colorMaskGreen; + clearParams.colorMaskBlue = mBlend.colorMaskBlue; + clearParams.colorMaskAlpha = mBlend.colorMaskAlpha; + clearParams.clearDepth = false; + clearParams.depthClearValue = mDepthClearValue; + clearParams.clearStencil = false; + clearParams.stencilClearValue = mStencilClearValue; + clearParams.stencilWriteMask = mDepthStencil.stencilWritemask; + clearParams.scissorEnabled = mScissorTest; + clearParams.scissor = mScissor; + + const Framebuffer *framebufferObject = getDrawFramebuffer(); + if (mask & GL_COLOR_BUFFER_BIT) + { + if (framebufferObject->hasEnabledColorAttachment()) + { + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = true; + } + } + } + + if (mask & GL_DEPTH_BUFFER_BIT) + { + if (mDepthStencil.depthMask && framebufferObject->getDepthbuffer() != NULL) + { + clearParams.clearDepth = true; + } + } + + if (mask & GL_STENCIL_BUFFER_BIT) + { + if (framebufferObject->getStencilbuffer() != NULL) + { + rx::RenderTarget *depthStencil = framebufferObject->getStencilbuffer()->getDepthStencil(); + if (!depthStencil) + { + ERR("Depth stencil pointer unexpectedly null."); + ClearParameters nullClearParam = { 0 }; + return nullClearParam; + } + + if (GetStencilBits(depthStencil->getActualFormat()) > 0) + { + clearParams.clearStencil = true; + } + } + } + + return clearParams; +} + +void State::setColorMask(bool red, bool green, bool blue, bool alpha) +{ + mBlend.colorMaskRed = red; + mBlend.colorMaskGreen = green; + mBlend.colorMaskBlue = blue; + mBlend.colorMaskAlpha = alpha; +} + +void State::setDepthMask(bool mask) +{ + mDepthStencil.depthMask = mask; +} + +bool State::isRasterizerDiscardEnabled() const +{ + return mRasterizer.rasterizerDiscard; +} + +void State::setRasterizerDiscard(bool enabled) +{ + mRasterizer.rasterizerDiscard = enabled; +} + +bool State::isCullFaceEnabled() const +{ + return mRasterizer.cullFace; +} + +void State::setCullFace(bool enabled) +{ + mRasterizer.cullFace = enabled; +} + +void State::setCullMode(GLenum mode) +{ + mRasterizer.cullMode = mode; +} + +void State::setFrontFace(GLenum front) +{ + mRasterizer.frontFace = front; +} + +bool State::isDepthTestEnabled() const +{ + return mDepthStencil.depthTest; +} + +void State::setDepthTest(bool enabled) +{ + mDepthStencil.depthTest = enabled; +} + +void State::setDepthFunc(GLenum depthFunc) +{ + mDepthStencil.depthFunc = depthFunc; +} + +void State::setDepthRange(float zNear, float zFar) +{ + mNearZ = zNear; + mFarZ = zFar; +} + +void State::getDepthRange(float *zNear, float *zFar) const +{ + *zNear = mNearZ; + *zFar = mFarZ; +} + +bool State::isBlendEnabled() const +{ + return mBlend.blend; +} + +void State::setBlend(bool enabled) +{ + mBlend.blend = enabled; +} + +void State::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha) +{ + mBlend.sourceBlendRGB = sourceRGB; + mBlend.destBlendRGB = destRGB; + mBlend.sourceBlendAlpha = sourceAlpha; + mBlend.destBlendAlpha = destAlpha; +} + +void State::setBlendColor(float red, float green, float blue, float alpha) +{ + mBlendColor.red = red; + mBlendColor.green = green; + mBlendColor.blue = blue; + mBlendColor.alpha = alpha; +} + +void State::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation) +{ + mBlend.blendEquationRGB = rgbEquation; + mBlend.blendEquationAlpha = alphaEquation; +} + +const ColorF &State::getBlendColor() const +{ + return mBlendColor; +} + +bool State::isStencilTestEnabled() const +{ + return mDepthStencil.stencilTest; +} + +void State::setStencilTest(bool enabled) +{ + mDepthStencil.stencilTest = enabled; +} + +void State::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask) +{ + mDepthStencil.stencilFunc = stencilFunc; + mStencilRef = (stencilRef > 0) ? stencilRef : 0; + mDepthStencil.stencilMask = stencilMask; +} + +void State::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask) +{ + mDepthStencil.stencilBackFunc = stencilBackFunc; + mStencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0; + mDepthStencil.stencilBackMask = stencilBackMask; +} + +void State::setStencilWritemask(GLuint stencilWritemask) +{ + mDepthStencil.stencilWritemask = stencilWritemask; +} + +void State::setStencilBackWritemask(GLuint stencilBackWritemask) +{ + mDepthStencil.stencilBackWritemask = stencilBackWritemask; +} + +void State::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass) +{ + mDepthStencil.stencilFail = stencilFail; + mDepthStencil.stencilPassDepthFail = stencilPassDepthFail; + mDepthStencil.stencilPassDepthPass = stencilPassDepthPass; +} + +void State::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass) +{ + mDepthStencil.stencilBackFail = stencilBackFail; + mDepthStencil.stencilBackPassDepthFail = stencilBackPassDepthFail; + mDepthStencil.stencilBackPassDepthPass = stencilBackPassDepthPass; +} + +GLint State::getStencilRef() const +{ + return mStencilRef; +} + +GLint State::getStencilBackRef() const +{ + return mStencilBackRef; +} + +bool State::isPolygonOffsetFillEnabled() const +{ + return mRasterizer.polygonOffsetFill; +} + +void State::setPolygonOffsetFill(bool enabled) +{ + mRasterizer.polygonOffsetFill = enabled; +} + +void State::setPolygonOffsetParams(GLfloat factor, GLfloat units) +{ + // An application can pass NaN values here, so handle this gracefully + mRasterizer.polygonOffsetFactor = factor != factor ? 0.0f : factor; + mRasterizer.polygonOffsetUnits = units != units ? 0.0f : units; +} + +bool State::isSampleAlphaToCoverageEnabled() const +{ + return mBlend.sampleAlphaToCoverage; +} + +void State::setSampleAlphaToCoverage(bool enabled) +{ + mBlend.sampleAlphaToCoverage = enabled; +} + +bool State::isSampleCoverageEnabled() const +{ + return mSampleCoverage; +} + +void State::setSampleCoverage(bool enabled) +{ + mSampleCoverage = enabled; +} + +void State::setSampleCoverageParams(GLclampf value, bool invert) +{ + mSampleCoverageValue = value; + mSampleCoverageInvert = invert; +} + +void State::getSampleCoverageParams(GLclampf *value, bool *invert) +{ + ASSERT(value != NULL && invert != NULL); + + *value = mSampleCoverageValue; + *invert = mSampleCoverageInvert; +} + +bool State::isScissorTestEnabled() const +{ + return mScissorTest; +} + +void State::setScissorTest(bool enabled) +{ + mScissorTest = enabled; +} + +void State::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mScissor.x = x; + mScissor.y = y; + mScissor.width = width; + mScissor.height = height; +} + +const Rectangle &State::getScissor() const +{ + return mScissor; +} + +bool State::isDitherEnabled() const +{ + return mBlend.dither; +} + +void State::setDither(bool enabled) +{ + mBlend.dither = enabled; +} + +void State::setEnableFeature(GLenum feature, bool enabled) +{ + switch (feature) + { + case GL_CULL_FACE: setCullFace(enabled); break; + case GL_POLYGON_OFFSET_FILL: setPolygonOffsetFill(enabled); break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: setSampleAlphaToCoverage(enabled); break; + case GL_SAMPLE_COVERAGE: setSampleCoverage(enabled); break; + case GL_SCISSOR_TEST: setScissorTest(enabled); break; + case GL_STENCIL_TEST: setStencilTest(enabled); break; + case GL_DEPTH_TEST: setDepthTest(enabled); break; + case GL_BLEND: setBlend(enabled); break; + case GL_DITHER: setDither(enabled); break; + case GL_PRIMITIVE_RESTART_FIXED_INDEX: UNIMPLEMENTED(); break; + case GL_RASTERIZER_DISCARD: setRasterizerDiscard(enabled); break; + default: UNREACHABLE(); + } +} + +bool State::getEnableFeature(GLenum feature) +{ + switch (feature) + { + case GL_CULL_FACE: return isCullFaceEnabled(); + case GL_POLYGON_OFFSET_FILL: return isPolygonOffsetFillEnabled(); + case GL_SAMPLE_ALPHA_TO_COVERAGE: return isSampleAlphaToCoverageEnabled(); + case GL_SAMPLE_COVERAGE: return isSampleCoverageEnabled(); + case GL_SCISSOR_TEST: return isScissorTestEnabled(); + case GL_STENCIL_TEST: return isStencilTestEnabled(); + case GL_DEPTH_TEST: return isDepthTestEnabled(); + case GL_BLEND: return isBlendEnabled(); + case GL_DITHER: return isDitherEnabled(); + case GL_PRIMITIVE_RESTART_FIXED_INDEX: UNIMPLEMENTED(); return false; + case GL_RASTERIZER_DISCARD: return isRasterizerDiscardEnabled(); + default: UNREACHABLE(); return false; + } +} + +void State::setLineWidth(GLfloat width) +{ + mLineWidth = width; +} + +void State::setGenerateMipmapHint(GLenum hint) +{ + mGenerateMipmapHint = hint; +} + +void State::setFragmentShaderDerivativeHint(GLenum hint) +{ + mFragmentShaderDerivativeHint = hint; + // TODO: Propagate the hint to shader translator so we can write + // ddx, ddx_coarse, or ddx_fine depending on the hint. + // Ignore for now. It is valid for implementations to ignore hint. +} + +void State::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mViewport.x = x; + mViewport.y = y; + mViewport.width = width; + mViewport.height = height; +} + +const Rectangle &State::getViewport() const +{ + return mViewport; +} + +void State::setActiveSampler(unsigned int active) +{ + mActiveSampler = active; +} + +unsigned int State::getActiveSampler() const +{ + return mActiveSampler; +} + +void State::setSamplerTexture(TextureType type, Texture *texture) +{ + mSamplerTexture[type][mActiveSampler].set(texture); +} + +Texture *State::getSamplerTexture(unsigned int sampler, TextureType type) const +{ + GLuint texid = mSamplerTexture[type][sampler].id(); + + if (texid == 0) // Special case: 0 refers to default textures held by Context + { + return NULL; + } + + return mSamplerTexture[type][sampler].get(); +} + +GLuint State::getSamplerTextureId(unsigned int sampler, TextureType type) const +{ + return mSamplerTexture[type][sampler].id(); +} + +void State::detachTexture(GLuint texture) +{ + // Textures have a detach method on State rather than a simple + // removeBinding, because the zero/null texture objects are managed + // separately, and don't have to go through the Context's maps or + // the ResourceManager. + + // [OpenGL ES 2.0.24] section 3.8 page 84: + // If a texture object is deleted, it is as if all texture units which are bound to that texture object are + // rebound to texture object zero + + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) + { + for (int sampler = 0; sampler < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; sampler++) + { + if (mSamplerTexture[type][sampler].id() == texture) + { + mSamplerTexture[type][sampler].set(NULL); + } + } + } + + // [OpenGL ES 2.0.24] section 4.4 page 112: + // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is + // as if Texture2DAttachment had been called, with a texture of 0, for each attachment point to which this + // image was attached in the currently bound framebuffer. + + if (mReadFramebuffer) + { + mReadFramebuffer->detachTexture(texture); + } + + if (mDrawFramebuffer) + { + mDrawFramebuffer->detachTexture(texture); + } +} + +void State::setSamplerBinding(GLuint textureUnit, Sampler *sampler) +{ + mSamplers[textureUnit].set(sampler); +} + +GLuint State::getSamplerId(GLuint textureUnit) const +{ + ASSERT(textureUnit < ArraySize(mSamplers)); + return mSamplers[textureUnit].id(); +} + +Sampler *State::getSampler(GLuint textureUnit) const +{ + return mSamplers[textureUnit].get(); +} + +void State::detachSampler(GLuint sampler) +{ + // [OpenGL ES 3.0.2] section 3.8.2 pages 123-124: + // If a sampler object that is currently bound to one or more texture units is + // deleted, it is as though BindSampler is called once for each texture unit to + // which the sampler is bound, with unit set to the texture unit and sampler set to zero. + for (unsigned int textureUnit = 0; textureUnit < ArraySize(mSamplers); textureUnit++) + { + if (mSamplers[textureUnit].id() == sampler) + { + mSamplers[textureUnit].set(NULL); + } + } +} + +void State::setRenderbufferBinding(Renderbuffer *renderbuffer) +{ + mRenderbuffer.set(renderbuffer); +} + +GLuint State::getRenderbufferId() const +{ + return mRenderbuffer.id(); +} + +Renderbuffer *State::getCurrentRenderbuffer() +{ + return mRenderbuffer.get(); +} + +void State::detachRenderbuffer(GLuint renderbuffer) +{ + // [OpenGL ES 2.0.24] section 4.4 page 109: + // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer + // had been executed with the target RENDERBUFFER and name of zero. + + if (mRenderbuffer.id() == renderbuffer) + { + mRenderbuffer.set(NULL); + } + + // [OpenGL ES 2.0.24] section 4.4 page 111: + // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer, + // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment + // point to which this image was attached in the currently bound framebuffer. + + Framebuffer *readFramebuffer = mReadFramebuffer; + Framebuffer *drawFramebuffer = mDrawFramebuffer; + + if (readFramebuffer) + { + readFramebuffer->detachRenderbuffer(renderbuffer); + } + + if (drawFramebuffer && drawFramebuffer != readFramebuffer) + { + drawFramebuffer->detachRenderbuffer(renderbuffer); + } + +} + +void State::setReadFramebufferBinding(Framebuffer *framebuffer) +{ + mReadFramebuffer = framebuffer; +} + +void State::setDrawFramebufferBinding(Framebuffer *framebuffer) +{ + mDrawFramebuffer = framebuffer; +} + +Framebuffer *State::getTargetFramebuffer(GLenum target) const +{ + switch (target) + { + case GL_READ_FRAMEBUFFER_ANGLE: return mReadFramebuffer; + case GL_DRAW_FRAMEBUFFER_ANGLE: + case GL_FRAMEBUFFER: return mDrawFramebuffer; + default: UNREACHABLE(); return NULL; + } +} + +Framebuffer *State::getReadFramebuffer() +{ + return mReadFramebuffer; +} + +Framebuffer *State::getDrawFramebuffer() +{ + return mDrawFramebuffer; +} + +const Framebuffer *State::getReadFramebuffer() const +{ + return mReadFramebuffer; +} + +const Framebuffer *State::getDrawFramebuffer() const +{ + return mDrawFramebuffer; +} + +bool State::removeReadFramebufferBinding(GLuint framebuffer) +{ + if (mReadFramebuffer->id() == framebuffer) + { + mReadFramebuffer = NULL; + return true; + } + + return false; +} + +bool State::removeDrawFramebufferBinding(GLuint framebuffer) +{ + if (mDrawFramebuffer->id() == framebuffer) + { + mDrawFramebuffer = NULL; + return true; + } + + return false; +} + +void State::setVertexArrayBinding(VertexArray *vertexArray) +{ + mVertexArray = vertexArray; +} + +GLuint State::getVertexArrayId() const +{ + ASSERT(mVertexArray != NULL); + return mVertexArray->id(); +} + +VertexArray *State::getVertexArray() const +{ + ASSERT(mVertexArray != NULL); + return mVertexArray; +} + +bool State::removeVertexArrayBinding(GLuint vertexArray) +{ + if (mVertexArray->id() == vertexArray) + { + mVertexArray = NULL; + return true; + } + + return false; +} + +void State::setCurrentProgram(GLuint programId, Program *newProgram) +{ + mCurrentProgramId = programId; // set new ID before trying to delete program binary; otherwise it will only be flagged for deletion + mCurrentProgramBinary.set(NULL); + + if (newProgram) + { + newProgram->addRef(); + mCurrentProgramBinary.set(newProgram->getProgramBinary()); + } +} + +void State::setCurrentProgramBinary(ProgramBinary *binary) +{ + mCurrentProgramBinary.set(binary); +} + +GLuint State::getCurrentProgramId() const +{ + return mCurrentProgramId; +} + +ProgramBinary *State::getCurrentProgramBinary() const +{ + return mCurrentProgramBinary.get(); +} + +void State::setTransformFeedbackBinding(TransformFeedback *transformFeedback) +{ + mTransformFeedback.set(transformFeedback); +} + +TransformFeedback *State::getCurrentTransformFeedback() const +{ + return mTransformFeedback.get(); +} + +void State::detachTransformFeedback(GLuint transformFeedback) +{ + if (mTransformFeedback.id() == transformFeedback) + { + mTransformFeedback.set(NULL); + } +} + +bool State::isQueryActive() const +{ + for (State::ActiveQueryMap::const_iterator i = mActiveQueries.begin(); + i != mActiveQueries.end(); i++) + { + if (i->second.get() != NULL) + { + return true; + } + } + + return false; +} + +void State::setActiveQuery(GLenum target, Query *query) +{ + mActiveQueries[target].set(query); +} + +GLuint State::getActiveQueryId(GLenum target) const +{ + const Query *query = getActiveQuery(target); + return (query ? query->id() : 0u); +} + +Query *State::getActiveQuery(GLenum target) const +{ + // All query types should already exist in the activeQueries map + ASSERT(mActiveQueries.find(target) != mActiveQueries.end()); + + return mActiveQueries.at(target).get(); +} + +void State::setArrayBufferBinding(Buffer *buffer) +{ + mArrayBuffer.set(buffer); +} + +GLuint State::getArrayBufferId() const +{ + return mArrayBuffer.id(); +} + +bool State::removeArrayBufferBinding(GLuint buffer) +{ + if (mArrayBuffer.id() == buffer) + { + mArrayBuffer.set(NULL); + return true; + } + + return false; +} + +void State::setGenericUniformBufferBinding(Buffer *buffer) +{ + mGenericUniformBuffer.set(buffer); +} + +void State::setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) +{ + mUniformBuffers[index].set(buffer, offset, size); +} + +GLuint State::getIndexedUniformBufferId(GLuint index) const +{ + ASSERT(index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS); + + return mUniformBuffers[index].id(); +} + +Buffer *State::getIndexedUniformBuffer(GLuint index) const +{ + ASSERT(index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS); + + return mUniformBuffers[index].get(); +} + +void State::setGenericTransformFeedbackBufferBinding(Buffer *buffer) +{ + mGenericTransformFeedbackBuffer.set(buffer); +} + +void State::setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) +{ + mTransformFeedbackBuffers[index].set(buffer, offset, size); +} + +GLuint State::getIndexedTransformFeedbackBufferId(GLuint index) const +{ + ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + + return mTransformFeedbackBuffers[index].id(); +} + +Buffer *State::getIndexedTransformFeedbackBuffer(GLuint index) const +{ + ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + + return mTransformFeedbackBuffers[index].get(); +} + +GLuint State::getIndexedTransformFeedbackBufferOffset(GLuint index) const +{ + ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + + return mTransformFeedbackBuffers[index].getOffset(); +} + +void State::setCopyReadBufferBinding(Buffer *buffer) +{ + mCopyReadBuffer.set(buffer); +} + +void State::setCopyWriteBufferBinding(Buffer *buffer) +{ + mCopyWriteBuffer.set(buffer); +} + +void State::setPixelPackBufferBinding(Buffer *buffer) +{ + mPack.pixelBuffer.set(buffer); +} + +void State::setPixelUnpackBufferBinding(Buffer *buffer) +{ + mUnpack.pixelBuffer.set(buffer); +} + +Buffer *State::getTargetBuffer(GLenum target) const +{ + switch (target) + { + case GL_ARRAY_BUFFER: return mArrayBuffer.get(); + case GL_COPY_READ_BUFFER: return mCopyReadBuffer.get(); + case GL_COPY_WRITE_BUFFER: return mCopyWriteBuffer.get(); + case GL_ELEMENT_ARRAY_BUFFER: return getVertexArray()->getElementArrayBuffer(); + case GL_PIXEL_PACK_BUFFER: return mPack.pixelBuffer.get(); + case GL_PIXEL_UNPACK_BUFFER: return mUnpack.pixelBuffer.get(); + case GL_TRANSFORM_FEEDBACK_BUFFER: return mGenericTransformFeedbackBuffer.get(); + case GL_UNIFORM_BUFFER: return mGenericUniformBuffer.get(); + default: UNREACHABLE(); return NULL; + } +} + +void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) +{ + getVertexArray()->enableAttribute(attribNum, enabled); +} + +void State::setVertexAttribf(GLuint index, const GLfloat values[4]) +{ + ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + mVertexAttribCurrentValues[index].setFloatValues(values); +} + +void State::setVertexAttribu(GLuint index, const GLuint values[4]) +{ + ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + mVertexAttribCurrentValues[index].setUnsignedIntValues(values); +} + +void State::setVertexAttribi(GLuint index, const GLint values[4]) +{ + ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + mVertexAttribCurrentValues[index].setIntValues(values); +} + +void State::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized, + bool pureInteger, GLsizei stride, const void *pointer) +{ + getVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer); +} + +const VertexAttribute &State::getVertexAttribState(unsigned int attribNum) const +{ + return getVertexArray()->getVertexAttribute(attribNum); +} + +const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const +{ + ASSERT(attribNum < MAX_VERTEX_ATTRIBS); + return mVertexAttribCurrentValues[attribNum]; +} + +const VertexAttribCurrentValueData *State::getVertexAttribCurrentValues() const +{ + return mVertexAttribCurrentValues; +} + +const void *State::getVertexAttribPointer(unsigned int attribNum) const +{ + return getVertexArray()->getVertexAttribute(attribNum).pointer; +} + +void State::setPackAlignment(GLint alignment) +{ + mPack.alignment = alignment; +} + +GLint State::getPackAlignment() const +{ + return mPack.alignment; +} + +void State::setPackReverseRowOrder(bool reverseRowOrder) +{ + mPack.reverseRowOrder = reverseRowOrder; +} + +bool State::getPackReverseRowOrder() const +{ + return mPack.reverseRowOrder; +} + +const PixelPackState &State::getPackState() const +{ + return mPack; +} + +void State::setUnpackAlignment(GLint alignment) +{ + mUnpack.alignment = alignment; +} + +GLint State::getUnpackAlignment() const +{ + return mUnpack.alignment; +} + +const PixelUnpackState &State::getUnpackState() const +{ + return mUnpack; +} + +void State::getBooleanv(GLenum pname, GLboolean *params) +{ + switch (pname) + { + case GL_SAMPLE_COVERAGE_INVERT: *params = mSampleCoverageInvert; break; + case GL_DEPTH_WRITEMASK: *params = mDepthStencil.depthMask; break; + case GL_COLOR_WRITEMASK: + params[0] = mBlend.colorMaskRed; + params[1] = mBlend.colorMaskGreen; + params[2] = mBlend.colorMaskBlue; + params[3] = mBlend.colorMaskAlpha; + break; + case GL_CULL_FACE: *params = mRasterizer.cullFace; break; + case GL_POLYGON_OFFSET_FILL: *params = mRasterizer.polygonOffsetFill; break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mBlend.sampleAlphaToCoverage; break; + case GL_SAMPLE_COVERAGE: *params = mSampleCoverage; break; + case GL_SCISSOR_TEST: *params = mScissorTest; break; + case GL_STENCIL_TEST: *params = mDepthStencil.stencilTest; break; + case GL_DEPTH_TEST: *params = mDepthStencil.depthTest; break; + case GL_BLEND: *params = mBlend.blend; break; + case GL_DITHER: *params = mBlend.dither; break; + case GL_TRANSFORM_FEEDBACK_ACTIVE: *params = getCurrentTransformFeedback()->isStarted(); break; + case GL_TRANSFORM_FEEDBACK_PAUSED: *params = getCurrentTransformFeedback()->isPaused(); break; + default: + UNREACHABLE(); + break; + } +} + +void State::getFloatv(GLenum pname, GLfloat *params) +{ + // Please note: DEPTH_CLEAR_VALUE is included in our internal getFloatv implementation + // because it is stored as a float, despite the fact that the GL ES 2.0 spec names + // GetIntegerv as its native query function. As it would require conversion in any + // case, this should make no difference to the calling application. + switch (pname) + { + case GL_LINE_WIDTH: *params = mLineWidth; break; + case GL_SAMPLE_COVERAGE_VALUE: *params = mSampleCoverageValue; break; + case GL_DEPTH_CLEAR_VALUE: *params = mDepthClearValue; break; + case GL_POLYGON_OFFSET_FACTOR: *params = mRasterizer.polygonOffsetFactor; break; + case GL_POLYGON_OFFSET_UNITS: *params = mRasterizer.polygonOffsetUnits; break; + case GL_DEPTH_RANGE: + params[0] = mNearZ; + params[1] = mFarZ; + break; + case GL_COLOR_CLEAR_VALUE: + params[0] = mColorClearValue.red; + params[1] = mColorClearValue.green; + params[2] = mColorClearValue.blue; + params[3] = mColorClearValue.alpha; + break; + case GL_BLEND_COLOR: + params[0] = mBlendColor.red; + params[1] = mBlendColor.green; + params[2] = mBlendColor.blue; + params[3] = mBlendColor.alpha; + break; + default: + UNREACHABLE(); + break; + } +} + +void State::getIntegerv(GLenum pname, GLint *params) +{ + if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) + { + unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0_EXT); + ASSERT(colorAttachment < mContext->getCaps().maxDrawBuffers); + Framebuffer *framebuffer = mDrawFramebuffer; + *params = framebuffer->getDrawBufferState(colorAttachment); + return; + } + + // Please note: DEPTH_CLEAR_VALUE is not included in our internal getIntegerv implementation + // because it is stored as a float, despite the fact that the GL ES 2.0 spec names + // GetIntegerv as its native query function. As it would require conversion in any + // case, this should make no difference to the calling application. You may find it in + // State::getFloatv. + switch (pname) + { + case GL_ARRAY_BUFFER_BINDING: *params = mArrayBuffer.id(); break; + case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = getVertexArray()->getElementArrayBufferId(); break; + //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mDrawFramebuffer->id(); break; + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mReadFramebuffer->id(); break; + case GL_RENDERBUFFER_BINDING: *params = mRenderbuffer.id(); break; + case GL_VERTEX_ARRAY_BINDING: *params = mVertexArray->id(); break; + case GL_CURRENT_PROGRAM: *params = mCurrentProgramId; break; + case GL_PACK_ALIGNMENT: *params = mPack.alignment; break; + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: *params = mPack.reverseRowOrder; break; + case GL_UNPACK_ALIGNMENT: *params = mUnpack.alignment; break; + case GL_GENERATE_MIPMAP_HINT: *params = mGenerateMipmapHint; break; + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mFragmentShaderDerivativeHint; break; + case GL_ACTIVE_TEXTURE: *params = (mActiveSampler + GL_TEXTURE0); break; + case GL_STENCIL_FUNC: *params = mDepthStencil.stencilFunc; break; + case GL_STENCIL_REF: *params = mStencilRef; break; + case GL_STENCIL_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilMask); break; + case GL_STENCIL_BACK_FUNC: *params = mDepthStencil.stencilBackFunc; break; + case GL_STENCIL_BACK_REF: *params = mStencilBackRef; break; + case GL_STENCIL_BACK_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilBackMask); break; + case GL_STENCIL_FAIL: *params = mDepthStencil.stencilFail; break; + case GL_STENCIL_PASS_DEPTH_FAIL: *params = mDepthStencil.stencilPassDepthFail; break; + case GL_STENCIL_PASS_DEPTH_PASS: *params = mDepthStencil.stencilPassDepthPass; break; + case GL_STENCIL_BACK_FAIL: *params = mDepthStencil.stencilBackFail; break; + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: *params = mDepthStencil.stencilBackPassDepthFail; break; + case GL_STENCIL_BACK_PASS_DEPTH_PASS: *params = mDepthStencil.stencilBackPassDepthPass; break; + case GL_DEPTH_FUNC: *params = mDepthStencil.depthFunc; break; + case GL_BLEND_SRC_RGB: *params = mBlend.sourceBlendRGB; break; + case GL_BLEND_SRC_ALPHA: *params = mBlend.sourceBlendAlpha; break; + case GL_BLEND_DST_RGB: *params = mBlend.destBlendRGB; break; + case GL_BLEND_DST_ALPHA: *params = mBlend.destBlendAlpha; break; + case GL_BLEND_EQUATION_RGB: *params = mBlend.blendEquationRGB; break; + case GL_BLEND_EQUATION_ALPHA: *params = mBlend.blendEquationAlpha; break; + case GL_STENCIL_WRITEMASK: *params = clampToInt(mDepthStencil.stencilWritemask); break; + case GL_STENCIL_BACK_WRITEMASK: *params = clampToInt(mDepthStencil.stencilBackWritemask); break; + case GL_STENCIL_CLEAR_VALUE: *params = mStencilClearValue; break; + case GL_SAMPLE_BUFFERS: + case GL_SAMPLES: + { + gl::Framebuffer *framebuffer = mDrawFramebuffer; + if (framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE) + { + switch (pname) + { + case GL_SAMPLE_BUFFERS: + if (framebuffer->getSamples() != 0) + { + *params = 1; + } + else + { + *params = 0; + } + break; + case GL_SAMPLES: + *params = framebuffer->getSamples(); + break; + } + } + else + { + *params = 0; + } + } + break; + case GL_VIEWPORT: + params[0] = mViewport.x; + params[1] = mViewport.y; + params[2] = mViewport.width; + params[3] = mViewport.height; + break; + case GL_SCISSOR_BOX: + params[0] = mScissor.x; + params[1] = mScissor.y; + params[2] = mScissor.width; + params[3] = mScissor.height; + break; + case GL_CULL_FACE_MODE: *params = mRasterizer.cullMode; break; + case GL_FRONT_FACE: *params = mRasterizer.frontFace; break; + case GL_RED_BITS: + case GL_GREEN_BITS: + case GL_BLUE_BITS: + case GL_ALPHA_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer(); + + if (colorbuffer) + { + switch (pname) + { + case GL_RED_BITS: *params = colorbuffer->getRedSize(); break; + case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); break; + case GL_BLUE_BITS: *params = colorbuffer->getBlueSize(); break; + case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); break; + } + } + else + { + *params = 0; + } + } + break; + case GL_DEPTH_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer(); + + if (depthbuffer) + { + *params = depthbuffer->getDepthSize(); + } + else + { + *params = 0; + } + } + break; + case GL_STENCIL_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer(); + + if (stencilbuffer) + { + *params = stencilbuffer->getStencilSize(); + } + else + { + *params = 0; + } + } + break; + case GL_TEXTURE_BINDING_2D: + ASSERT(mActiveSampler < mContext->getMaximumCombinedTextureImageUnits()); + *params = mSamplerTexture[TEXTURE_2D][mActiveSampler].id(); + break; + case GL_TEXTURE_BINDING_CUBE_MAP: + ASSERT(mActiveSampler < mContext->getMaximumCombinedTextureImageUnits()); + *params = mSamplerTexture[TEXTURE_CUBE][mActiveSampler].id(); + break; + case GL_TEXTURE_BINDING_3D: + ASSERT(mActiveSampler < mContext->getMaximumCombinedTextureImageUnits()); + *params = mSamplerTexture[TEXTURE_3D][mActiveSampler].id(); + break; + case GL_TEXTURE_BINDING_2D_ARRAY: + ASSERT(mActiveSampler < mContext->getMaximumCombinedTextureImageUnits()); + *params = mSamplerTexture[TEXTURE_2D_ARRAY][mActiveSampler].id(); + break; + case GL_UNIFORM_BUFFER_BINDING: + *params = mGenericUniformBuffer.id(); + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + *params = mGenericTransformFeedbackBuffer.id(); + break; + case GL_COPY_READ_BUFFER_BINDING: + *params = mCopyReadBuffer.id(); + break; + case GL_COPY_WRITE_BUFFER_BINDING: + *params = mCopyWriteBuffer.id(); + break; + case GL_PIXEL_PACK_BUFFER_BINDING: + *params = mPack.pixelBuffer.id(); + break; + case GL_PIXEL_UNPACK_BUFFER_BINDING: + *params = mUnpack.pixelBuffer.id(); + break; + default: + UNREACHABLE(); + break; + } +} + +bool State::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) +{ + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS) + { + *data = mTransformFeedbackBuffers[index].id(); + } + break; + case GL_UNIFORM_BUFFER_BINDING: + if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS) + { + *data = mUniformBuffers[index].id(); + } + break; + default: + return false; + } + + return true; +} + +bool State::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) +{ + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS) + { + *data = mTransformFeedbackBuffers[index].getOffset(); + } + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS) + { + *data = mTransformFeedbackBuffers[index].getSize(); + } + break; + case GL_UNIFORM_BUFFER_START: + if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS) + { + *data = mUniformBuffers[index].getOffset(); + } + break; + case GL_UNIFORM_BUFFER_SIZE: + if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS) + { + *data = mUniformBuffers[index].getSize(); + } + break; + default: + return false; + } + + return true; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/State.h b/src/3rdparty/angle/src/libGLESv2/State.h new file mode 100644 index 0000000000..09be0b335d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/State.h @@ -0,0 +1,307 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// State.h: Defines the State class, encapsulating raw GL state + +#ifndef LIBGLESV2_STATE_H_ +#define LIBGLESV2_STATE_H_ + +#include "common/angleutils.h" +#include "common/RefCountObject.h" +#include "libGLESv2/angletypes.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/TransformFeedback.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/Sampler.h" + +namespace gl +{ +class Query; +class VertexArray; +class Context; + +class State +{ + public: + State(); + ~State(); + + void setContext(Context *context) { mContext = context; } + + // State chunk getters + const RasterizerState &getRasterizerState() const; + const BlendState &getBlendState() const; + const DepthStencilState &getDepthStencilState() const; + + // Clear behavior setters & state parameter block generation function + void setClearColor(float red, float green, float blue, float alpha); + void setClearDepth(float depth); + void setClearStencil(int stencil); + ClearParameters getClearParameters(GLbitfield mask) const; + + // Write mask manipulation + void setColorMask(bool red, bool green, bool blue, bool alpha); + void setDepthMask(bool mask); + + // Discard toggle & query + bool isRasterizerDiscardEnabled() const; + void setRasterizerDiscard(bool enabled); + + // Face culling state manipulation + bool isCullFaceEnabled() const; + void setCullFace(bool enabled); + void setCullMode(GLenum mode); + void setFrontFace(GLenum front); + + // Depth test state manipulation + bool isDepthTestEnabled() const; + void setDepthTest(bool enabled); + void setDepthFunc(GLenum depthFunc); + void setDepthRange(float zNear, float zFar); + void getDepthRange(float *zNear, float *zFar) const; + + // Blend state manipulation + bool isBlendEnabled() const; + void setBlend(bool enabled); + void setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha); + void setBlendColor(float red, float green, float blue, float alpha); + void setBlendEquation(GLenum rgbEquation, GLenum alphaEquation); + const ColorF &getBlendColor() const; + + // Stencil state maniupulation + bool isStencilTestEnabled() const; + void setStencilTest(bool enabled); + void setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask); + void setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask); + void setStencilWritemask(GLuint stencilWritemask); + void setStencilBackWritemask(GLuint stencilBackWritemask); + void setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass); + void setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass); + GLint getStencilRef() const; + GLint getStencilBackRef() const; + + // Depth bias/polygon offset state manipulation + bool isPolygonOffsetFillEnabled() const; + void setPolygonOffsetFill(bool enabled); + void setPolygonOffsetParams(GLfloat factor, GLfloat units); + + // Multisample coverage state manipulation + bool isSampleAlphaToCoverageEnabled() const; + void setSampleAlphaToCoverage(bool enabled); + bool isSampleCoverageEnabled() const; + void setSampleCoverage(bool enabled); + void setSampleCoverageParams(GLclampf value, bool invert); + void getSampleCoverageParams(GLclampf *value, bool *invert); + + // Scissor test state toggle & query + bool isScissorTestEnabled() const; + void setScissorTest(bool enabled); + void setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height); + const Rectangle &getScissor() const; + + // Dither state toggle & query + bool isDitherEnabled() const; + void setDither(bool enabled); + + // Generic state toggle & query + void setEnableFeature(GLenum feature, bool enabled); + bool getEnableFeature(GLenum feature); + + // Line width state setter + void setLineWidth(GLfloat width); + + // Hint setters + void setGenerateMipmapHint(GLenum hint); + void setFragmentShaderDerivativeHint(GLenum hint); + + // Viewport state setter/getter + void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height); + const Rectangle &getViewport() const; + + // Texture binding & active texture unit manipulation + void setActiveSampler(unsigned int active); + unsigned int getActiveSampler() const; + void setSamplerTexture(TextureType type, Texture *texture); + Texture *getSamplerTexture(unsigned int sampler, TextureType type) const; + GLuint getSamplerTextureId(unsigned int sampler, TextureType type) const; + void detachTexture(GLuint texture); + + // Sampler object binding manipulation + void setSamplerBinding(GLuint textureUnit, Sampler *sampler); + GLuint getSamplerId(GLuint textureUnit) const; + Sampler *getSampler(GLuint textureUnit) const; + void detachSampler(GLuint sampler); + + // Renderbuffer binding manipulation + void setRenderbufferBinding(Renderbuffer *renderbuffer); + GLuint getRenderbufferId() const; + Renderbuffer *getCurrentRenderbuffer(); + void detachRenderbuffer(GLuint renderbuffer); + + // Framebuffer binding manipulation + void setReadFramebufferBinding(Framebuffer *framebuffer); + void setDrawFramebufferBinding(Framebuffer *framebuffer); + Framebuffer *getTargetFramebuffer(GLenum target) const; + Framebuffer *getReadFramebuffer(); + Framebuffer *getDrawFramebuffer(); + const Framebuffer *getReadFramebuffer() const; + const Framebuffer *getDrawFramebuffer() const; + bool removeReadFramebufferBinding(GLuint framebuffer); + bool removeDrawFramebufferBinding(GLuint framebuffer); + + // Vertex array object binding manipulation + void setVertexArrayBinding(VertexArray *vertexArray); + GLuint getVertexArrayId() const; + VertexArray *getVertexArray() const; + bool removeVertexArrayBinding(GLuint vertexArray); + + // Program binding manipulation + void setCurrentProgram(GLuint programId, Program *newProgram); + void setCurrentProgramBinary(ProgramBinary *binary); + GLuint getCurrentProgramId() const; + ProgramBinary *getCurrentProgramBinary() const; + + // Transform feedback object (not buffer) binding manipulation + void setTransformFeedbackBinding(TransformFeedback *transformFeedback); + TransformFeedback *getCurrentTransformFeedback() const; + void detachTransformFeedback(GLuint transformFeedback); + + // Query binding manipulation + bool isQueryActive() const; + void setActiveQuery(GLenum target, Query *query); + GLuint getActiveQueryId(GLenum target) const; + Query *getActiveQuery(GLenum target) const; + + //// Typed buffer binding point manipulation //// + // GL_ARRAY_BUFFER + void setArrayBufferBinding(Buffer *buffer); + GLuint getArrayBufferId() const; + bool removeArrayBufferBinding(GLuint buffer); + + // GL_UNIFORM_BUFFER - Both indexed and generic targets + void setGenericUniformBufferBinding(Buffer *buffer); + void setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size); + GLuint getIndexedUniformBufferId(GLuint index) const; + Buffer *getIndexedUniformBuffer(GLuint index) const; + + // GL_TRANSFORM_FEEDBACK_BUFFER - Both indexed and generic targets + void setGenericTransformFeedbackBufferBinding(Buffer *buffer); + void setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size); + GLuint getIndexedTransformFeedbackBufferId(GLuint index) const; + Buffer *getIndexedTransformFeedbackBuffer(GLuint index) const; + GLuint getIndexedTransformFeedbackBufferOffset(GLuint index) const; + + // GL_COPY_[READ/WRITE]_BUFFER + void setCopyReadBufferBinding(Buffer *buffer); + void setCopyWriteBufferBinding(Buffer *buffer); + + // GL_PIXEL[PACK/UNPACK]_BUFFER + void setPixelPackBufferBinding(Buffer *buffer); + void setPixelUnpackBufferBinding(Buffer *buffer); + + // Retrieve typed buffer by target (non-indexed) + Buffer *getTargetBuffer(GLenum target) const; + + // Vertex attrib manipulation + void setEnableVertexAttribArray(unsigned int attribNum, bool enabled); + void setVertexAttribf(GLuint index, const GLfloat values[4]); + void setVertexAttribu(GLuint index, const GLuint values[4]); + void setVertexAttribi(GLuint index, const GLint values[4]); + void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, + bool normalized, bool pureInteger, GLsizei stride, const void *pointer); + const VertexAttribute &getVertexAttribState(unsigned int attribNum) const; + const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const; + const VertexAttribCurrentValueData *getVertexAttribCurrentValues() const; + const void *getVertexAttribPointer(unsigned int attribNum) const; + + // Pixel pack state manipulation + void setPackAlignment(GLint alignment); + GLint getPackAlignment() const; + void setPackReverseRowOrder(bool reverseRowOrder); + bool getPackReverseRowOrder() const; + const PixelPackState &getPackState() const; + + // Pixel unpack state manipulation + void setUnpackAlignment(GLint alignment); + GLint getUnpackAlignment() const; + const PixelUnpackState &getUnpackState() const; + + // State query functions + void getBooleanv(GLenum pname, GLboolean *params); + void getFloatv(GLenum pname, GLfloat *params); + void getIntegerv(GLenum pname, GLint *params); + bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data); + bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data); + + private: + DISALLOW_COPY_AND_ASSIGN(State); + + Context *mContext; + + ColorF mColorClearValue; + GLclampf mDepthClearValue; + int mStencilClearValue; + + RasterizerState mRasterizer; + bool mScissorTest; + Rectangle mScissor; + + BlendState mBlend; + ColorF mBlendColor; + bool mSampleCoverage; + GLclampf mSampleCoverageValue; + bool mSampleCoverageInvert; + + DepthStencilState mDepthStencil; + GLint mStencilRef; + GLint mStencilBackRef; + + GLfloat mLineWidth; + + GLenum mGenerateMipmapHint; + GLenum mFragmentShaderDerivativeHint; + + Rectangle mViewport; + float mNearZ; + float mFarZ; + + unsigned int mActiveSampler; // Active texture unit selector - GL_TEXTURE0 + BindingPointer<Buffer> mArrayBuffer; + Framebuffer *mReadFramebuffer; + Framebuffer *mDrawFramebuffer; + BindingPointer<Renderbuffer> mRenderbuffer; + GLuint mCurrentProgramId; + BindingPointer<ProgramBinary> mCurrentProgramBinary; + + VertexAttribCurrentValueData mVertexAttribCurrentValues[MAX_VERTEX_ATTRIBS]; // From glVertexAttrib + VertexArray *mVertexArray; + + BindingPointer<Texture> mSamplerTexture[TEXTURE_TYPE_COUNT][IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS]; + BindingPointer<Sampler> mSamplers[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS]; + + typedef std::map< GLenum, BindingPointer<Query> > ActiveQueryMap; + ActiveQueryMap mActiveQueries; + + BindingPointer<Buffer> mGenericUniformBuffer; + OffsetBindingPointer<Buffer> mUniformBuffers[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS]; + + BindingPointer<TransformFeedback> mTransformFeedback; + BindingPointer<Buffer> mGenericTransformFeedbackBuffer; + OffsetBindingPointer<Buffer> mTransformFeedbackBuffers[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + + BindingPointer<Buffer> mCopyReadBuffer; + BindingPointer<Buffer> mCopyWriteBuffer; + + PixelUnpackState mUnpack; + PixelPackState mPack; +}; + +} + +#endif // LIBGLESV2_STATE_H_ + diff --git a/src/3rdparty/angle/src/libGLESv2/Texture.cpp b/src/3rdparty/angle/src/libGLESv2/Texture.cpp index 3257d05dd4..b0c0ee51bd 100644 --- a/src/3rdparty/angle/src/libGLESv2/Texture.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Texture.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -12,168 +12,49 @@ #include "libGLESv2/Texture.h" #include "libGLESv2/main.h" -#include "libGLESv2/mathutil.h" -#include "libGLESv2/utilities.h" -#if defined(ANGLE_ENABLE_D3D9) -# include "libGLESv2/renderer/d3d9/Blit.h" -#else -# define D3DFMT_UNKNOWN DXGI_FORMAT_UNKNOWN -#endif +#include "common/mathutil.h" +#include "common/utilities.h" +#include "libGLESv2/formatutils.h" #include "libGLESv2/Renderbuffer.h" #include "libGLESv2/renderer/Image.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/TextureStorage.h" +#include "libGLESv2/renderer/d3d/TextureStorage.h" #include "libEGL/Surface.h" +#include "libGLESv2/renderer/RenderTarget.h" +#include "libGLESv2/renderer/TextureImpl.h" namespace gl { -Texture::Texture(rx::Renderer *renderer, GLuint id) : RefCountObject(id) +Texture::Texture(GLuint id, GLenum target) + : RefCountObject(id), + mUsage(GL_NONE), + mImmutable(false), + mTarget(target) { - mRenderer = renderer; - - mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR; - mSamplerState.magFilter = GL_LINEAR; - mSamplerState.wrapS = GL_REPEAT; - mSamplerState.wrapT = GL_REPEAT; - mSamplerState.maxAnisotropy = 1.0f; - mSamplerState.lodOffset = 0; - mUsage = GL_NONE; - - mDirtyImages = true; - - mImmutable = false; } Texture::~Texture() { } -// Returns true on successful filter state update (valid enum parameter) -bool Texture::setMinFilter(GLenum filter) -{ - switch (filter) - { - case GL_NEAREST: - case GL_LINEAR: - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: - mSamplerState.minFilter = filter; - return true; - default: - return false; - } -} - -// Returns true on successful filter state update (valid enum parameter) -bool Texture::setMagFilter(GLenum filter) +GLenum Texture::getTarget() const { - switch (filter) - { - case GL_NEAREST: - case GL_LINEAR: - mSamplerState.magFilter = filter; - return true; - default: - return false; - } + return mTarget; } -// Returns true on successful wrap state update (valid enum parameter) -bool Texture::setWrapS(GLenum wrap) +void Texture::setUsage(GLenum usage) { - switch (wrap) - { - case GL_REPEAT: - case GL_CLAMP_TO_EDGE: - case GL_MIRRORED_REPEAT: - mSamplerState.wrapS = wrap; - return true; - default: - return false; - } + mUsage = usage; } -// Returns true on successful wrap state update (valid enum parameter) -bool Texture::setWrapT(GLenum wrap) -{ - switch (wrap) - { - case GL_REPEAT: - case GL_CLAMP_TO_EDGE: - case GL_MIRRORED_REPEAT: - mSamplerState.wrapT = wrap; - return true; - default: - return false; - } -} - -// Returns true on successful max anisotropy update (valid anisotropy value) -bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy) -{ - textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy); - if (textureMaxAnisotropy < 1.0f) - { - return false; - } - - mSamplerState.maxAnisotropy = textureMaxAnisotropy; - - return true; -} - -// Returns true on successful usage state update (valid enum parameter) -bool Texture::setUsage(GLenum usage) -{ - switch (usage) - { - case GL_NONE: - case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: - mUsage = usage; - return true; - default: - return false; - } -} - -GLenum Texture::getMinFilter() const -{ - return mSamplerState.minFilter; -} - -GLenum Texture::getMagFilter() const -{ - return mSamplerState.magFilter; -} - -GLenum Texture::getWrapS() const -{ - return mSamplerState.wrapS; -} - -GLenum Texture::getWrapT() const -{ - return mSamplerState.wrapT; -} - -float Texture::getMaxAnisotropy() const -{ - return mSamplerState.maxAnisotropy; -} - -int Texture::getLodOffset() -{ - rx::TextureStorageInterface *texture = getStorage(false); - return texture ? texture->getLodOffset() : 0; -} - -void Texture::getSamplerState(SamplerState *sampler) +void Texture::getSamplerStateWithNativeOffset(SamplerState *sampler) { *sampler = mSamplerState; - sampler->lodOffset = getLodOffset(); + + // Offset the effective base level by the texture storage's top level + rx::TextureStorageInterface *texture = getNativeTexture(); + int topLevel = texture ? texture->getTopLevel() : 0; + sampler->baseLevel = topLevel + mSamplerState.baseLevel; } GLenum Texture::getUsage() const @@ -181,179 +62,97 @@ GLenum Texture::getUsage() const return mUsage; } -bool Texture::isMipmapFiltered() const +GLint Texture::getBaseLevelWidth() const { - switch (mSamplerState.minFilter) - { - case GL_NEAREST: - case GL_LINEAR: - return false; - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: - return true; - default: UNREACHABLE(); - return false; - } + const rx::Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getWidth() : 0); } -void Texture::setImage(GLint unpackAlignment, const void *pixels, rx::Image *image) +GLint Texture::getBaseLevelHeight() const { - if (pixels != NULL) - { - image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels); - mDirtyImages = true; - } + const rx::Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getHeight() : 0); } -void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image) +GLint Texture::getBaseLevelDepth() const { - if (pixels != NULL) - { - image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels); - mDirtyImages = true; - } + const rx::Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getDepth() : 0); } -bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image) +// Note: "base level image" is loosely defined to be any image from the base level, +// where in the base of 2D array textures and cube maps there are several. Don't use +// the base level image for anything except querying texture format and size. +GLenum Texture::getBaseLevelInternalFormat() const { - if (pixels != NULL) - { - image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels); - mDirtyImages = true; - } - - return true; -} - -bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image) -{ - if (pixels != NULL) - { - image->loadCompressedData(xoffset, yoffset, width, height, pixels); - mDirtyImages = true; - } - - return true; -} - -rx::TextureStorageInterface *Texture::getNativeTexture() -{ - // ensure the underlying texture is created - - rx::TextureStorageInterface *storage = getStorage(false); - if (storage) - { - updateTexture(); - } - - return storage; -} - -bool Texture::hasDirtyImages() const -{ - return mDirtyImages; -} - -void Texture::resetDirty() -{ - mDirtyImages = false; + const rx::Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getInternalFormat() : GL_NONE); } unsigned int Texture::getTextureSerial() { - rx::TextureStorageInterface *texture = getStorage(false); + rx::TextureStorageInterface *texture = getNativeTexture(); return texture ? texture->getTextureSerial() : 0; } -unsigned int Texture::getRenderTargetSerial(GLenum target) -{ - rx::TextureStorageInterface *texture = getStorage(true); - return texture ? texture->getRenderTargetSerial(target) : 0; -} - bool Texture::isImmutable() const { return mImmutable; } -GLint Texture::creationLevels(GLsizei width, GLsizei height) const +int Texture::immutableLevelCount() { - if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport()) - { - return 0; // Maximum number of levels - } - else - { - // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. - return 1; - } + return (mImmutable ? getNativeTexture()->getStorageInstance()->getLevelCount() : 0); } -GLint Texture::creationLevels(GLsizei size) const +int Texture::mipLevels() const { - return creationLevels(size, size); + return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; } -Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id) +Texture2D::Texture2D(rx::Texture2DImpl *impl, GLuint id) + : Texture(id, GL_TEXTURE_2D), + mTexture(impl) { - mTexStorage = NULL; mSurface = NULL; - mColorbufferProxy = NULL; - mProxyRefs = 0; - - for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) - { - mImageArray[i] = renderer->createImage(); - } } Texture2D::~Texture2D() { - mColorbufferProxy = NULL; + SafeDelete(mTexture); - delete mTexStorage; - mTexStorage = NULL; - if (mSurface) { mSurface->setBoundTexture(NULL); mSurface = NULL; } - - for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) - { - delete mImageArray[i]; - } } -// We need to maintain a count of references to renderbuffers acting as -// proxies for this texture, so that we do not attempt to use a pointer -// to a renderbuffer proxy which has been deleted. -void Texture2D::addProxyRef(const Renderbuffer *proxy) +rx::TextureStorageInterface *Texture2D::getNativeTexture() { - mProxyRefs++; + return mTexture->getNativeTexture(); } -void Texture2D::releaseProxy(const Renderbuffer *proxy) +void Texture2D::setUsage(GLenum usage) { - if (mProxyRefs > 0) - mProxyRefs--; + mUsage = usage; + mTexture->setUsage(usage); +} - if (mProxyRefs == 0) - mColorbufferProxy = NULL; +bool Texture2D::hasDirtyImages() const +{ + return mTexture->hasDirtyImages(); } -GLenum Texture2D::getTarget() const +void Texture2D::resetDirty() { - return GL_TEXTURE_2D; + mTexture->resetDirty(); } GLsizei Texture2D::getWidth(GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getWidth(); + return mTexture->getImage(level)->getWidth(); else return 0; } @@ -361,7 +160,7 @@ GLsizei Texture2D::getWidth(GLint level) const GLsizei Texture2D::getHeight(GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getHeight(); + return mTexture->getImage(level)->getHeight(); else return 0; } @@ -369,7 +168,7 @@ GLsizei Texture2D::getHeight(GLint level) const GLenum Texture2D::getInternalFormat(GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getInternalFormat(); + return mTexture->getImage(level)->getInternalFormat(); else return GL_NONE; } @@ -377,63 +176,33 @@ GLenum Texture2D::getInternalFormat(GLint level) const GLenum Texture2D::getActualFormat(GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getActualFormat(); + return mTexture->getImage(level)->getActualFormat(); else - return D3DFMT_UNKNOWN; + return GL_NONE; } -void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height) +void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height) { releaseTexImage(); - // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level); - const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level); - const int storageFormat = mImageArray[0]->getInternalFormat(); - - mImageArray[level]->redefine(mRenderer, internalformat, width, height, false); - - if (mTexStorage) - { - const int storageLevels = mTexStorage->levelCount(); - - if ((level >= storageLevels && storageLevels != 0) || - width != storageWidth || - height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage - { - for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->markDirty(); - } - - delete mTexStorage; - mTexStorage = NULL; - mDirtyImages = true; - } - } + mTexture->redefineImage(level, internalformat, width, height); } -void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - GLint internalformat = ConvertSizedInternalFormat(format, type); - redefineImage(level, internalformat, width, height); + GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat + : GetSizedInternalFormat(format, type); + redefineImage(level, sizedInternalFormat, width, height); - Texture::setImage(unpackAlignment, pixels, mImageArray[level]); + mTexture->setImage(level, width, height, internalFormat, format, type, unpack, pixels); } void Texture2D::bindTexImage(egl::Surface *surface) { releaseTexImage(); - GLint internalformat = surface->getFormat(); + mTexture->bindTexImage(surface); - mImageArray[0]->redefine(mRenderer, internalformat, surface->getWidth(), surface->getHeight(), true); - - delete mTexStorage; - mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain()); - - mDirtyImages = true; mSurface = surface; mSurface->setBoundTexture(this); } @@ -445,16 +214,7 @@ void Texture2D::releaseTexImage() mSurface->setBoundTexture(NULL); mSurface = NULL; - if (mTexStorage) - { - delete mTexStorage; - mTexStorage = NULL; - } - - for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->redefine(mRenderer, GL_NONE, 0, 0, true); - } + mTexture->releaseTexImage(); } } @@ -463,495 +223,126 @@ void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GL // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly redefineImage(level, format, width, height); - Texture::setCompressedImage(imageSize, pixels, mImageArray[level]); + mTexture->setCompressedImage(level, format, width, height, imageSize, pixels); } -void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - if (level < levelCount()) - { - rx::Image *image = mImageArray[level]; - if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height)) - { - image->markClean(); - } - } -} - -void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) -{ - if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[level])) - { - commitRect(level, xoffset, yoffset, width, height); - } + mTexture->subImage(level, xoffset, yoffset, width, height, format, type, unpack, pixels); } void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) { - if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[level])) - { - commitRect(level, xoffset, yoffset, width, height); - } + mTexture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, pixels); } void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE); - redefineImage(level, internalformat, width, height); + GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format + : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); + redefineImage(level, sizedInternalFormat, width, height); - if (!mImageArray[level]->isRenderableFormat()) - { - mImageArray[level]->copy(0, 0, x, y, width, height, source); - mDirtyImages = true; - } - else - { - if (!mTexStorage || !mTexStorage->isRenderTarget()) - { - convertToRenderTarget(); - } - - mImageArray[level]->markClean(); - - if (width != 0 && height != 0 && level < levelCount()) - { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level); - } - } + mTexture->copyImage(level, format, x, y, width, height, source); } -void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight()) - { - return gl::error(GL_INVALID_VALUE); - } - - if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) - { - mImageArray[level]->copy(xoffset, yoffset, x, y, width, height, source); - mDirtyImages = true; - } - else - { - if (!mTexStorage || !mTexStorage->isRenderTarget()) - { - convertToRenderTarget(); - } - - updateTexture(); - - if (level < levelCount()) - { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage(source, sourceRect, - gl::ExtractFormat(mImageArray[0]->getInternalFormat()), - xoffset, yoffset, mTexStorage, level); - } - } + mTexture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); } void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { - delete mTexStorage; - mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height); mImmutable = true; - for (int level = 0; level < levels; level++) - { - mImageArray[level]->redefine(mRenderer, internalformat, width, height, true); - width = std::max(1, width >> 1); - height = std::max(1, height >> 1); - } - - for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - mImageArray[level]->redefine(mRenderer, GL_NONE, 0, 0, true); - } - - if (mTexStorage->isManaged()) - { - int levels = levelCount(); - - for (int level = 0; level < levels; level++) - { - mImageArray[level]->setManagedSurface(mTexStorage, level); - } - } + mTexture->storage(levels, internalformat, width, height); } // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. -bool Texture2D::isSamplerComplete() const +bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const { - GLsizei width = mImageArray[0]->getWidth(); - GLsizei height = mImageArray[0]->getHeight(); - - if (width <= 0 || height <= 0) - { - return false; - } - - bool mipmapping = isMipmapFiltered(); - bool filtering, renderable; - - if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) || - (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable))) - { - if (mSamplerState.magFilter != GL_NEAREST || - (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) - { - return false; - } - } - - bool npotSupport = mRenderer->getNonPower2TextureSupport(); - - if (!npotSupport) - { - if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) || - (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height))) - { - return false; - } - } - - if (mipmapping) - { - if (!npotSupport) - { - if (!isPow2(width) || !isPow2(height)) - { - return false; - } - } - - if (!isMipmapComplete()) - { - return false; - } - } - - return true; -} - -// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool Texture2D::isMipmapComplete() const -{ - if (isImmutable()) - { - return true; - } - - GLsizei width = mImageArray[0]->getWidth(); - GLsizei height = mImageArray[0]->getHeight(); - - if (width <= 0 || height <= 0) - { - return false; - } - - int q = log2(std::max(width, height)); - - for (int level = 1; level <= q; level++) - { - if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat()) - { - return false; - } - - if (mImageArray[level]->getWidth() != std::max(1, width >> level)) - { - return false; - } - - if (mImageArray[level]->getHeight() != std::max(1, height >> level)) - { - return false; - } - } - - return true; + return mTexture->isSamplerComplete(samplerState); } bool Texture2D::isCompressed(GLint level) const { - return IsCompressed(getInternalFormat(level)); + return IsFormatCompressed(getInternalFormat(level)); } bool Texture2D::isDepth(GLint level) const { - return IsDepthTexture(getInternalFormat(level)); -} - -// Constructs a native texture resource from the texture images -void Texture2D::createTexture() -{ - GLsizei width = mImageArray[0]->getWidth(); - GLsizei height = mImageArray[0]->getHeight(); - - if (!(width > 0 && height > 0)) - return; // do not attempt to create native textures for nonexistant data - - GLint levels = creationLevels(width, height); - GLenum internalformat = mImageArray[0]->getInternalFormat(); - - delete mTexStorage; - mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height); - - if (mTexStorage->isManaged()) - { - int levels = levelCount(); - - for (int level = 0; level < levels; level++) - { - mImageArray[level]->setManagedSurface(mTexStorage, level); - } - } - - mDirtyImages = true; -} - -void Texture2D::updateTexture() -{ - bool mipmapping = (isMipmapFiltered() && isMipmapComplete()); - - int levels = (mipmapping ? levelCount() : 1); - - for (int level = 0; level < levels; level++) - { - rx::Image *image = mImageArray[level]; - - if (image->isDirty()) - { - commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight()); - } - } -} - -void Texture2D::convertToRenderTarget() -{ - rx::TextureStorageInterface2D *newTexStorage = NULL; - - if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0) - { - GLsizei width = mImageArray[0]->getWidth(); - GLsizei height = mImageArray[0]->getHeight(); - GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height); - GLenum internalformat = mImageArray[0]->getInternalFormat(); - - newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height); - - if (mTexStorage != NULL) - { - if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage)) - { - delete newTexStorage; - return gl::error(GL_OUT_OF_MEMORY); - } - } - } - - delete mTexStorage; - mTexStorage = newTexStorage; - - mDirtyImages = true; + return GetDepthBits(getInternalFormat(level)) > 0; } void Texture2D::generateMipmaps() { - if (!mRenderer->getNonPower2TextureSupport()) - { - if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight())) - { - return gl::error(GL_INVALID_OPERATION); - } - } - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight())); - for (unsigned int i = 1; i <= q; i++) + int levelCount = mipLevels(); + for (int level = 1; level < levelCount; level++) { - redefineImage(i, mImageArray[0]->getInternalFormat(), - std::max(mImageArray[0]->getWidth() >> i, 1), - std::max(mImageArray[0]->getHeight() >> i, 1)); + redefineImage(level, getBaseLevelInternalFormat(), + std::max(getBaseLevelWidth() >> level, 1), + std::max(getBaseLevelHeight() >> level, 1)); } - if (mTexStorage && mTexStorage->isRenderTarget()) - { - for (unsigned int i = 1; i <= q; i++) - { - mTexStorage->generateMipmap(i); - - mImageArray[i]->markClean(); - } - } - else - { - for (unsigned int i = 1; i <= q; i++) - { - mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]); - } - } + mTexture->generateMipmaps(); } -Renderbuffer *Texture2D::getRenderbuffer(GLenum target) +const rx::Image *Texture2D::getBaseLevelImage() const { - if (target != GL_TEXTURE_2D) - { - return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); - } - - if (mColorbufferProxy == NULL) - { - mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target)); - } - - return mColorbufferProxy; + return mTexture->getImage(0); } -rx::RenderTarget *Texture2D::getRenderTarget(GLenum target) +unsigned int Texture2D::getRenderTargetSerial(GLint level) { - ASSERT(target == GL_TEXTURE_2D); - - // ensure the underlying texture is created - if (getStorage(true) == NULL) - { - return NULL; - } - - updateTexture(); - - // ensure this is NOT a depth texture - if (isDepth(0)) - { - return NULL; - } - - return mTexStorage->getRenderTarget(); + return mTexture->getRenderTargetSerial(level); } -rx::RenderTarget *Texture2D::getDepthStencil(GLenum target) +rx::RenderTarget *Texture2D::getRenderTarget(GLint level) { - ASSERT(target == GL_TEXTURE_2D); - - // ensure the underlying texture is created - if (getStorage(true) == NULL) - { - return NULL; - } - - updateTexture(); - - // ensure this is actually a depth texture - if (!isDepth(0)) - { - return NULL; - } - return mTexStorage->getRenderTarget(); + return mTexture->getRenderTarget(level); } -int Texture2D::levelCount() +rx::RenderTarget *Texture2D::getDepthSencil(GLint level) { - return mTexStorage ? mTexStorage->levelCount() : 0; + return mTexture->getDepthSencil(level); } -rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget) +TextureCubeMap::TextureCubeMap(rx::TextureCubeImpl *impl, GLuint id) + : Texture(id, GL_TEXTURE_CUBE_MAP), + mTexture(impl) { - if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) - { - if (renderTarget) - { - convertToRenderTarget(); - } - else - { - createTexture(); - } - } - - return mTexStorage; } -TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id) +TextureCubeMap::~TextureCubeMap() { - mTexStorage = NULL; - for (int i = 0; i < 6; i++) - { - mFaceProxies[i] = NULL; - mFaceProxyRefs[i] = 0; - - for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) - { - mImageArray[i][j] = renderer->createImage(); - } - } + SafeDelete(mTexture); } -TextureCubeMap::~TextureCubeMap() +rx::TextureStorageInterface *TextureCubeMap::getNativeTexture() { - for (int i = 0; i < 6; i++) - { - mFaceProxies[i] = NULL; - - for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) - { - delete mImageArray[i][j]; - } - } - - delete mTexStorage; - mTexStorage = NULL; + return mTexture->getNativeTexture(); } -// We need to maintain a count of references to renderbuffers acting as -// proxies for this texture, so that the texture is not deleted while -// proxy references still exist. If the reference count drops to zero, -// we set our proxy pointer NULL, so that a new attempt at referencing -// will cause recreation. -void TextureCubeMap::addProxyRef(const Renderbuffer *proxy) +void TextureCubeMap::setUsage(GLenum usage) { - for (int i = 0; i < 6; i++) - { - if (mFaceProxies[i] == proxy) - mFaceProxyRefs[i]++; - } + mUsage = usage; + mTexture->setUsage(usage); } -void TextureCubeMap::releaseProxy(const Renderbuffer *proxy) +bool TextureCubeMap::hasDirtyImages() const { - for (int i = 0; i < 6; i++) - { - if (mFaceProxies[i] == proxy) - { - if (mFaceProxyRefs[i] > 0) - mFaceProxyRefs[i]--; - - if (mFaceProxyRefs[i] == 0) - mFaceProxies[i] = NULL; - } - } + return mTexture->hasDirtyImages(); } -GLenum TextureCubeMap::getTarget() const +void TextureCubeMap::resetDirty() { - return GL_TEXTURE_CUBE_MAP; + mTexture->resetDirty(); } GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[faceIndex(target)][level]->getWidth(); + return mTexture->getImage(target, level)->getWidth(); else return 0; } @@ -959,7 +350,7 @@ GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[faceIndex(target)][level]->getHeight(); + return mTexture->getImage(target, level)->getHeight(); else return 0; } @@ -967,7 +358,7 @@ GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[faceIndex(target)][level]->getInternalFormat(); + return mTexture->getImage(target, level)->getInternalFormat(); else return GL_NONE; } @@ -975,525 +366,393 @@ GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const { if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[faceIndex(target)][level]->getActualFormat(); + return mTexture->getImage(target, level)->getActualFormat(); else - return D3DFMT_UNKNOWN; + return GL_NONE; } -void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(0, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(0, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(1, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(1, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(2, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(2, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(3, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(3, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(4, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(4, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - setImage(5, level, width, height, format, type, unpackAlignment, pixels); + mTexture->setImage(5, level, width, height, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) +void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) { - // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - redefineImage(faceIndex(face), level, format, width, height); + mTexture->setCompressedImage(target, level, format, width, height, imageSize, pixels); +} - Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]); +void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +{ + mTexture->subImage(target, level, xoffset, yoffset, width, height, format, type, unpack, pixels); } -void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) { - if (level < levelCount()) - { - rx::Image *image = mImageArray[face][level]; - if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height)) - image->markClean(); - } + mTexture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, pixels); } -void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86. +bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const { - if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[faceIndex(target)][level])) - { - commitRect(faceIndex(target), level, xoffset, yoffset, width, height); - } + return mTexture->isSamplerComplete(samplerState); } -void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool TextureCubeMap::isCubeComplete() const { - if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[faceIndex(target)][level])) - { - commitRect(faceIndex(target), level, xoffset, yoffset, width, height); - } + return mTexture->isCubeComplete(); } -// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86. -bool TextureCubeMap::isSamplerComplete() const +bool TextureCubeMap::isCompressed(GLenum target, GLint level) const { - int size = mImageArray[0][0]->getWidth(); + return IsFormatCompressed(getInternalFormat(target, level)); +} - bool mipmapping = isMipmapFiltered(); - bool filtering, renderable; +bool TextureCubeMap::isDepth(GLenum target, GLint level) const +{ + return GetDepthBits(getInternalFormat(target, level)) > 0; +} - if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) || - (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable))) - { - if (mSamplerState.magFilter != GL_NEAREST || - (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) - { - return false; - } - } +void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + mTexture->copyImage(target, level, format, x, y, width, height, source); +} - if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport()) - { - if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping) - { - return false; - } - } +void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + mTexture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); +} - if (!mipmapping) - { - if (!isCubeComplete()) - { - return false; - } - } - else - { - if (!isMipmapCubeComplete()) // Also tests for isCubeComplete() - { - return false; - } - } +void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) +{ + mImmutable = true; - return true; + mTexture->storage(levels, internalformat, size); } -// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool TextureCubeMap::isCubeComplete() const +void TextureCubeMap::generateMipmaps() { - if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth()) - { - return false; - } + mTexture->generateMipmaps(); +} - for (unsigned int face = 1; face < 6; face++) - { - if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() || - mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() || - mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat()) - { - return false; - } - } +const rx::Image *TextureCubeMap::getBaseLevelImage() const +{ + // Note: if we are not cube-complete, there is no single base level image that can describe all + // cube faces, so this method is only well-defined for a cube-complete base level. + return mTexture->getImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); +} - return true; +unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level) +{ + return mTexture->getRenderTargetSerial(target, level); } -bool TextureCubeMap::isMipmapCubeComplete() const +rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level) { - if (isImmutable()) - { - return true; - } + return mTexture->getRenderTarget(target, level); +} - if (!isCubeComplete()) - { - return false; - } +rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level) +{ + return mTexture->getDepthStencil(target, level); +} - GLsizei size = mImageArray[0][0]->getWidth(); +Texture3D::Texture3D(rx::Texture3DImpl *impl, GLuint id) + : Texture(id, GL_TEXTURE_3D), + mTexture(impl) +{ +} - int q = log2(size); +Texture3D::~Texture3D() +{ + SafeDelete(mTexture); +} - for (int face = 0; face < 6; face++) - { - for (int level = 1; level <= q; level++) - { - if (mImageArray[face][level]->getInternalFormat() != mImageArray[0][0]->getInternalFormat()) - { - return false; - } - - if (mImageArray[face][level]->getWidth() != std::max(1, size >> level)) - { - return false; - } - } - } +rx::TextureStorageInterface *Texture3D::getNativeTexture() +{ + return mTexture->getNativeTexture(); +} - return true; +void Texture3D::setUsage(GLenum usage) +{ + mUsage = usage; + mTexture->setUsage(usage); } -bool TextureCubeMap::isCompressed(GLenum target, GLint level) const +bool Texture3D::hasDirtyImages() const { - return IsCompressed(getInternalFormat(target, level)); + return mTexture->hasDirtyImages(); } -// Constructs a native texture resource from the texture images, or returns an existing one -void TextureCubeMap::createTexture() +void Texture3D::resetDirty() { - GLsizei size = mImageArray[0][0]->getWidth(); + mTexture->resetDirty(); +} - if (!(size > 0)) - return; // do not attempt to create native textures for nonexistant data +GLsizei Texture3D::getWidth(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level)->getWidth() : 0; +} - GLint levels = creationLevels(size); - GLenum internalformat = mImageArray[0][0]->getInternalFormat(); +GLsizei Texture3D::getHeight(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level)->getHeight() : 0; +} - delete mTexStorage; - mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size); +GLsizei Texture3D::getDepth(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level)->getDepth() : 0; +} - if (mTexStorage->isManaged()) - { - int levels = levelCount(); - - for (int face = 0; face < 6; face++) - { - for (int level = 0; level < levels; level++) - { - mImageArray[face][level]->setManagedSurface(mTexStorage, face, level); - } - } - } +GLenum Texture3D::getInternalFormat(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level)->getInternalFormat() : GL_NONE; +} - mDirtyImages = true; +GLenum Texture3D::getActualFormat(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level)->getActualFormat() : GL_NONE; } -void TextureCubeMap::updateTexture() +bool Texture3D::isCompressed(GLint level) const { - bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete(); + return IsFormatCompressed(getInternalFormat(level)); +} - for (int face = 0; face < 6; face++) - { - int levels = (mipmapping ? levelCount() : 1); +bool Texture3D::isDepth(GLint level) const +{ + return GetDepthBits(getInternalFormat(level)) > 0; +} - for (int level = 0; level < levels; level++) - { - rx::Image *image = mImageArray[face][level]; +void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +{ + mTexture->setImage(level, width, height, depth, internalFormat, format, type, unpack, pixels); +} - if (image->isDirty()) - { - commitRect(face, level, 0, 0, image->getWidth(), image->getHeight()); - } - } - } +void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +{ + mTexture->setCompressedImage(level, format, width, height, depth, imageSize, pixels); } -void TextureCubeMap::convertToRenderTarget() +void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - rx::TextureStorageInterfaceCube *newTexStorage = NULL; + mTexture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); +} - if (mImageArray[0][0]->getWidth() != 0) - { - GLsizei size = mImageArray[0][0]->getWidth(); - GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size); - GLenum internalformat = mImageArray[0][0]->getInternalFormat(); - - newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size); - - if (mTexStorage != NULL) - { - if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage)) - { - delete newTexStorage; - return gl::error(GL_OUT_OF_MEMORY); - } - } - } +void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) +{ + mTexture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels); +} - delete mTexStorage; - mTexStorage = newTexStorage; +void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +{ + mImmutable = true; - mDirtyImages = true; + mTexture->storage(levels, internalformat, width, height, depth); } -void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +void Texture3D::generateMipmaps() { - GLint internalformat = ConvertSizedInternalFormat(format, type); - redefineImage(faceIndex, level, internalformat, width, height); + mTexture->generateMipmaps(); +} - Texture::setImage(unpackAlignment, pixels, mImageArray[faceIndex][level]); +const rx::Image *Texture3D::getBaseLevelImage() const +{ + return mTexture->getImage(0); } -unsigned int TextureCubeMap::faceIndex(GLenum face) +void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1); - META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2); - META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3); - META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4); - META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5); + mTexture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); +} - return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X; +bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const +{ + return mTexture->isSamplerComplete(samplerState); } -void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height) +bool Texture3D::isMipmapComplete() const { - // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level); - const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level); - const int storageFormat = mImageArray[0][0]->getInternalFormat(); + return mTexture->isMipmapComplete(); +} - mImageArray[face][level]->redefine(mRenderer, internalformat, width, height, false); +unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer) +{ + return mTexture->getRenderTargetSerial(level, layer); +} - if (mTexStorage) - { - const int storageLevels = mTexStorage->levelCount(); - - if ((level >= storageLevels && storageLevels != 0) || - width != storageWidth || - height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage - { - for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - for (int f = 0; f < 6; f++) - { - mImageArray[f][i]->markDirty(); - } - } - - delete mTexStorage; - mTexStorage = NULL; - - mDirtyImages = true; - } - } +rx::RenderTarget *Texture3D::getRenderTarget(GLint level) +{ + return mTexture->getRenderTarget(level); } -void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer) { - unsigned int faceindex = faceIndex(target); - GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE); - redefineImage(faceindex, level, internalformat, width, height); + return mTexture->getRenderTarget(level, layer); +} - if (!mImageArray[faceindex][level]->isRenderableFormat()) - { - mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source); - mDirtyImages = true; - } - else - { - if (!mTexStorage || !mTexStorage->isRenderTarget()) - { - convertToRenderTarget(); - } - - mImageArray[faceindex][level]->markClean(); - - ASSERT(width == height); - - if (width > 0 && level < levelCount()) - { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level); - } - } +rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer) +{ + return mTexture->getDepthStencil(level, layer); } -void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +Texture2DArray::Texture2DArray(rx::Texture2DArrayImpl *impl, GLuint id) + : Texture(id, GL_TEXTURE_2D_ARRAY), + mTexture(impl) { - GLsizei size = mImageArray[faceIndex(target)][level]->getWidth(); +} - if (xoffset + width > size || yoffset + height > size) - { - return gl::error(GL_INVALID_VALUE); - } +Texture2DArray::~Texture2DArray() +{ + SafeDelete(mTexture); +} - unsigned int faceindex = faceIndex(target); +rx::TextureStorageInterface *Texture2DArray::getNativeTexture() +{ + return mTexture->getNativeTexture(); +} - if (!mImageArray[faceindex][level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) - { - mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source); - mDirtyImages = true; - } - else - { - if (!mTexStorage || !mTexStorage->isRenderTarget()) - { - convertToRenderTarget(); - } - - updateTexture(); - - if (level < levelCount()) - { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(mImageArray[0][0]->getInternalFormat()), - xoffset, yoffset, mTexStorage, target, level); - } - } +void Texture2DArray::setUsage(GLenum usage) +{ + mUsage = usage; + mTexture->setUsage(usage); } -void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) +bool Texture2DArray::hasDirtyImages() const { - delete mTexStorage; - mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size); - mImmutable = true; + return mTexture->hasDirtyImages(); +} - for (int level = 0; level < levels; level++) - { - GLsizei mipSize = std::max(1, size >> level); - for (int face = 0; face < 6; face++) - { - mImageArray[face][level]->redefine(mRenderer, internalformat, mipSize, mipSize, true); - } - } +void Texture2DArray::resetDirty() +{ + mTexture->resetDirty(); +} - for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - for (int face = 0; face < 6; face++) - { - mImageArray[face][level]->redefine(mRenderer, GL_NONE, 0, 0, true); - } - } +GLsizei Texture2DArray::getWidth(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getWidth() : 0; +} - if (mTexStorage->isManaged()) - { - int levels = levelCount(); - - for (int face = 0; face < 6; face++) - { - for (int level = 0; level < levels; level++) - { - mImageArray[face][level]->setManagedSurface(mTexStorage, face, level); - } - } - } +GLsizei Texture2DArray::getHeight(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getHeight() : 0; } -void TextureCubeMap::generateMipmaps() +GLsizei Texture2DArray::getLayers(GLint level) const { - if (!isCubeComplete()) - { - return gl::error(GL_INVALID_OPERATION); - } + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getLayerCount(level) : 0; +} - if (!mRenderer->getNonPower2TextureSupport()) - { - if (!isPow2(mImageArray[0][0]->getWidth())) - { - return gl::error(GL_INVALID_OPERATION); - } - } +GLenum Texture2DArray::getInternalFormat(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getInternalFormat() : GL_NONE; +} - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - unsigned int q = log2(mImageArray[0][0]->getWidth()); - for (unsigned int f = 0; f < 6; f++) - { - for (unsigned int i = 1; i <= q; i++) - { - redefineImage(f, i, mImageArray[f][0]->getInternalFormat(), - std::max(mImageArray[f][0]->getWidth() >> i, 1), - std::max(mImageArray[f][0]->getWidth() >> i, 1)); - } - } +GLenum Texture2DArray::getActualFormat(GLint level) const +{ + return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getActualFormat() : GL_NONE; +} - if (mTexStorage && mTexStorage->isRenderTarget()) - { - for (unsigned int f = 0; f < 6; f++) - { - for (unsigned int i = 1; i <= q; i++) - { - mTexStorage->generateMipmap(f, i); - - mImageArray[f][i]->markClean(); - } - } - } - else - { - for (unsigned int f = 0; f < 6; f++) - { - for (unsigned int i = 1; i <= q; i++) - { - mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]); - } - } - } +bool Texture2DArray::isCompressed(GLint level) const +{ + return IsFormatCompressed(getInternalFormat(level)); } -Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target) +bool Texture2DArray::isDepth(GLint level) const { - if (!IsCubemapTextureTarget(target)) - { - return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); - } + return GetDepthBits(getInternalFormat(level)) > 0; +} - unsigned int face = faceIndex(target); +void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +{ + mTexture->setImage(level, width, height, depth, internalFormat, format, type, unpack, pixels); +} - if (mFaceProxies[face] == NULL) - { - mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target)); - } +void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +{ + mTexture->setCompressedImage(level, format, width, height, depth, imageSize, pixels); +} - return mFaceProxies[face]; +void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +{ + mTexture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); } -rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target) +void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) { - ASSERT(IsCubemapTextureTarget(target)); + mTexture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels); +} - // ensure the underlying texture is created - if (getStorage(true) == NULL) - { - return NULL; - } +void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +{ + mImmutable = true; - updateTexture(); - - return mTexStorage->getRenderTarget(target); + mTexture->storage(levels, internalformat, width, height, depth); } -int TextureCubeMap::levelCount() +void Texture2DArray::generateMipmaps() { - return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0; + mTexture->generateMipmaps(); } -rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget) +const rx::Image *Texture2DArray::getBaseLevelImage() const { - if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) - { - if (renderTarget) - { - convertToRenderTarget(); - } - else - { - createTexture(); - } - } + return (mTexture->getLayerCount(0) > 0 ? mTexture->getImage(0, 0) : NULL); +} + +void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + mTexture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); +} - return mTexStorage; +bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const +{ + return mTexture->isSamplerComplete(samplerState); +} + +bool Texture2DArray::isMipmapComplete() const +{ + return mTexture->isMipmapComplete(); +} + +unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer) +{ + return mTexture->getRenderTargetSerial(level, layer); +} + +rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer) +{ + return mTexture->getRenderTarget(level, layer); +} + +rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer) +{ + return mTexture->getDepthStencil(level, layer); } } diff --git a/src/3rdparty/angle/src/libGLESv2/Texture.h b/src/3rdparty/angle/src/libGLESv2/Texture.h index 4f5fab28d0..29f952f9f6 100644 --- a/src/3rdparty/angle/src/libGLESv2/Texture.h +++ b/src/3rdparty/angle/src/libGLESv2/Texture.h @@ -13,12 +13,12 @@ #include <vector> -#define GL_APICALL -#include <GLES2/gl2.h> +#include "angle_gl.h" #include "common/debug.h" #include "common/RefCountObject.h" #include "libGLESv2/angletypes.h" +#include "libGLESv2/constants.h" namespace egl { @@ -27,10 +27,11 @@ class Surface; namespace rx { -class Renderer; +class Texture2DImpl; +class TextureCubeImpl; +class Texture3DImpl; +class Texture2DArrayImpl; class TextureStorageInterface; -class TextureStorageInterface2D; -class TextureStorageInterfaceCube; class RenderTarget; class Image; } @@ -38,108 +39,72 @@ class Image; namespace gl { class Framebuffer; -class Renderbuffer; - -enum -{ - // These are the maximums the implementation can support - // The actual GL caps are limited by the device caps - // and should be queried from the Context - IMPLEMENTATION_MAX_TEXTURE_SIZE = 16384, - IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384, - - IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE -}; +class FramebufferAttachment; class Texture : public RefCountObject { public: - Texture(rx::Renderer *renderer, GLuint id); + Texture(GLuint id, GLenum target); virtual ~Texture(); - virtual void addProxyRef(const Renderbuffer *proxy) = 0; - virtual void releaseProxy(const Renderbuffer *proxy) = 0; - - virtual GLenum getTarget() const = 0; - - bool setMinFilter(GLenum filter); - bool setMagFilter(GLenum filter); - bool setWrapS(GLenum wrap); - bool setWrapT(GLenum wrap); - bool setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy); - bool setUsage(GLenum usage); - - GLenum getMinFilter() const; - GLenum getMagFilter() const; - GLenum getWrapS() const; - GLenum getWrapT() const; - float getMaxAnisotropy() const; - int getLodOffset(); - void getSamplerState(SamplerState *sampler); + GLenum getTarget() const; + + const SamplerState &getSamplerState() const { return mSamplerState; } + SamplerState &getSamplerState() { return mSamplerState; } + void getSamplerStateWithNativeOffset(SamplerState *sampler); + + virtual void setUsage(GLenum usage); GLenum getUsage() const; - bool isMipmapFiltered() const; - virtual bool isSamplerComplete() const = 0; + GLint getBaseLevelWidth() const; + GLint getBaseLevelHeight() const; + GLint getBaseLevelDepth() const; + GLenum getBaseLevelInternalFormat() const; + + virtual bool isSamplerComplete(const SamplerState &samplerState) const = 0; - rx::TextureStorageInterface *getNativeTexture(); - virtual Renderbuffer *getRenderbuffer(GLenum target) = 0; + virtual rx::TextureStorageInterface *getNativeTexture() = 0; virtual void generateMipmaps() = 0; - virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0; + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0; - bool hasDirtyParameters() const; - bool hasDirtyImages() const; - void resetDirty(); + virtual bool hasDirtyImages() const = 0; + virtual void resetDirty() = 0; unsigned int getTextureSerial(); - unsigned int getRenderTargetSerial(GLenum target); bool isImmutable() const; + int immutableLevelCount(); static const GLuint INCOMPLETE_TEXTURE_ID = static_cast<GLuint>(-1); // Every texture takes an id at creation time. The value is arbitrary because it is never registered with the resource manager. protected: - void setImage(GLint unpackAlignment, const void *pixels, rx::Image *image); - bool subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image); - void setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image); - bool subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image); - - GLint creationLevels(GLsizei width, GLsizei height) const; - GLint creationLevels(GLsizei size) const; - - virtual void createTexture() = 0; - virtual void updateTexture() = 0; - virtual void convertToRenderTarget() = 0; - virtual rx::RenderTarget *getRenderTarget(GLenum target) = 0; - - virtual int levelCount() = 0; - - rx::Renderer *mRenderer; + int mipLevels() const; SamplerState mSamplerState; GLenum mUsage; - bool mDirtyImages; - bool mImmutable; + GLenum mTarget; + private: DISALLOW_COPY_AND_ASSIGN(Texture); - virtual rx::TextureStorageInterface *getStorage(bool renderTarget) = 0; + virtual const rx::Image *getBaseLevelImage() const = 0; }; class Texture2D : public Texture { public: - Texture2D(rx::Renderer *renderer, GLuint id); + Texture2D(rx::Texture2DImpl *impl, GLuint id); ~Texture2D(); - void addProxyRef(const Renderbuffer *proxy); - void releaseProxy(const Renderbuffer *proxy); - - virtual GLenum getTarget() const; + virtual rx::TextureStorageInterface *getNativeTexture(); + virtual void setUsage(GLenum usage); + virtual bool hasDirtyImages() const; + virtual void resetDirty(); GLsizei getWidth(GLint level) const; GLsizei getHeight(GLint level) const; @@ -148,128 +113,187 @@ class Texture2D : public Texture bool isCompressed(GLint level) const; bool isDepth(GLint level) const; - void setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); - void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); - virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); - virtual bool isSamplerComplete() const; + virtual bool isSamplerComplete(const SamplerState &samplerState) const; virtual void bindTexImage(egl::Surface *surface); virtual void releaseTexImage(); virtual void generateMipmaps(); - virtual Renderbuffer *getRenderbuffer(GLenum target); + unsigned int getRenderTargetSerial(GLint level); protected: - friend class RenderbufferTexture2D; - virtual rx::RenderTarget *getRenderTarget(GLenum target); - virtual rx::RenderTarget *getDepthStencil(GLenum target); - virtual int levelCount(); + friend class Texture2DAttachment; + rx::RenderTarget *getRenderTarget(GLint level); + rx::RenderTarget *getDepthSencil(GLint level); private: DISALLOW_COPY_AND_ASSIGN(Texture2D); - virtual void createTexture(); - virtual void updateTexture(); - virtual void convertToRenderTarget(); - virtual rx::TextureStorageInterface *getStorage(bool renderTarget); - - bool isMipmapComplete() const; + virtual const rx::Image *getBaseLevelImage() const; - void redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height); - void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height); - rx::Image *mImageArray[IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - rx::TextureStorageInterface2D *mTexStorage; + rx::Texture2DImpl *mTexture; egl::Surface *mSurface; - - // A specific internal reference count is kept for colorbuffer proxy references, - // because, as the renderbuffer acting as proxy will maintain a binding pointer - // back to this texture, there would be a circular reference if we used a binding - // pointer here. This reference count will cause the pointer to be set to NULL if - // the count drops to zero, but will not cause deletion of the Renderbuffer. - Renderbuffer *mColorbufferProxy; - unsigned int mProxyRefs; }; class TextureCubeMap : public Texture { public: - TextureCubeMap(rx::Renderer *renderer, GLuint id); + TextureCubeMap(rx::TextureCubeImpl *impl, GLuint id); ~TextureCubeMap(); - void addProxyRef(const Renderbuffer *proxy); - void releaseProxy(const Renderbuffer *proxy); + virtual rx::TextureStorageInterface *getNativeTexture(); + virtual void setUsage(GLenum usage); + virtual bool hasDirtyImages() const; + virtual void resetDirty(); - virtual GLenum getTarget() const; - GLsizei getWidth(GLenum target, GLint level) const; GLsizei getHeight(GLenum target, GLint level) const; GLenum getInternalFormat(GLenum target, GLint level) const; GLenum getActualFormat(GLenum target, GLint level) const; bool isCompressed(GLenum target, GLint level) const; + bool isDepth(GLenum target, GLint level) const; - void setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + void setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + void setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + void setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + void setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + void setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); + void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); - void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); - virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); void storage(GLsizei levels, GLenum internalformat, GLsizei size); - virtual bool isSamplerComplete() const; + virtual bool isSamplerComplete(const SamplerState &samplerState) const; + bool isCubeComplete() const; virtual void generateMipmaps(); - virtual Renderbuffer *getRenderbuffer(GLenum target); - - static unsigned int faceIndex(GLenum face); + unsigned int getRenderTargetSerial(GLenum target, GLint level); protected: - friend class RenderbufferTextureCubeMap; - virtual rx::RenderTarget *getRenderTarget(GLenum target); - virtual int levelCount(); + friend class TextureCubeMapAttachment; + rx::RenderTarget *getRenderTarget(GLenum target, GLint level); + rx::RenderTarget *getDepthStencil(GLenum target, GLint level); private: DISALLOW_COPY_AND_ASSIGN(TextureCubeMap); - virtual void createTexture(); - virtual void updateTexture(); - virtual void convertToRenderTarget(); - virtual rx::TextureStorageInterface *getStorage(bool renderTarget); + virtual const rx::Image *getBaseLevelImage() const; - bool isCubeComplete() const; - bool isMipmapCubeComplete() const; + rx::TextureCubeImpl *mTexture; +}; + +class Texture3D : public Texture +{ + public: + Texture3D(rx::Texture3DImpl *impl, GLuint id); + + ~Texture3D(); - void setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - void redefineImage(int faceIndex, GLint level, GLint internalformat, GLsizei width, GLsizei height); + virtual rx::TextureStorageInterface *getNativeTexture(); + virtual void setUsage(GLenum usage); + virtual bool hasDirtyImages() const; + virtual void resetDirty(); - rx::Image *mImageArray[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLsizei getDepth(GLint level) const; + GLenum getInternalFormat(GLint level) const; + GLenum getActualFormat(GLint level) const; + bool isCompressed(GLint level) const; + bool isDepth(GLint level) const; - rx::TextureStorageInterfaceCube *mTexStorage; + void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels); + void subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels); + void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + + virtual void generateMipmaps(); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); - // A specific internal reference count is kept for colorbuffer proxy references, - // because, as the renderbuffer acting as proxy will maintain a binding pointer - // back to this texture, there would be a circular reference if we used a binding - // pointer here. This reference count will cause the pointer to be set to NULL if - // the count drops to zero, but will not cause deletion of the Renderbuffer. - Renderbuffer *mFaceProxies[6]; - unsigned int *mFaceProxyRefs[6]; + virtual bool isSamplerComplete(const SamplerState &samplerState) const; + virtual bool isMipmapComplete() const; + + unsigned int getRenderTargetSerial(GLint level, GLint layer); + + protected: + friend class Texture3DAttachment; + rx::RenderTarget *getRenderTarget(GLint level); + rx::RenderTarget *getRenderTarget(GLint level, GLint layer); + rx::RenderTarget *getDepthStencil(GLint level, GLint layer); + + private: + DISALLOW_COPY_AND_ASSIGN(Texture3D); + + virtual const rx::Image *getBaseLevelImage() const; + + rx::Texture3DImpl *mTexture; +}; + +class Texture2DArray : public Texture +{ + public: + Texture2DArray(rx::Texture2DArrayImpl *impl, GLuint id); + + ~Texture2DArray(); + + virtual rx::TextureStorageInterface *getNativeTexture(); + virtual void setUsage(GLenum usage); + virtual bool hasDirtyImages() const; + virtual void resetDirty(); + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLsizei getLayers(GLint level) const; + GLenum getInternalFormat(GLint level) const; + GLenum getActualFormat(GLint level) const; + bool isCompressed(GLint level) const; + bool isDepth(GLint level) const; + + void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels); + void subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels); + void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + + virtual void generateMipmaps(); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + + virtual bool isSamplerComplete(const SamplerState &samplerState) const; + virtual bool isMipmapComplete() const; + + unsigned int getRenderTargetSerial(GLint level, GLint layer); + + protected: + friend class Texture2DArrayAttachment; + rx::RenderTarget *getRenderTarget(GLint level, GLint layer); + rx::RenderTarget *getDepthStencil(GLint level, GLint layer); + + private: + DISALLOW_COPY_AND_ASSIGN(Texture2DArray); + + virtual const rx::Image *getBaseLevelImage() const; + + rx::Texture2DArrayImpl *mTexture; }; + } #endif // LIBGLESV2_TEXTURE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/TransformFeedback.cpp b/src/3rdparty/angle/src/libGLESv2/TransformFeedback.cpp new file mode 100644 index 0000000000..79ce08405d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/TransformFeedback.cpp @@ -0,0 +1,63 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "libGLESv2/TransformFeedback.h" + +namespace gl +{ + +TransformFeedback::TransformFeedback(GLuint id) + : RefCountObject(id), + mStarted(GL_FALSE), + mPrimitiveMode(GL_NONE), + mPaused(GL_FALSE) +{ +} + +TransformFeedback::~TransformFeedback() +{ +} + +void TransformFeedback::start(GLenum primitiveMode) +{ + mStarted = GL_TRUE; + mPrimitiveMode = primitiveMode; + mPaused = GL_FALSE; +} + +void TransformFeedback::stop() +{ + mStarted = GL_FALSE; + mPrimitiveMode = GL_NONE; + mPaused = GL_FALSE; +} + +GLboolean TransformFeedback::isStarted() const +{ + return mStarted; +} + +GLenum TransformFeedback::getDrawMode() const +{ + return mPrimitiveMode; +} + +void TransformFeedback::pause() +{ + mPaused = GL_TRUE; +} + +void TransformFeedback::resume() +{ + mPaused = GL_FALSE; +} + +GLboolean TransformFeedback::isPaused() const +{ + return mPaused; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/TransformFeedback.h b/src/3rdparty/angle/src/libGLESv2/TransformFeedback.h new file mode 100644 index 0000000000..d6f4522e2a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/TransformFeedback.h @@ -0,0 +1,44 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef LIBGLESV2_TRANSFORM_FEEDBACK_H_ +#define LIBGLESV2_TRANSFORM_FEEDBACK_H_ + +#include "common/angleutils.h" +#include "common/RefCountObject.h" + +#include "angle_gl.h" + +namespace gl +{ + +class TransformFeedback : public RefCountObject +{ + public: + explicit TransformFeedback(GLuint id); + virtual ~TransformFeedback(); + + void start(GLenum primitiveMode); + void stop(); + GLboolean isStarted() const; + + GLenum getDrawMode() const; + + void pause(); + void resume(); + GLboolean isPaused() const; + + private: + DISALLOW_COPY_AND_ASSIGN(TransformFeedback); + + GLboolean mStarted; + GLenum mPrimitiveMode; + GLboolean mPaused; +}; + +} + +#endif // LIBGLESV2_TRANSFORM_FEEDBACK_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Uniform.cpp b/src/3rdparty/angle/src/libGLESv2/Uniform.cpp index 5424e271b5..cddc7ec7d0 100644 --- a/src/3rdparty/angle/src/libGLESv2/Uniform.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Uniform.cpp @@ -7,37 +7,100 @@ #include "libGLESv2/Uniform.h" -#include "libGLESv2/utilities.h" +#include "common/utilities.h" namespace gl { -Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize) - : type(type), precision(precision), name(name), arraySize(arraySize) +LinkedUniform::LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, + const int blockIndex, const sh::BlockMemberInfo &blockInfo) + : type(type), + precision(precision), + name(name), + arraySize(arraySize), + blockIndex(blockIndex), + blockInfo(blockInfo), + data(NULL), + dirty(true), + psRegisterIndex(GL_INVALID_INDEX), + vsRegisterIndex(GL_INVALID_INDEX), + registerCount(0), + registerElement(0) { - int bytes = gl::UniformInternalSize(type) * elementCount(); - data = new unsigned char[bytes]; - memset(data, 0, bytes); - dirty = true; - - psRegisterIndex = -1; - vsRegisterIndex = -1; - registerCount = VariableRowCount(type) * elementCount(); + // We use data storage for default block uniforms to cache values that are sent to D3D during rendering + // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only) + if (isInDefaultBlock()) + { + size_t bytes = dataSize(); + data = new unsigned char[bytes]; + memset(data, 0, bytes); + registerCount = VariableRowCount(type) * elementCount(); + } } -Uniform::~Uniform() +LinkedUniform::~LinkedUniform() { delete[] data; } -bool Uniform::isArray() const +bool LinkedUniform::isArray() const { return arraySize > 0; } -unsigned int Uniform::elementCount() const +unsigned int LinkedUniform::elementCount() const { return arraySize > 0 ? arraySize : 1; } +bool LinkedUniform::isReferencedByVertexShader() const +{ + return vsRegisterIndex != GL_INVALID_INDEX; +} + +bool LinkedUniform::isReferencedByFragmentShader() const +{ + return psRegisterIndex != GL_INVALID_INDEX; +} + +bool LinkedUniform::isInDefaultBlock() const +{ + return blockIndex == -1; +} + +size_t LinkedUniform::dataSize() const +{ + ASSERT(type != GL_STRUCT_ANGLEX); + return VariableInternalSize(type) * elementCount(); +} + +bool LinkedUniform::isSampler() const +{ + return IsSampler(type); +} + +UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize) + : name(name), + elementIndex(elementIndex), + dataSize(dataSize), + psRegisterIndex(GL_INVALID_INDEX), + vsRegisterIndex(GL_INVALID_INDEX) +{ +} + +bool UniformBlock::isArrayElement() const +{ + return elementIndex != GL_INVALID_INDEX; +} + +bool UniformBlock::isReferencedByVertexShader() const +{ + return vsRegisterIndex != GL_INVALID_INDEX; +} + +bool UniformBlock::isReferencedByFragmentShader() const +{ + return psRegisterIndex != GL_INVALID_INDEX; +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/Uniform.h b/src/3rdparty/angle/src/libGLESv2/Uniform.h index 8ab0fbe234..24f834f3c6 100644 --- a/src/3rdparty/angle/src/libGLESv2/Uniform.h +++ b/src/3rdparty/angle/src/libGLESv2/Uniform.h @@ -10,38 +10,69 @@ #include <string> #include <vector> -#define GL_APICALL -#include <GLES2/gl2.h> +#include "angle_gl.h" #include "common/debug.h" +#include "angletypes.h" +#include "common/shadervars.h" +#include "common/blocklayout.h" namespace gl { // Helper struct representing a single shader uniform -struct Uniform +struct LinkedUniform { - Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize); + LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, const int blockIndex, const sh::BlockMemberInfo &blockInfo); - ~Uniform(); + ~LinkedUniform(); bool isArray() const; unsigned int elementCount() const; + bool isReferencedByVertexShader() const; + bool isReferencedByFragmentShader() const; + bool isInDefaultBlock() const; + size_t dataSize() const; + bool isSampler() const; const GLenum type; const GLenum precision; const std::string name; const unsigned int arraySize; + const int blockIndex; + const sh::BlockMemberInfo blockInfo; unsigned char *data; bool dirty; - int psRegisterIndex; - int vsRegisterIndex; + unsigned int psRegisterIndex; + unsigned int vsRegisterIndex; unsigned int registerCount; + + // Register "elements" are used for uniform structs in ES3, to appropriately identify single uniforms + // inside aggregate types, which are packed according C-like structure rules. + unsigned int registerElement; }; -typedef std::vector<Uniform*> UniformArray; +// Helper struct representing a single shader uniform block +struct UniformBlock +{ + // use GL_INVALID_INDEX for non-array elements + UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize); + + bool isArrayElement() const; + bool isReferencedByVertexShader() const; + bool isReferencedByFragmentShader() const; + + const std::string name; + const unsigned int elementIndex; + const unsigned int dataSize; + + std::vector<unsigned int> memberUniformIndexes; + + unsigned int psRegisterIndex; + unsigned int vsRegisterIndex; +}; } diff --git a/src/3rdparty/angle/src/libGLESv2/VertexArray.cpp b/src/3rdparty/angle/src/libGLESv2/VertexArray.cpp new file mode 100644 index 0000000000..120064a532 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/VertexArray.cpp @@ -0,0 +1,97 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Implementation of the state class for mananging GLES 3 Vertex Array Objects. +// + +#include "libGLESv2/VertexArray.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/renderer/VertexArrayImpl.h" + +namespace gl +{ + +VertexArray::VertexArray(rx::VertexArrayImpl *impl, GLuint id, size_t maxAttribs) + : mId(id), + mVertexArray(impl), + mVertexAttributes(maxAttribs) +{ + ASSERT(impl != NULL); +} + +VertexArray::~VertexArray() +{ + SafeDelete(mVertexArray); + + for (size_t i = 0; i < getMaxAttribs(); i++) + { + mVertexAttributes[i].buffer.set(NULL); + } + mElementArrayBuffer.set(NULL); +} + +GLuint VertexArray::id() const +{ + return mId; +} + +void VertexArray::detachBuffer(GLuint bufferName) +{ + for (size_t attribute = 0; attribute < getMaxAttribs(); attribute++) + { + if (mVertexAttributes[attribute].buffer.id() == bufferName) + { + mVertexAttributes[attribute].buffer.set(NULL); + } + } + + if (mElementArrayBuffer.id() == bufferName) + { + mElementArrayBuffer.set(NULL); + } +} + +const VertexAttribute& VertexArray::getVertexAttribute(size_t attributeIndex) const +{ + ASSERT(attributeIndex < getMaxAttribs()); + return mVertexAttributes[attributeIndex]; +} + +void VertexArray::setVertexAttribDivisor(GLuint index, GLuint divisor) +{ + ASSERT(index < getMaxAttribs()); + mVertexAttributes[index].divisor = divisor; + mVertexArray->setAttributeDivisor(index, divisor); +} + +void VertexArray::enableAttribute(unsigned int attributeIndex, bool enabledState) +{ + ASSERT(attributeIndex < getMaxAttribs()); + mVertexAttributes[attributeIndex].enabled = enabledState; + mVertexArray->enableAttribute(attributeIndex, enabledState); +} + +void VertexArray::setAttributeState(unsigned int attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, + bool normalized, bool pureInteger, GLsizei stride, const void *pointer) +{ + ASSERT(attributeIndex < getMaxAttribs()); + mVertexAttributes[attributeIndex].buffer.set(boundBuffer); + mVertexAttributes[attributeIndex].size = size; + mVertexAttributes[attributeIndex].type = type; + mVertexAttributes[attributeIndex].normalized = normalized; + mVertexAttributes[attributeIndex].pureInteger = pureInteger; + mVertexAttributes[attributeIndex].stride = stride; + mVertexAttributes[attributeIndex].pointer = pointer; + mVertexArray->setAttribute(attributeIndex, mVertexAttributes[attributeIndex]); +} + +void VertexArray::setElementArrayBuffer(Buffer *buffer) +{ + mElementArrayBuffer.set(buffer); + mVertexArray->setElementArrayBuffer(buffer); +} + +}
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/VertexArray.h b/src/3rdparty/angle/src/libGLESv2/VertexArray.h new file mode 100644 index 0000000000..accd98731a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/VertexArray.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This class contains prototypes for representing GLES 3 Vertex Array Objects: +// +// The buffer objects that are to be used by the vertex stage of the GL are collected +// together to form a vertex array object. All state related to the definition of data used +// by the vertex processor is encapsulated in a vertex array object. +// + +#ifndef LIBGLESV2_VERTEXARRAY_H_ +#define LIBGLESV2_VERTEXARRAY_H_ + +#include "common/RefCountObject.h" +#include "libGLESv2/constants.h" +#include "libGLESv2/VertexAttribute.h" + +namespace rx +{ +class Renderer; +class VertexArrayImpl; +} + +namespace gl +{ +class Buffer; + +class VertexArray +{ + public: + VertexArray(rx::VertexArrayImpl *impl, GLuint id, size_t maxAttribs); + ~VertexArray(); + + GLuint id() const; + + const VertexAttribute& getVertexAttribute(size_t attributeIndex) const; + void detachBuffer(GLuint bufferName); + void setVertexAttribDivisor(GLuint index, GLuint divisor); + void enableAttribute(unsigned int attributeIndex, bool enabledState); + void setAttributeState(unsigned int attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, + bool normalized, bool pureInteger, GLsizei stride, const void *pointer); + + const VertexAttribute* getVertexAttributes() const { return mVertexAttributes.data(); } + Buffer *getElementArrayBuffer() const { return mElementArrayBuffer.get(); } + void setElementArrayBuffer(Buffer *buffer); + GLuint getElementArrayBufferId() const { return mElementArrayBuffer.id(); } + size_t getMaxAttribs() const { return mVertexAttributes.size(); } + + private: + GLuint mId; + + rx::VertexArrayImpl *mVertexArray; + std::vector<VertexAttribute> mVertexAttributes; + BindingPointer<Buffer> mElementArrayBuffer; +}; + +} + +#endif // LIBGLESV2_VERTEXARRAY_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/VertexAttribute.cpp b/src/3rdparty/angle/src/libGLESv2/VertexAttribute.cpp new file mode 100644 index 0000000000..7d011ef758 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/VertexAttribute.cpp @@ -0,0 +1,56 @@ +#include "precompiled.h" +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Implementation of the state class for mananging GLES 3 Vertex Array Objects. +// + +#include "libGLESv2/VertexAttribute.h" + +namespace gl +{ + +VertexAttribute::VertexAttribute() + : enabled(false), + type(GL_FLOAT), + size(4), + normalized(false), + pureInteger(false), + stride(0), + pointer(NULL), + divisor(0) +{ +} + +size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib) +{ + GLuint size = attrib.size; + switch (attrib.type) + { + case GL_BYTE: return size * sizeof(GLbyte); + case GL_UNSIGNED_BYTE: return size * sizeof(GLubyte); + case GL_SHORT: return size * sizeof(GLshort); + case GL_UNSIGNED_SHORT: return size * sizeof(GLushort); + case GL_INT: return size * sizeof(GLint); + case GL_UNSIGNED_INT: return size * sizeof(GLuint); + case GL_INT_2_10_10_10_REV: return 4; + case GL_UNSIGNED_INT_2_10_10_10_REV: return 4; + case GL_FIXED: return size * sizeof(GLfixed); + case GL_HALF_FLOAT: return size * sizeof(GLhalf); + case GL_FLOAT: return size * sizeof(GLfloat); + default: UNREACHABLE(); return size * sizeof(GLfloat); + } +} + +size_t ComputeVertexAttributeStride(const VertexAttribute& attrib) +{ + if (!attrib.enabled) + { + return 16; + } + return attrib.stride ? attrib.stride : ComputeVertexAttributeTypeSize(attrib); +} + +}
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/VertexAttribute.h b/src/3rdparty/angle/src/libGLESv2/VertexAttribute.h new file mode 100644 index 0000000000..e9757b618b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/VertexAttribute.h @@ -0,0 +1,119 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Helper structure describing a single vertex attribute +// + +#ifndef LIBGLESV2_VERTEXATTRIBUTE_H_ +#define LIBGLESV2_VERTEXATTRIBUTE_H_ + +#include "libGLESv2/Buffer.h" + +namespace gl +{ + +struct VertexAttribute +{ + bool enabled; // From glEnable/DisableVertexAttribArray + + GLenum type; + GLuint size; + bool normalized; + bool pureInteger; + GLuint stride; // 0 means natural stride + + union + { + const GLvoid *pointer; + GLintptr offset; + }; + BindingPointer<Buffer> buffer; // Captured when glVertexAttribPointer is called. + + GLuint divisor; + + VertexAttribute(); +}; + +template <typename T> +T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pname) +{ + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + return static_cast<T>(attrib.enabled ? GL_TRUE : GL_FALSE); + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + return static_cast<T>(attrib.size); + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + return static_cast<T>(attrib.stride); + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + return static_cast<T>(attrib.type); + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + return static_cast<T>(attrib.normalized ? GL_TRUE : GL_FALSE); + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + return static_cast<T>(attrib.buffer.id()); + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + return static_cast<T>(attrib.divisor); + case GL_VERTEX_ATTRIB_ARRAY_INTEGER: + return static_cast<T>(attrib.pureInteger ? GL_TRUE : GL_FALSE); + default: + UNREACHABLE(); + return static_cast<T>(0); + } +} + +size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib); +size_t ComputeVertexAttributeStride(const VertexAttribute& attrib); + +struct VertexAttribCurrentValueData +{ + union + { + GLfloat FloatValues[4]; + GLint IntValues[4]; + GLuint UnsignedIntValues[4]; + }; + GLenum Type; + + void setFloatValues(const GLfloat floatValues[4]) + { + for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) + { + FloatValues[valueIndex] = floatValues[valueIndex]; + } + Type = GL_FLOAT; + } + + void setIntValues(const GLint intValues[4]) + { + for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) + { + IntValues[valueIndex] = intValues[valueIndex]; + } + Type = GL_INT; + } + + void setUnsignedIntValues(const GLuint unsignedIntValues[4]) + { + for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) + { + UnsignedIntValues[valueIndex] = unsignedIntValues[valueIndex]; + } + Type = GL_UNSIGNED_INT; + } + + bool operator==(const VertexAttribCurrentValueData &other) + { + return (Type == other.Type && memcmp(FloatValues, other.FloatValues, sizeof(float) * 4) == 0); + } + + bool operator!=(const VertexAttribCurrentValueData &other) + { + return !(*this == other); + } +}; + +} + +#endif // LIBGLESV2_VERTEXATTRIBUTE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/angletypes.cpp b/src/3rdparty/angle/src/libGLESv2/angletypes.cpp new file mode 100644 index 0000000000..bc929c7d0c --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/angletypes.cpp @@ -0,0 +1,196 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2 + +#include "libGLESv2/angletypes.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/VertexAttribute.h" + +namespace gl +{ + +SamplerState::SamplerState() + : minFilter(GL_NEAREST_MIPMAP_LINEAR), + magFilter(GL_LINEAR), + wrapS(GL_REPEAT), + wrapT(GL_REPEAT), + wrapR(GL_REPEAT), + maxAnisotropy(1.0f), + baseLevel(0), + maxLevel(1000), + minLod(-FLT_MAX), + maxLod(FLT_MAX), + compareMode(GL_NONE), + compareFunc(GL_LEQUAL), + swizzleRed(GL_RED), + swizzleGreen(GL_GREEN), + swizzleBlue(GL_BLUE), + swizzleAlpha(GL_ALPHA) +{} + +bool SamplerState::swizzleRequired() const +{ + return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || + swizzleBlue != GL_BLUE || swizzleAlpha != GL_ALPHA; +} + +static void MinMax(int a, int b, int *minimum, int *maximum) +{ + if (a < b) + { + *minimum = a; + *maximum = b; + } + else + { + *minimum = b; + *maximum = a; + } +} + +bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection) +{ + int minSourceX, maxSourceX, minSourceY, maxSourceY; + MinMax(source.x, source.x + source.width, &minSourceX, &maxSourceX); + MinMax(source.y, source.y + source.height, &minSourceY, &maxSourceY); + + int minClipX, maxClipX, minClipY, maxClipY; + MinMax(clip.x, clip.x + clip.width, &minClipX, &maxClipX); + MinMax(clip.y, clip.y + clip.height, &minClipY, &maxClipY); + + if (minSourceX >= maxClipX || maxSourceX <= minClipX || minSourceY >= maxClipY || maxSourceY <= minClipY) + { + if (intersection) + { + intersection->x = minSourceX; + intersection->y = maxSourceY; + intersection->width = maxSourceX - minSourceX; + intersection->height = maxSourceY - minSourceY; + } + + return false; + } + else + { + if (intersection) + { + intersection->x = std::max(minSourceX, minClipX); + intersection->y = std::max(minSourceY, minClipY); + intersection->width = std::min(maxSourceX, maxClipX) - std::max(minSourceX, minClipX); + intersection->height = std::min(maxSourceY, maxClipY) - std::max(minSourceY, minClipY); + } + + return true; + } +} + +VertexFormat::VertexFormat() + : mType(GL_NONE), + mNormalized(GL_FALSE), + mComponents(0), + mPureInteger(false) +{} + +VertexFormat::VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger) + : mType(type), + mNormalized(normalized), + mComponents(components), + mPureInteger(pureInteger) +{ + // Float data can not be normalized, so ignore the user setting + if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) + { + mNormalized = GL_FALSE; + } +} + +VertexFormat::VertexFormat(const VertexAttribute &attrib) + : mType(attrib.type), + mNormalized(attrib.normalized ? GL_TRUE : GL_FALSE), + mComponents(attrib.size), + mPureInteger(attrib.pureInteger) +{ + // Ensure we aren't initializing a vertex format which should be using + // the current-value type + ASSERT(attrib.enabled); + + // Float data can not be normalized, so ignore the user setting + if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) + { + mNormalized = GL_FALSE; + } +} + +VertexFormat::VertexFormat(const VertexAttribute &attrib, GLenum currentValueType) + : mType(attrib.type), + mNormalized(attrib.normalized ? GL_TRUE : GL_FALSE), + mComponents(attrib.size), + mPureInteger(attrib.pureInteger) +{ + if (!attrib.enabled) + { + mType = currentValueType; + mNormalized = GL_FALSE; + mComponents = 4; + mPureInteger = (currentValueType != GL_FLOAT); + } + + // Float data can not be normalized, so ignore the user setting + if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) + { + mNormalized = GL_FALSE; + } +} + +void VertexFormat::GetInputLayout(VertexFormat *inputLayout, + ProgramBinary *programBinary, + const VertexAttribute *attributes, + const gl::VertexAttribCurrentValueData *currentValues) +{ + for (unsigned int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + int semanticIndex = programBinary->getSemanticIndex(attributeIndex); + + if (semanticIndex != -1) + { + inputLayout[semanticIndex] = VertexFormat(attributes[attributeIndex], currentValues[attributeIndex].Type); + } + } +} + +bool VertexFormat::operator==(const VertexFormat &other) const +{ + return (mType == other.mType && + mComponents == other.mComponents && + mNormalized == other.mNormalized && + mPureInteger == other.mPureInteger ); +} + +bool VertexFormat::operator!=(const VertexFormat &other) const +{ + return !(*this == other); +} + +bool VertexFormat::operator<(const VertexFormat& other) const +{ + if (mType != other.mType) + { + return mType < other.mType; + } + if (mNormalized != other.mNormalized) + { + return mNormalized < other.mNormalized; + } + if (mComponents != other.mComponents) + { + return mComponents < other.mComponents; + } + return mPureInteger < other.mPureInteger; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/angletypes.h b/src/3rdparty/angle/src/libGLESv2/angletypes.h index b2f0cad265..79ad810e9e 100644 --- a/src/3rdparty/angle/src/libGLESv2/angletypes.h +++ b/src/3rdparty/angle/src/libGLESv2/angletypes.h @@ -9,13 +9,22 @@ #ifndef LIBGLESV2_ANGLETYPES_H_ #define LIBGLESV2_ANGLETYPES_H_ +#include "libGLESv2/constants.h" +#include "common/RefCountObject.h" + namespace gl { +class Buffer; +class ProgramBinary; +struct VertexAttribute; +struct VertexAttribCurrentValueData; enum TextureType { TEXTURE_2D, TEXTURE_CUBE, + TEXTURE_3D, + TEXTURE_2D_ARRAY, TEXTURE_TYPE_COUNT, TEXTURE_UNKNOWN @@ -27,20 +36,56 @@ enum SamplerType SAMPLER_VERTEX }; +template <typename T> struct Color { - float red; - float green; - float blue; - float alpha; + T red; + T green; + T blue; + T alpha; + + Color() : red(0), green(0), blue(0), alpha(0) { } + Color(T r, T g, T b, T a) : red(r), green(g), blue(b), alpha(a) { } }; +typedef Color<float> ColorF; +typedef Color<int> ColorI; +typedef Color<unsigned int> ColorUI; + struct Rectangle { int x; int y; int width; int height; + + Rectangle() : x(0), y(0), width(0), height(0) { } + Rectangle(int x_in, int y_in, int width_in, int height_in) : x(x_in), y(y_in), width(width_in), height(height_in) { } +}; + +bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection); + +struct Box +{ + int x; + int y; + int z; + int width; + int height; + int depth; + + Box() : x(0), y(0), z(0), width(0), height(0), depth(0) { } + Box(int x_in, int y_in, int z_in, int width_in, int height_in, int depth_in) : x(x_in), y(y_in), z(z_in), width(width_in), height(height_in), depth(depth_in) { } +}; + +struct Extents +{ + int width; + int height; + int depth; + + Extents() : width(0), height(0), depth(0) { } + Extents(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) { } }; struct RasterizerState @@ -55,6 +100,8 @@ struct RasterizerState bool pointDrawMode; bool multiSample; + + bool rasterizerDiscard; }; struct BlendState @@ -100,28 +147,125 @@ struct DepthStencilState struct SamplerState { + SamplerState(); + GLenum minFilter; GLenum magFilter; GLenum wrapS; GLenum wrapT; + GLenum wrapR; float maxAnisotropy; - int lodOffset; + + GLint baseLevel; + GLint maxLevel; + GLfloat minLod; + GLfloat maxLod; + + GLenum compareMode; + GLenum compareFunc; + + GLenum swizzleRed; + GLenum swizzleGreen; + GLenum swizzleBlue; + GLenum swizzleAlpha; + + bool swizzleRequired() const; }; struct ClearParameters { - GLbitfield mask; - - Color colorClearValue; + bool clearColor[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; + ColorF colorFClearValue; + ColorI colorIClearValue; + ColorUI colorUIClearValue; + GLenum colorClearType; bool colorMaskRed; bool colorMaskGreen; bool colorMaskBlue; bool colorMaskAlpha; + bool clearDepth; float depthClearValue; + bool clearStencil; GLint stencilClearValue; GLuint stencilWriteMask; + + bool scissorEnabled; + Rectangle scissor; +}; + +struct PixelUnpackState +{ + BindingPointer<Buffer> pixelBuffer; + GLint alignment; + + PixelUnpackState() + : alignment(4) + {} + + explicit PixelUnpackState(GLint alignmentIn) + : alignment(alignmentIn) + {} +}; + +struct PixelPackState +{ + BindingPointer<Buffer> pixelBuffer; + GLint alignment; + bool reverseRowOrder; + + PixelPackState() + : alignment(4), + reverseRowOrder(false) + {} + + explicit PixelPackState(GLint alignmentIn, bool reverseRowOrderIn) + : alignment(alignmentIn), + reverseRowOrder(reverseRowOrderIn) + {} +}; + +struct VertexFormat +{ + GLenum mType; + GLboolean mNormalized; + GLuint mComponents; + bool mPureInteger; + + VertexFormat(); + VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger); + explicit VertexFormat(const VertexAttribute &attribute); + VertexFormat(const VertexAttribute &attribute, GLenum currentValueType); + + static void GetInputLayout(VertexFormat *inputLayout, + ProgramBinary *programBinary, + const VertexAttribute *attributes, + const gl::VertexAttribCurrentValueData *currentValues); + + bool operator==(const VertexFormat &other) const; + bool operator!=(const VertexFormat &other) const; + bool operator<(const VertexFormat& other) const; +}; + +} + +namespace rx +{ + +enum VertexConversionType +{ + VERTEX_CONVERT_NONE = 0, + VERTEX_CONVERT_CPU = 1, + VERTEX_CONVERT_GPU = 2, + VERTEX_CONVERT_BOTH = 3 +}; + +enum D3DWorkaroundType +{ + ANGLE_D3D_WORKAROUND_NONE, + ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION, + ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION }; } diff --git a/src/3rdparty/angle/src/libGLESv2/constants.h b/src/3rdparty/angle/src/libGLESv2/constants.h index 9f24d66a7d..c87f92d497 100644 --- a/src/3rdparty/angle/src/libGLESv2/constants.h +++ b/src/3rdparty/angle/src/libGLESv2/constants.h @@ -22,12 +22,26 @@ enum IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS = MAX_TEXTURE_IMAGE_UNITS + IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS, IMPLEMENTATION_MAX_VARYING_VECTORS = 32, - IMPLEMENTATION_MAX_DRAW_BUFFERS = 8 -}; + IMPLEMENTATION_MAX_DRAW_BUFFERS = 8, + IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS = IMPLEMENTATION_MAX_DRAW_BUFFERS + 2, // 2 extra for depth and/or stencil buffers + + IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS = 16, + IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS = 16, + IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS = IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS + + IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS, + + IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS = 4, -const float ALIASED_LINE_WIDTH_RANGE_MIN = 1.0f; -const float ALIASED_LINE_WIDTH_RANGE_MAX = 1.0f; -const float ALIASED_POINT_SIZE_RANGE_MIN = 1.0f; + // These are the maximums the implementation can support + // The actual GL caps are limited by the device caps + // and should be queried from the Context + IMPLEMENTATION_MAX_2D_TEXTURE_SIZE = 16384, + IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384, + IMPLEMENTATION_MAX_3D_TEXTURE_SIZE = 2048, + IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS = 2048, + + IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE +}; } diff --git a/src/3rdparty/angle/src/libGLESv2/formatutils.cpp b/src/3rdparty/angle/src/libGLESv2/formatutils.cpp new file mode 100644 index 0000000000..8cc2e19a83 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/formatutils.cpp @@ -0,0 +1,1548 @@ +#include "precompiled.h" +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils.cpp: Queries for GL image formats. + +#include "common/mathutil.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/Context.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/imageformats.h" +#include "libGLESv2/renderer/copyimage.h" + +namespace gl +{ + +// ES2 requires that format is equal to internal format at all glTex*Image2D entry points and the implementation +// can decide the true, sized, internal format. The ES2FormatMap determines the internal format for all valid +// format and type combinations. + +struct FormatTypeInfo +{ + GLenum mInternalFormat; + ColorWriteFunction mColorWriteFunction; + + FormatTypeInfo(GLenum internalFormat, ColorWriteFunction writeFunc) + : mInternalFormat(internalFormat), mColorWriteFunction(writeFunc) + { } +}; + +typedef std::pair<GLenum, GLenum> FormatTypePair; +typedef std::pair<FormatTypePair, FormatTypeInfo> FormatPair; +typedef std::map<FormatTypePair, FormatTypeInfo> FormatMap; + +// A helper function to insert data into the format map with fewer characters. +static inline void InsertFormatMapping(FormatMap *map, GLenum format, GLenum type, GLenum internalFormat, ColorWriteFunction writeFunc) +{ + map->insert(FormatPair(FormatTypePair(format, type), FormatTypeInfo(internalFormat, writeFunc))); +} + +FormatMap BuildFormatMap() +{ + FormatMap map; + + using namespace rx; + + // | Format | Type | Internal format | Color write function | + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA8, WriteColor<R8G8B8A8, GLfloat> ); + InsertFormatMapping(&map, GL_RGBA, GL_BYTE, GL_RGBA8_SNORM, WriteColor<R8G8B8A8S, GLfloat> ); + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA4, WriteColor<R4G4B4A4, GLfloat> ); + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_RGB5_A1, WriteColor<R5G5B5A1, GLfloat> ); + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2, WriteColor<R10G10B10A2, GLfloat> ); + InsertFormatMapping(&map, GL_RGBA, GL_FLOAT, GL_RGBA32F, WriteColor<R32G32B32A32F, GLfloat>); + InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT, GL_RGBA16F, WriteColor<R16G16B16A16F, GLfloat>); + InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT_OES, GL_RGBA16F, WriteColor<R16G16B16A16F, GLfloat>); + + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_RGBA8UI, WriteColor<R8G8B8A8, GLuint> ); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_BYTE, GL_RGBA8I, WriteColor<R8G8B8A8S, GLint> ); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_RGBA16UI, WriteColor<R16G16B16A16, GLuint> ); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_SHORT, GL_RGBA16I, WriteColor<R16G16B16A16S, GLint> ); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_RGBA32UI, WriteColor<R32G32B32A32, GLuint> ); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_INT, GL_RGBA32I, WriteColor<R32G32B32A32S, GLint> ); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2UI, WriteColor<R10G10B10A2, GLuint> ); + + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_BYTE, GL_RGB8, WriteColor<R8G8B8, GLfloat> ); + InsertFormatMapping(&map, GL_RGB, GL_BYTE, GL_RGB8_SNORM, WriteColor<R8G8B8S, GLfloat> ); + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB565, WriteColor<R5G6B5, GLfloat> ); + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_R11F_G11F_B10F, WriteColor<R11G11B10F, GLfloat> ); + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_RGB9_E5, WriteColor<R9G9B9E5, GLfloat> ); + InsertFormatMapping(&map, GL_RGB, GL_FLOAT, GL_RGB32F, WriteColor<R32G32B32F, GLfloat> ); + InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT, GL_RGB16F, WriteColor<R16G16B16F, GLfloat> ); + InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT_OES, GL_RGB16F, WriteColor<R16G16B16F, GLfloat> ); + + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_RGB8UI, WriteColor<R8G8B8, GLuint> ); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_BYTE, GL_RGB8I, WriteColor<R8G8B8S, GLint> ); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_RGB16UI, WriteColor<R16G16B16, GLuint> ); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_SHORT, GL_RGB16I, WriteColor<R16G16B16S, GLint> ); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_RGB32UI, WriteColor<R32G32B32, GLuint> ); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_INT, GL_RGB32I, WriteColor<R32G32B32S, GLint> ); + + InsertFormatMapping(&map, GL_RG, GL_UNSIGNED_BYTE, GL_RG8, WriteColor<R8G8, GLfloat> ); + InsertFormatMapping(&map, GL_RG, GL_BYTE, GL_RG8_SNORM, WriteColor<R8G8S, GLfloat> ); + InsertFormatMapping(&map, GL_RG, GL_FLOAT, GL_RG32F, WriteColor<R32G32F, GLfloat> ); + InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT, GL_RG16F, WriteColor<R16G16F, GLfloat> ); + InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT_OES, GL_RG16F, WriteColor<R16G16F, GLfloat> ); + + InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_RG8UI, WriteColor<R8G8, GLuint> ); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_BYTE, GL_RG8I, WriteColor<R8G8S, GLint> ); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_RG16UI, WriteColor<R16G16, GLuint> ); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_SHORT, GL_RG16I, WriteColor<R16G16S, GLint> ); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_RG32UI, WriteColor<R32G32, GLuint> ); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_INT, GL_RG32I, WriteColor<R32G32S, GLint> ); + + InsertFormatMapping(&map, GL_RED, GL_UNSIGNED_BYTE, GL_R8, WriteColor<R8, GLfloat> ); + InsertFormatMapping(&map, GL_RED, GL_BYTE, GL_R8_SNORM, WriteColor<R8S, GLfloat> ); + InsertFormatMapping(&map, GL_RED, GL_FLOAT, GL_R32F, WriteColor<R32F, GLfloat> ); + InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT, GL_R16F, WriteColor<R16F, GLfloat> ); + InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT_OES, GL_R16F, WriteColor<R16F, GLfloat> ); + + InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_R8UI, WriteColor<R8, GLuint> ); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_BYTE, GL_R8I, WriteColor<R8S, GLint> ); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_R16UI, WriteColor<R16, GLuint> ); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_SHORT, GL_R16I, WriteColor<R16S, GLint> ); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_R32UI, WriteColor<R32, GLuint> ); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_INT, GL_R32I, WriteColor<R32S, GLint> ); + + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_LUMINANCE8_ALPHA8_EXT, WriteColor<L8A8, GLfloat> ); + InsertFormatMapping(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE8_EXT, WriteColor<L8, GLfloat> ); + InsertFormatMapping(&map, GL_ALPHA, GL_UNSIGNED_BYTE, GL_ALPHA8_EXT, WriteColor<A8, GLfloat> ); + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_LUMINANCE_ALPHA32F_EXT, WriteColor<L32A32F, GLfloat> ); + InsertFormatMapping(&map, GL_LUMINANCE, GL_FLOAT, GL_LUMINANCE32F_EXT, WriteColor<L32F, GLfloat> ); + InsertFormatMapping(&map, GL_ALPHA, GL_FLOAT, GL_ALPHA32F_EXT, WriteColor<A32F, GLfloat> ); + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_LUMINANCE_ALPHA16F_EXT, WriteColor<L16A16F, GLfloat> ); + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, GL_LUMINANCE_ALPHA16F_EXT, WriteColor<L16A16F, GLfloat> ); + InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT, GL_LUMINANCE16F_EXT, WriteColor<L16F, GLfloat> ); + InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, GL_LUMINANCE16F_EXT, WriteColor<L16F, GLfloat> ); + InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT, GL_ALPHA16F_EXT, WriteColor<A16F, GLfloat> ); + InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT_OES, GL_ALPHA16F_EXT, WriteColor<A16F, GLfloat> ); + + InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_BGRA8_EXT, WriteColor<B8G8R8A8, GLfloat> ); + InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_BGRA4_ANGLEX, WriteColor<B4G4R4A4, GLfloat> ); + InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_BGR5_A1_ANGLEX, WriteColor<B5G5R5A1, GLfloat> ); + + InsertFormatMapping(&map, GL_SRGB_EXT, GL_UNSIGNED_BYTE, GL_SRGB8, WriteColor<R8G8B8, GLfloat> ); + InsertFormatMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, GL_SRGB8_ALPHA8, WriteColor<R8G8B8A8, GLfloat> ); + + InsertFormatMapping(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, NULL ); + InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, NULL ); + InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, NULL ); + InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, NULL ); + + InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_DEPTH_COMPONENT16, NULL ); + InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_DEPTH_COMPONENT32_OES, NULL ); + InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, GL_DEPTH_COMPONENT32F, NULL ); + + InsertFormatMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, GL_STENCIL_INDEX8, NULL ); + + InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_DEPTH24_STENCIL8, NULL ); + InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_DEPTH32F_STENCIL8, NULL ); + + return map; +} + +static const FormatMap &GetFormatMap() +{ + static const FormatMap formatMap = BuildFormatMap(); + return formatMap; +} + +struct FormatInfo +{ + GLenum mInternalformat; + GLenum mFormat; + GLenum mType; + + FormatInfo(GLenum internalformat, GLenum format, GLenum type) + : mInternalformat(internalformat), mFormat(format), mType(type) { } + + bool operator<(const FormatInfo& other) const + { + return memcmp(this, &other, sizeof(FormatInfo)) < 0; + } +}; + +// ES3 has a specific set of permutations of internal formats, formats and types which are acceptable. +typedef std::set<FormatInfo> ES3FormatSet; + +ES3FormatSet BuildES3FormatSet() +{ + ES3FormatSet set; + + // Format combinations from ES 3.0.1 spec, table 3.2 + + // | Internal format | Format | Type | + // | | | | + set.insert(FormatInfo(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_RGBA8_SNORM, GL_RGBA, GL_BYTE )); + set.insert(FormatInfo(GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 )); + set.insert(FormatInfo(GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV )); + set.insert(FormatInfo(GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV )); + set.insert(FormatInfo(GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 )); + set.insert(FormatInfo(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT_OES )); + set.insert(FormatInfo(GL_RGBA32F, GL_RGBA, GL_FLOAT )); + set.insert(FormatInfo(GL_RGBA16F, GL_RGBA, GL_FLOAT )); + set.insert(FormatInfo(GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE )); + set.insert(FormatInfo(GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT )); + set.insert(FormatInfo(GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT )); + set.insert(FormatInfo(GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT )); + set.insert(FormatInfo(GL_RGBA32I, GL_RGBA_INTEGER, GL_INT )); + set.insert(FormatInfo(GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV )); + set.insert(FormatInfo(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_RGB8_SNORM, GL_RGB, GL_BYTE )); + set.insert(FormatInfo(GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 )); + set.insert(FormatInfo(GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV )); + set.insert(FormatInfo(GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV )); + set.insert(FormatInfo(GL_RGB16F, GL_RGB, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_RGB16F, GL_RGB, GL_HALF_FLOAT_OES )); + set.insert(FormatInfo(GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT_OES )); + set.insert(FormatInfo(GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT_OES )); + set.insert(FormatInfo(GL_RGB32F, GL_RGB, GL_FLOAT )); + set.insert(FormatInfo(GL_RGB16F, GL_RGB, GL_FLOAT )); + set.insert(FormatInfo(GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT )); + set.insert(FormatInfo(GL_RGB9_E5, GL_RGB, GL_FLOAT )); + set.insert(FormatInfo(GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_RGB8I, GL_RGB_INTEGER, GL_BYTE )); + set.insert(FormatInfo(GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT )); + set.insert(FormatInfo(GL_RGB16I, GL_RGB_INTEGER, GL_SHORT )); + set.insert(FormatInfo(GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT )); + set.insert(FormatInfo(GL_RGB32I, GL_RGB_INTEGER, GL_INT )); + set.insert(FormatInfo(GL_RG8, GL_RG, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_RG8_SNORM, GL_RG, GL_BYTE )); + set.insert(FormatInfo(GL_RG16F, GL_RG, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_RG16F, GL_RG, GL_HALF_FLOAT_OES )); + set.insert(FormatInfo(GL_RG32F, GL_RG, GL_FLOAT )); + set.insert(FormatInfo(GL_RG16F, GL_RG, GL_FLOAT )); + set.insert(FormatInfo(GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_RG8I, GL_RG_INTEGER, GL_BYTE )); + set.insert(FormatInfo(GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT )); + set.insert(FormatInfo(GL_RG16I, GL_RG_INTEGER, GL_SHORT )); + set.insert(FormatInfo(GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT )); + set.insert(FormatInfo(GL_RG32I, GL_RG_INTEGER, GL_INT )); + set.insert(FormatInfo(GL_R8, GL_RED, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_R8_SNORM, GL_RED, GL_BYTE )); + set.insert(FormatInfo(GL_R16F, GL_RED, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_R16F, GL_RED, GL_HALF_FLOAT_OES )); + set.insert(FormatInfo(GL_R32F, GL_RED, GL_FLOAT )); + set.insert(FormatInfo(GL_R16F, GL_RED, GL_FLOAT )); + set.insert(FormatInfo(GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_R8I, GL_RED_INTEGER, GL_BYTE )); + set.insert(FormatInfo(GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT )); + set.insert(FormatInfo(GL_R16I, GL_RED_INTEGER, GL_SHORT )); + set.insert(FormatInfo(GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT )); + set.insert(FormatInfo(GL_R32I, GL_RED_INTEGER, GL_INT )); + + // Unsized formats + set.insert(FormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 )); + set.insert(FormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 )); + set.insert(FormatInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 )); + set.insert(FormatInfo(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_SRGB_ALPHA_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_SRGB_EXT, GL_SRGB_EXT, GL_UNSIGNED_BYTE )); + + // Depth stencil formats + set.insert(FormatInfo(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT )); + set.insert(FormatInfo(GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT )); + set.insert(FormatInfo(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT )); + set.insert(FormatInfo(GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT )); + set.insert(FormatInfo(GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 )); + set.insert(FormatInfo(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV)); + + // From GL_EXT_sRGB + set.insert(FormatInfo(GL_SRGB8_ALPHA8_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_SRGB8, GL_SRGB_EXT, GL_UNSIGNED_BYTE )); + + // From GL_OES_texture_float + set.insert(FormatInfo(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT )); + set.insert(FormatInfo(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT )); + set.insert(FormatInfo(GL_ALPHA, GL_ALPHA, GL_FLOAT )); + + // From GL_OES_texture_half_float + set.insert(FormatInfo(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES )); + set.insert(FormatInfo(GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES )); + set.insert(FormatInfo(GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES )); + + // From GL_EXT_texture_format_BGRA8888 + set.insert(FormatInfo(GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE )); + + // From GL_EXT_texture_storage + // | Internal format | Format | Type | + // | | | | + set.insert(FormatInfo(GL_ALPHA8_EXT, GL_ALPHA, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_LUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT )); + set.insert(FormatInfo(GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT )); + set.insert(FormatInfo(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT )); + set.insert(FormatInfo(GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT_OES )); + set.insert(FormatInfo(GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT_OES )); + set.insert(FormatInfo(GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT )); + set.insert(FormatInfo(GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES )); + + // From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888 + set.insert(FormatInfo(GL_BGRA8_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT)); + set.insert(FormatInfo(GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE )); + set.insert(FormatInfo(GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT)); + set.insert(FormatInfo(GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE )); + + // From GL_ANGLE_depth_texture + set.insert(FormatInfo(GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES )); + + // Compressed formats + // From ES 3.0.1 spec, table 3.16 + // | Internal format | Format | Type | + // | | | | + set.insert(FormatInfo(GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE)); + set.insert(FormatInfo(GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE)); + set.insert(FormatInfo(GL_COMPRESSED_SIGNED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE)); + set.insert(FormatInfo(GL_COMPRESSED_RG11_EAC, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE)); + set.insert(FormatInfo(GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE)); + set.insert(FormatInfo(GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE)); + set.insert(FormatInfo(GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE)); + set.insert(FormatInfo(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE)); + set.insert(FormatInfo(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE)); + set.insert(FormatInfo(GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE)); + set.insert(FormatInfo(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE)); + + + // From GL_EXT_texture_compression_dxt1 + set.insert(FormatInfo(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE)); + set.insert(FormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE)); + + // From GL_ANGLE_texture_compression_dxt3 + set.insert(FormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE)); + + // From GL_ANGLE_texture_compression_dxt5 + set.insert(FormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE)); + + return set; +} + +static const ES3FormatSet &GetES3FormatSet() +{ + static const ES3FormatSet es3FormatSet = BuildES3FormatSet(); + return es3FormatSet; +} + +// Map of sizes of input types +struct TypeInfo +{ + GLuint mTypeBytes; + bool mSpecialInterpretation; + + TypeInfo() + : mTypeBytes(0), mSpecialInterpretation(false) { } + + TypeInfo(GLuint typeBytes, bool specialInterpretation) + : mTypeBytes(typeBytes), mSpecialInterpretation(specialInterpretation) { } + + bool operator<(const TypeInfo& other) const + { + return memcmp(this, &other, sizeof(TypeInfo)) < 0; + } +}; + +typedef std::pair<GLenum, TypeInfo> TypeInfoPair; +typedef std::map<GLenum, TypeInfo> TypeInfoMap; + +static TypeInfoMap BuildTypeInfoMap() +{ + TypeInfoMap map; + + map.insert(TypeInfoPair(GL_UNSIGNED_BYTE, TypeInfo( 1, false))); + map.insert(TypeInfoPair(GL_BYTE, TypeInfo( 1, false))); + map.insert(TypeInfoPair(GL_UNSIGNED_SHORT, TypeInfo( 2, false))); + map.insert(TypeInfoPair(GL_SHORT, TypeInfo( 2, false))); + map.insert(TypeInfoPair(GL_UNSIGNED_INT, TypeInfo( 4, false))); + map.insert(TypeInfoPair(GL_INT, TypeInfo( 4, false))); + map.insert(TypeInfoPair(GL_HALF_FLOAT, TypeInfo( 2, false))); + map.insert(TypeInfoPair(GL_HALF_FLOAT_OES, TypeInfo( 2, false))); + map.insert(TypeInfoPair(GL_FLOAT, TypeInfo( 4, false))); + map.insert(TypeInfoPair(GL_UNSIGNED_SHORT_5_6_5, TypeInfo( 2, true ))); + map.insert(TypeInfoPair(GL_UNSIGNED_SHORT_4_4_4_4, TypeInfo( 2, true ))); + map.insert(TypeInfoPair(GL_UNSIGNED_SHORT_5_5_5_1, TypeInfo( 2, true ))); + map.insert(TypeInfoPair(GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, TypeInfo( 2, true ))); + map.insert(TypeInfoPair(GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, TypeInfo( 2, true ))); + map.insert(TypeInfoPair(GL_UNSIGNED_INT_2_10_10_10_REV, TypeInfo( 4, true ))); + map.insert(TypeInfoPair(GL_UNSIGNED_INT_24_8, TypeInfo( 4, true ))); + map.insert(TypeInfoPair(GL_UNSIGNED_INT_10F_11F_11F_REV, TypeInfo( 4, true ))); + map.insert(TypeInfoPair(GL_UNSIGNED_INT_5_9_9_9_REV, TypeInfo( 4, true ))); + map.insert(TypeInfoPair(GL_UNSIGNED_INT_24_8_OES, TypeInfo( 4, true ))); + map.insert(TypeInfoPair(GL_FLOAT_32_UNSIGNED_INT_24_8_REV, TypeInfo( 8, true ))); + + return map; +} + +static bool GetTypeInfo(GLenum type, TypeInfo *outTypeInfo) +{ + static const TypeInfoMap infoMap = BuildTypeInfoMap(); + TypeInfoMap::const_iterator iter = infoMap.find(type); + if (iter != infoMap.end()) + { + if (outTypeInfo) + { + *outTypeInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +// Information about internal formats +typedef bool(*SupportCheckFunction)(GLuint, const Extensions &); + +static bool AlwaysSupported(GLuint, const Extensions &) +{ + return true; +} + +static bool UnimplementedSupport(GLuint, const Extensions &) +{ + return false; +} + +static bool NeverSupported(GLuint, const Extensions &) +{ + return false; +} + +template <GLuint minCoreGLVersion> +static bool RequireESVersion(GLuint clientVersion, const Extensions &) +{ + return clientVersion >= minCoreGLVersion; +} + +// Pointer to a boolean memeber of the Extensions struct +typedef bool(Extensions::*ExtensionBool); + +// Check support for a single extension +template <ExtensionBool bool1> +static bool RequireExtension(GLuint, const Extensions & extensions) +{ + return extensions.*bool1; +} + +// Check for a minimum client version or a single extension +template <GLuint minCoreGLVersion, ExtensionBool bool1> +static bool RequireESVersionOrExtension(GLuint clientVersion, const Extensions &extensions) +{ + return clientVersion >= minCoreGLVersion || extensions.*bool1; +} + +// Check for a minimum client version or two extensions +template <GLuint minCoreGLVersion, ExtensionBool bool1, ExtensionBool bool2> +static bool RequireESVersionOrExtensions(GLuint clientVersion, const Extensions &extensions) +{ + return clientVersion >= minCoreGLVersion || (extensions.*bool1 || extensions.*bool2); +} + +// Check support for two extensions +template <ExtensionBool bool1, ExtensionBool bool2> +static bool RequireExtensions(GLuint, const Extensions &extensions) +{ + return extensions.*bool1 || extensions.*bool2; +} + +struct InternalFormatInfo +{ + GLuint mRedBits; + GLuint mGreenBits; + GLuint mBlueBits; + + GLuint mLuminanceBits; + + GLuint mAlphaBits; + GLuint mSharedBits; + + GLuint mDepthBits; + GLuint mStencilBits; + + GLuint mPixelBits; + + GLuint mComponentCount; + + GLuint mCompressedBlockWidth; + GLuint mCompressedBlockHeight; + + GLenum mFormat; + GLenum mType; + + GLenum mComponentType; + GLenum mColorEncoding; + + bool mIsCompressed; + + SupportCheckFunction mTextureSupportFunction; + SupportCheckFunction mRenderSupportFunction; + SupportCheckFunction mFilterSupportFunction; + + InternalFormatInfo() : mRedBits(0), mGreenBits(0), mBlueBits(0), mLuminanceBits(0), mAlphaBits(0), mSharedBits(0), mDepthBits(0), mStencilBits(0), + mPixelBits(0), mComponentCount(0), mCompressedBlockWidth(0), mCompressedBlockHeight(0), mFormat(GL_NONE), mType(GL_NONE), + mComponentType(GL_NONE), mColorEncoding(GL_NONE), mIsCompressed(false), mTextureSupportFunction(NeverSupported), + mRenderSupportFunction(NeverSupported), mFilterSupportFunction(NeverSupported) + { + } + + static InternalFormatInfo UnsizedFormat(GLenum format, SupportCheckFunction textureSupport, SupportCheckFunction renderSupport, + SupportCheckFunction filterSupport) + { + InternalFormatInfo formatInfo; + formatInfo.mFormat = format; + formatInfo.mTextureSupportFunction = textureSupport; + formatInfo.mRenderSupportFunction = renderSupport; + formatInfo.mFilterSupportFunction = filterSupport; + return formatInfo; + } + + static InternalFormatInfo RGBAFormat(GLuint red, GLuint green, GLuint blue, GLuint alpha, GLuint shared, + GLenum format, GLenum type, GLenum componentType, bool srgb, + SupportCheckFunction textureSupport, SupportCheckFunction renderSupport, + SupportCheckFunction filterSupport) + { + InternalFormatInfo formatInfo; + formatInfo.mRedBits = red; + formatInfo.mGreenBits = green; + formatInfo.mBlueBits = blue; + formatInfo.mAlphaBits = alpha; + formatInfo.mSharedBits = shared; + formatInfo.mPixelBits = red + green + blue + alpha + shared; + formatInfo.mComponentCount = ((red > 0) ? 1 : 0) + ((green > 0) ? 1 : 0) + ((blue > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0); + formatInfo.mFormat = format; + formatInfo.mType = type; + formatInfo.mComponentType = componentType; + formatInfo.mColorEncoding = (srgb ? GL_SRGB : GL_LINEAR); + formatInfo.mTextureSupportFunction = textureSupport; + formatInfo.mRenderSupportFunction = renderSupport; + formatInfo.mFilterSupportFunction = filterSupport; + return formatInfo; + } + + static InternalFormatInfo LUMAFormat(GLuint luminance, GLuint alpha, GLenum format, GLenum type, GLenum componentType, + SupportCheckFunction textureSupport, SupportCheckFunction renderSupport, + SupportCheckFunction filterSupport) + { + InternalFormatInfo formatInfo; + formatInfo.mLuminanceBits = luminance; + formatInfo.mAlphaBits = alpha; + formatInfo.mPixelBits = luminance + alpha; + formatInfo.mComponentCount = ((luminance > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0); + formatInfo.mFormat = format; + formatInfo.mType = type; + formatInfo.mComponentType = componentType; + formatInfo.mColorEncoding = GL_LINEAR; + formatInfo.mTextureSupportFunction = textureSupport; + formatInfo.mRenderSupportFunction = renderSupport; + formatInfo.mFilterSupportFunction = filterSupport; + return formatInfo; + } + + static InternalFormatInfo DepthStencilFormat(GLuint depthBits, GLuint stencilBits, GLuint unusedBits, GLenum format, + GLenum type, GLenum componentType, SupportCheckFunction textureSupport, + SupportCheckFunction renderSupport, SupportCheckFunction filterSupport) + { + InternalFormatInfo formatInfo; + formatInfo.mDepthBits = depthBits; + formatInfo.mStencilBits = stencilBits; + formatInfo.mPixelBits = depthBits + stencilBits + unusedBits; + formatInfo.mComponentCount = ((depthBits > 0) ? 1 : 0) + ((stencilBits > 0) ? 1 : 0); + formatInfo.mFormat = format; + formatInfo.mType = type; + formatInfo.mComponentType = componentType; + formatInfo.mColorEncoding = GL_LINEAR; + formatInfo.mTextureSupportFunction = textureSupport; + formatInfo.mRenderSupportFunction = renderSupport; + formatInfo.mFilterSupportFunction = filterSupport; + return formatInfo; + } + + static InternalFormatInfo CompressedFormat(GLuint compressedBlockWidth, GLuint compressedBlockHeight, GLuint compressedBlockSize, + GLuint componentCount, GLenum format, GLenum type, bool srgb, + SupportCheckFunction textureSupport, SupportCheckFunction renderSupport, + SupportCheckFunction filterSupport) + { + InternalFormatInfo formatInfo; + formatInfo.mCompressedBlockWidth = compressedBlockWidth; + formatInfo.mCompressedBlockHeight = compressedBlockHeight; + formatInfo.mPixelBits = compressedBlockSize; + formatInfo.mComponentCount = componentCount; + formatInfo.mFormat = format; + formatInfo.mType = type; + formatInfo.mComponentType = GL_UNSIGNED_NORMALIZED; + formatInfo.mColorEncoding = (srgb ? GL_SRGB : GL_LINEAR); + formatInfo.mIsCompressed = true; + formatInfo.mTextureSupportFunction = textureSupport; + formatInfo.mRenderSupportFunction = renderSupport; + formatInfo.mFilterSupportFunction = filterSupport; + return formatInfo; + } +}; + +typedef std::pair<GLenum, InternalFormatInfo> InternalFormatInfoPair; +typedef std::map<GLenum, InternalFormatInfo> InternalFormatInfoMap; + +static InternalFormatInfoMap BuildInternalFormatInfoMap() +{ + InternalFormatInfoMap map; + + // From ES 3.0.1 spec, table 3.12 + map.insert(InternalFormatInfoPair(GL_NONE, InternalFormatInfo())); + + // | Internal format | | R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_R8, InternalFormatInfo::RGBAFormat( 8, 0, 0, 0, 0, GL_RED, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::textureRG>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_R8_SNORM, InternalFormatInfo::RGBAFormat( 8, 0, 0, 0, 0, GL_RED, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireESVersion<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RG8, InternalFormatInfo::RGBAFormat( 8, 8, 0, 0, 0, GL_RG, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::textureRG>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RG8_SNORM, InternalFormatInfo::RGBAFormat( 8, 8, 0, 0, 0, GL_RG, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireESVersion<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8, InternalFormatInfo::RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::rgb8rgba8>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8_SNORM, InternalFormatInfo::RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireESVersion<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB565, InternalFormatInfo::RGBAFormat( 5, 6, 5, 0, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, RequireESVersion<2>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA4, InternalFormatInfo::RGBAFormat( 4, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_NORMALIZED, false, RequireESVersion<2>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB5_A1, InternalFormatInfo::RGBAFormat( 5, 5, 5, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_NORMALIZED, false, RequireESVersion<2>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8, InternalFormatInfo::RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESVersionOrExtension<3, &Extensions::rgb8rgba8>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8_SNORM, InternalFormatInfo::RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireESVersion<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB10_A2, InternalFormatInfo::RGBAFormat(10, 10, 10, 2, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_NORMALIZED, false, RequireESVersion<3>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB10_A2UI, InternalFormatInfo::RGBAFormat(10, 10, 10, 2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT, false, RequireESVersion<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB8, InternalFormatInfo::RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESVersionOrExtension<3, &Extensions::sRGB>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB8_ALPHA8, InternalFormatInfo::RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESVersionOrExtension<3, &Extensions::sRGB>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_R11F_G11F_B10F, InternalFormatInfo::RGBAFormat(11, 11, 10, 0, 0, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_FLOAT, false, RequireESVersion<3>, RequireExtension<&Extensions::colorBufferFloat>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB9_E5, InternalFormatInfo::RGBAFormat( 9, 9, 9, 0, 5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT, false, RequireESVersion<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_R8I, InternalFormatInfo::RGBAFormat( 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_BYTE, GL_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R8UI, InternalFormatInfo::RGBAFormat( 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R16I, InternalFormatInfo::RGBAFormat(16, 0, 0, 0, 0, GL_RED_INTEGER, GL_SHORT, GL_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R16UI, InternalFormatInfo::RGBAFormat(16, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R32I, InternalFormatInfo::RGBAFormat(32, 0, 0, 0, 0, GL_RED_INTEGER, GL_INT, GL_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R32UI, InternalFormatInfo::RGBAFormat(32, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG8I, InternalFormatInfo::RGBAFormat( 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_BYTE, GL_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG8UI, InternalFormatInfo::RGBAFormat( 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG16I, InternalFormatInfo::RGBAFormat(16, 16, 0, 0, 0, GL_RG_INTEGER, GL_SHORT, GL_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG16UI, InternalFormatInfo::RGBAFormat(16, 16, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG32I, InternalFormatInfo::RGBAFormat(32, 32, 0, 0, 0, GL_RG_INTEGER, GL_INT, GL_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG32UI, InternalFormatInfo::RGBAFormat(32, 32, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8I, InternalFormatInfo::RGBAFormat( 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_BYTE, GL_INT, false, RequireESVersion<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8UI, InternalFormatInfo::RGBAFormat( 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireESVersion<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB16I, InternalFormatInfo::RGBAFormat(16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_SHORT, GL_INT, false, RequireESVersion<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB16UI, InternalFormatInfo::RGBAFormat(16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireESVersion<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB32I, InternalFormatInfo::RGBAFormat(32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_INT, GL_INT, false, RequireESVersion<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB32UI, InternalFormatInfo::RGBAFormat(32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireESVersion<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8I, InternalFormatInfo::RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_BYTE, GL_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8UI, InternalFormatInfo::RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA16I, InternalFormatInfo::RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_SHORT, GL_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA16UI, InternalFormatInfo::RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA32I, InternalFormatInfo::RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_INT, GL_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA32UI, InternalFormatInfo::RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireESVersion<3>, AlwaysSupported, NeverSupported))); + + map.insert(InternalFormatInfoPair(GL_BGRA8_EXT, InternalFormatInfo::RGBAFormat( 8, 8, 8, 8, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExtension<&Extensions::textureFormatBGRA8888>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_BGRA4_ANGLEX, InternalFormatInfo::RGBAFormat( 4, 4, 4, 4, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExtension<&Extensions::textureFormatBGRA8888>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_BGR5_A1_ANGLEX, InternalFormatInfo::RGBAFormat( 5, 5, 5, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExtension<&Extensions::textureFormatBGRA8888>, AlwaysSupported, AlwaysSupported))); + + // Floating point renderability and filtering is provided by OES_texture_float and OES_texture_half_float + // | Internal format | | D |S | Format | Type | Comp | SRGB | Texture supported | Renderable | Filterable | + // | | | | | | | type | | | | | + map.insert(InternalFormatInfoPair(GL_R16F, InternalFormatInfo::RGBAFormat(16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT, GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_RG16F, InternalFormatInfo::RGBAFormat(16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT, GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_RGB16F, InternalFormatInfo::RGBAFormat(16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT, GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureHalfFloat>, AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_RGBA16F, InternalFormatInfo::RGBAFormat(16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureHalfFloat>, AlwaysSupported, RequireExtension<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_R32F, InternalFormatInfo::RGBAFormat(32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureFloat, &Extensions::textureRG>, AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear> ))); + map.insert(InternalFormatInfoPair(GL_RG32F, InternalFormatInfo::RGBAFormat(32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, RequireESVersionOrExtensions<3, &Extensions::textureFloat, &Extensions::textureRG>, AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear> ))); + map.insert(InternalFormatInfoPair(GL_RGB32F, InternalFormatInfo::RGBAFormat(32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureFloat>, AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear> ))); + map.insert(InternalFormatInfoPair(GL_RGBA32F, InternalFormatInfo::RGBAFormat(32, 32, 32, 32, 0, GL_RGBA, GL_FLOAT, GL_FLOAT, false, RequireESVersionOrExtension<3, &Extensions::textureFloat>, AlwaysSupported, RequireExtension<&Extensions::textureFloatLinear> ))); + + // Depth stencil formats + // | Internal format | | D |S | X | Format | Type | Component type | Supported | + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT16, InternalFormatInfo::DepthStencilFormat(16, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, RequireESVersion<2>, AlwaysSupported, RequireESVersionOrExtension<3, &Extensions::depthTextures>))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT24, InternalFormatInfo::DepthStencilFormat(24, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireESVersion<3>, AlwaysSupported, RequireESVersionOrExtension<3, &Extensions::depthTextures>))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32F, InternalFormatInfo::DepthStencilFormat(32, 0, 0, GL_DEPTH_COMPONENT, GL_FLOAT, GL_FLOAT, RequireESVersion<3>, AlwaysSupported, RequireESVersionOrExtension<3, &Extensions::depthTextures>))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32_OES, InternalFormatInfo::DepthStencilFormat(32, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::depthTextures>, AlwaysSupported, AlwaysSupported ))); + map.insert(InternalFormatInfoPair(GL_DEPTH24_STENCIL8, InternalFormatInfo::DepthStencilFormat(24, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_UNSIGNED_NORMALIZED, RequireESVersionOrExtension<2, &Extensions::depthTextures>, AlwaysSupported, AlwaysSupported ))); + map.insert(InternalFormatInfoPair(GL_DEPTH32F_STENCIL8, InternalFormatInfo::DepthStencilFormat(32, 8, 24, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_FLOAT, RequireESVersion<3>, AlwaysSupported, AlwaysSupported ))); + map.insert(InternalFormatInfoPair(GL_STENCIL_INDEX8, InternalFormatInfo::DepthStencilFormat( 0, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, RequireESVersion<2>, AlwaysSupported, NeverSupported ))); + + // Luminance alpha formats + // | Internal format | | L | A | Format | Type | Component type | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_ALPHA8_EXT, InternalFormatInfo::LUMAFormat( 0, 8, GL_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE8_EXT, InternalFormatInfo::LUMAFormat( 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_ALPHA32F_EXT, InternalFormatInfo::LUMAFormat( 0, 32, GL_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtensions<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE32F_EXT, InternalFormatInfo::LUMAFormat(32, 0, GL_LUMINANCE, GL_FLOAT, GL_FLOAT, RequireExtensions<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_ALPHA16F_EXT, InternalFormatInfo::LUMAFormat( 0, 16, GL_ALPHA, GL_HALF_FLOAT, GL_FLOAT, RequireExtensions<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE16F_EXT, InternalFormatInfo::LUMAFormat(16, 0, GL_LUMINANCE, GL_HALF_FLOAT, GL_FLOAT, RequireExtensions<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE8_ALPHA8_EXT, InternalFormatInfo::LUMAFormat( 8, 8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExtension<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA32F_EXT, InternalFormatInfo::LUMAFormat(32, 32, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtensions<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA16F_EXT, InternalFormatInfo::LUMAFormat(16, 16, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_FLOAT, RequireExtensions<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); + + // Unsized formats + // | Internal format | | Format | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_ALPHA, InternalFormatInfo::UnsizedFormat(GL_ALPHA, RequireESVersion<2>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE, InternalFormatInfo::UnsizedFormat(GL_LUMINANCE, RequireESVersion<2>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA, InternalFormatInfo::UnsizedFormat(GL_LUMINANCE_ALPHA, RequireESVersion<2>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RED, InternalFormatInfo::UnsizedFormat(GL_RED, RequireESVersionOrExtension<3, &Extensions::textureRG>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RG, InternalFormatInfo::UnsizedFormat(GL_RG, RequireESVersionOrExtension<3, &Extensions::textureRG>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB, InternalFormatInfo::UnsizedFormat(GL_RGB, RequireESVersion<2>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA, InternalFormatInfo::UnsizedFormat(GL_RGBA, RequireESVersion<2>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RED_INTEGER, InternalFormatInfo::UnsizedFormat(GL_RED_INTEGER, RequireESVersion<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_RG_INTEGER, InternalFormatInfo::UnsizedFormat(GL_RG_INTEGER, RequireESVersion<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_RGB_INTEGER, InternalFormatInfo::UnsizedFormat(GL_RGB_INTEGER, RequireESVersion<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_RGBA_INTEGER, InternalFormatInfo::UnsizedFormat(GL_RGBA_INTEGER, RequireESVersion<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_BGRA_EXT, InternalFormatInfo::UnsizedFormat(GL_BGRA_EXT, RequireExtension<&Extensions::textureFormatBGRA8888>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT, InternalFormatInfo::UnsizedFormat(GL_DEPTH_COMPONENT, RequireESVersion<2>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_DEPTH_STENCIL, InternalFormatInfo::UnsizedFormat(GL_DEPTH_STENCIL, RequireESVersionOrExtension<3, &Extensions::packedDepthStencil>, AlwaysSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB_EXT, InternalFormatInfo::UnsizedFormat(GL_RGB, RequireESVersionOrExtension<3, &Extensions::sRGB>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB_ALPHA_EXT, InternalFormatInfo::UnsizedFormat(GL_RGBA, RequireESVersionOrExtension<3, &Extensions::sRGB>, AlwaysSupported, AlwaysSupported))); + + // Compressed formats, From ES 3.0.1 spec, table 3.16 + // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_COMPRESSED_R11_EAC, InternalFormatInfo::CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_R11_EAC, InternalFormatInfo::CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RG11_EAC, InternalFormatInfo::CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_RG11_EAC, InternalFormatInfo::CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_ETC2, InternalFormatInfo::CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ETC2, InternalFormatInfo::CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, InternalFormatInfo::CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, InternalFormatInfo::CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA8_ETC2_EAC, InternalFormatInfo::CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, InternalFormatInfo::CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + + // From GL_EXT_texture_compression_dxt1 + // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, InternalFormatInfo::CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported ))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, InternalFormatInfo::CompressedFormat(4, 4, 64, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported ))); + + // From GL_ANGLE_texture_compression_dxt3 + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, InternalFormatInfo::CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported ))); + + // From GL_ANGLE_texture_compression_dxt5 + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, InternalFormatInfo::CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, false, RequireExtension<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported ))); + + return map; +} + +static const InternalFormatInfoMap &GetInternalFormatMap() +{ + static const InternalFormatInfoMap formatMap = BuildInternalFormatInfoMap(); + return formatMap; +} + +static bool GetInternalFormatInfo(GLenum internalFormat, InternalFormatInfo *outFormatInfo) +{ + const InternalFormatInfoMap &map = GetInternalFormatMap(); + InternalFormatInfoMap::const_iterator iter = map.find(internalFormat); + if (iter != map.end()) + { + if (outFormatInfo) + { + *outFormatInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +static FormatSet BuildAllSizedInternalFormatSet() +{ + FormatSet result; + + const InternalFormatInfoMap &formats = GetInternalFormatMap(); + for (InternalFormatInfoMap::const_iterator i = formats.begin(); i != formats.end(); i++) + { + if (i->second.mPixelBits > 0) + { + result.insert(i->first); + } + } + + return result; +} + +typedef std::set<GLenum> TypeSet; + +struct EffectiveInternalFormatInfo +{ + GLenum mEffectiveFormat; + GLenum mDestFormat; + GLuint mMinRedBits; + GLuint mMaxRedBits; + GLuint mMinGreenBits; + GLuint mMaxGreenBits; + GLuint mMinBlueBits; + GLuint mMaxBlueBits; + GLuint mMinAlphaBits; + GLuint mMaxAlphaBits; + + EffectiveInternalFormatInfo(GLenum effectiveFormat, GLenum destFormat, GLuint minRedBits, GLuint maxRedBits, + GLuint minGreenBits, GLuint maxGreenBits, GLuint minBlueBits, GLuint maxBlueBits, + GLuint minAlphaBits, GLuint maxAlphaBits) + : mEffectiveFormat(effectiveFormat), mDestFormat(destFormat), mMinRedBits(minRedBits), + mMaxRedBits(maxRedBits), mMinGreenBits(minGreenBits), mMaxGreenBits(maxGreenBits), + mMinBlueBits(minBlueBits), mMaxBlueBits(maxBlueBits), mMinAlphaBits(minAlphaBits), + mMaxAlphaBits(maxAlphaBits) {}; +}; + +typedef std::vector<EffectiveInternalFormatInfo> EffectiveInternalFormatList; + +static EffectiveInternalFormatList BuildSizedEffectiveInternalFormatList() +{ + EffectiveInternalFormatList list; + + // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and + // linear source buffer component sizes. + // | Source channel min/max sizes | + // Effective Internal Format | N/A | R | G | B | A | + list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_NONE, 0, 0, 0, 0, 0, 0, 1, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_R8, GL_NONE, 1, 8, 0, 0, 0, 0, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RG8, GL_NONE, 1, 8, 1, 8, 0, 0, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_NONE, 1, 5, 1, 6, 1, 5, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_NONE, 6, 8, 7, 8, 6, 8, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_NONE, 1, 4, 1, 4, 1, 4, 1, 4)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_NONE, 5, 5, 5, 5, 5, 5, 1, 1)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_NONE, 5, 8, 5, 8, 5, 8, 2, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB10_A2, GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2)); + + return list; +} + + +static EffectiveInternalFormatList BuildUnsizedEffectiveInternalFormatList() +{ + EffectiveInternalFormatList list; + + // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and + // linear source buffer component sizes. + // | Source channel min/max sizes | + // Effective Internal Format | Dest Format | R | G | B | A | + list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_ALPHA, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX, 1, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_EXT, GL_LUMINANCE, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX)); + list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 1, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_RGB, 1, 5, 1, 6, 1, 5, 0, UINT_MAX)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_RGB, 6, 8, 7, 8, 6, 8, 0, UINT_MAX)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_RGBA, 1, 4, 1, 4, 1, 4, 1, 4)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_RGBA, 5, 5, 5, 5, 5, 5, 1, 1)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_RGBA, 5, 8, 5, 8, 5, 8, 5, 8)); + + return list; +} + +static bool GetEffectiveInternalFormat(const InternalFormatInfo &srcFormat, const InternalFormatInfo &destFormat, + GLenum *outEffectiveFormat) +{ + const EffectiveInternalFormatList *list = NULL; + GLenum targetFormat = GL_NONE; + + if (gl::IsSizedInternalFormat(destFormat.mFormat)) + { + static const EffectiveInternalFormatList sizedList = BuildSizedEffectiveInternalFormatList(); + list = &sizedList; + } + else + { + static const EffectiveInternalFormatList unsizedList = BuildUnsizedEffectiveInternalFormatList(); + list = &unsizedList; + targetFormat = destFormat.mFormat; + } + + for (size_t curFormat = 0; curFormat < list->size(); ++curFormat) + { + const EffectiveInternalFormatInfo& formatInfo = list->at(curFormat); + if ((formatInfo.mDestFormat == targetFormat) && + (formatInfo.mMinRedBits <= srcFormat.mRedBits && formatInfo.mMaxRedBits >= srcFormat.mRedBits) && + (formatInfo.mMinGreenBits <= srcFormat.mGreenBits && formatInfo.mMaxGreenBits >= srcFormat.mGreenBits) && + (formatInfo.mMinBlueBits <= srcFormat.mBlueBits && formatInfo.mMaxBlueBits >= srcFormat.mBlueBits) && + (formatInfo.mMinAlphaBits <= srcFormat.mAlphaBits && formatInfo.mMaxAlphaBits >= srcFormat.mAlphaBits)) + { + *outEffectiveFormat = formatInfo.mEffectiveFormat; + return true; + } + } + + return false; +} + +struct CopyConversion +{ + GLenum mTextureFormat; + GLenum mFramebufferFormat; + + CopyConversion(GLenum textureFormat, GLenum framebufferFormat) + : mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { } + + bool operator<(const CopyConversion& other) const + { + return memcmp(this, &other, sizeof(CopyConversion)) < 0; + } +}; + +typedef std::set<CopyConversion> CopyConversionSet; + +static CopyConversionSet BuildValidES3CopyTexImageCombinations() +{ + CopyConversionSet set; + + // From ES 3.0.1 spec, table 3.15 + set.insert(CopyConversion(GL_ALPHA, GL_RGBA)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RED)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RG)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RGB)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RGBA)); + set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_RGBA)); + set.insert(CopyConversion(GL_RED, GL_RED)); + set.insert(CopyConversion(GL_RED, GL_RG)); + set.insert(CopyConversion(GL_RED, GL_RGB)); + set.insert(CopyConversion(GL_RED, GL_RGBA)); + set.insert(CopyConversion(GL_RG, GL_RG)); + set.insert(CopyConversion(GL_RG, GL_RGB)); + set.insert(CopyConversion(GL_RG, GL_RGBA)); + set.insert(CopyConversion(GL_RGB, GL_RGB)); + set.insert(CopyConversion(GL_RGB, GL_RGBA)); + set.insert(CopyConversion(GL_RGBA, GL_RGBA)); + + // Necessary for ANGLE back-buffers + set.insert(CopyConversion(GL_ALPHA, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_LUMINANCE, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RED, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RG, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RGB, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RGBA, GL_BGRA_EXT)); + + set.insert(CopyConversion(GL_RED_INTEGER, GL_RED_INTEGER)); + set.insert(CopyConversion(GL_RED_INTEGER, GL_RG_INTEGER)); + set.insert(CopyConversion(GL_RED_INTEGER, GL_RGB_INTEGER)); + set.insert(CopyConversion(GL_RED_INTEGER, GL_RGBA_INTEGER)); + set.insert(CopyConversion(GL_RG_INTEGER, GL_RG_INTEGER)); + set.insert(CopyConversion(GL_RG_INTEGER, GL_RGB_INTEGER)); + set.insert(CopyConversion(GL_RG_INTEGER, GL_RGBA_INTEGER)); + set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGB_INTEGER)); + set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGBA_INTEGER)); + set.insert(CopyConversion(GL_RGBA_INTEGER, GL_RGBA_INTEGER)); + + return set; +} + +bool IsValidInternalFormat(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + ASSERT(internalFormatInfo.mTextureSupportFunction != NULL); + return internalFormatInfo.mTextureSupportFunction(clientVersion, extensions); + } + else + { + return false; + } +} + +bool IsValidFormat(GLenum format, const Extensions &extensions, GLuint clientVersion) +{ + const InternalFormatInfoMap &internalFormats = GetInternalFormatMap(); + for (InternalFormatInfoMap::const_iterator i = internalFormats.begin(); i != internalFormats.end(); i++) + { + if (i->second.mFormat == format && i->second.mTextureSupportFunction(clientVersion, extensions)) + { + return true; + } + } + + return false; +} + +bool IsValidType(GLenum type, const Extensions &extensions, GLuint clientVersion) +{ + const InternalFormatInfoMap &internalFormats = GetInternalFormatMap(); + for (InternalFormatInfoMap::const_iterator i = internalFormats.begin(); i != internalFormats.end(); i++) + { + if (i->second.mType == type && i->second.mTextureSupportFunction(clientVersion, extensions)) + { + return true; + } + } + + return false; +} + +bool IsValidFormatCombination(GLenum internalFormat, GLenum format, GLenum type, const Extensions &extensions, GLuint clientVersion) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + if (!internalFormatInfo.mTextureSupportFunction(clientVersion, extensions)) + { + return false; + } + } + else + { + UNREACHABLE(); + return false; + } + + if (clientVersion == 2) + { + static const FormatMap &formats = GetFormatMap(); + FormatMap::const_iterator iter = formats.find(FormatTypePair(format, type)); + return (iter != formats.end()) && ((internalFormat == (GLint)type) || (internalFormat == iter->second.mInternalFormat)); + } + else if (clientVersion == 3) + { + static const ES3FormatSet &formats = GetES3FormatSet(); + return formats.find(FormatInfo(internalFormat, format, type)) != formats.end(); + } + else + { + UNREACHABLE(); + return false; + } +} + +bool IsValidCopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle, GLuint clientVersion) +{ + InternalFormatInfo textureInternalFormatInfo; + InternalFormatInfo framebufferInternalFormatInfo; + if (GetInternalFormatInfo(textureInternalFormat, &textureInternalFormatInfo) && + GetInternalFormatInfo(frameBufferInternalFormat, &framebufferInternalFormatInfo)) + { + if (clientVersion == 2) + { + UNIMPLEMENTED(); + return false; + } + else if (clientVersion == 3) + { + static const CopyConversionSet conversionSet = BuildValidES3CopyTexImageCombinations(); + const CopyConversion conversion = CopyConversion(textureInternalFormatInfo.mFormat, + framebufferInternalFormatInfo.mFormat); + if (conversionSet.find(conversion) != conversionSet.end()) + { + // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats + // must both be signed, unsigned, or fixed point and both source and destinations + // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed + // conversion between fixed and floating point. + + if ((textureInternalFormatInfo.mColorEncoding == GL_SRGB) != (framebufferInternalFormatInfo.mColorEncoding == GL_SRGB)) + { + return false; + } + + if (((textureInternalFormatInfo.mComponentType == GL_INT) != (framebufferInternalFormatInfo.mComponentType == GL_INT)) || + ((textureInternalFormatInfo.mComponentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.mComponentType == GL_UNSIGNED_INT))) + { + return false; + } + + if (gl::IsFloatOrFixedComponentType(textureInternalFormatInfo.mComponentType) && + !gl::IsFloatOrFixedComponentType(framebufferInternalFormatInfo.mComponentType)) + { + return false; + } + + // GLES specification 3.0.3, sec 3.8.5, pg 139-140: + // The effective internal format of the source buffer is determined with the following rules applied in order: + // * If the source buffer is a texture or renderbuffer that was created with a sized internal format then the + // effective internal format is the source buffer's sized internal format. + // * If the source buffer is a texture that was created with an unsized base internal format, then the + // effective internal format is the source image array's effective internal format, as specified by table + // 3.12, which is determined from the <format> and <type> that were used when the source image array was + // specified by TexImage*. + // * Otherwise the effective internal format is determined by the row in table 3.17 or 3.18 where + // Destination Internal Format matches internalformat and where the [source channel sizes] are consistent + // with the values of the source buffer's [channel sizes]. Table 3.17 is used if the + // FRAMEBUFFER_ATTACHMENT_ENCODING is LINEAR and table 3.18 is used if the FRAMEBUFFER_ATTACHMENT_ENCODING + // is SRGB. + InternalFormatInfo sourceEffectiveFormat; + if (readBufferHandle != 0) + { + // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer + if (gl::IsSizedInternalFormat(framebufferInternalFormatInfo.mFormat)) + { + sourceEffectiveFormat = framebufferInternalFormatInfo; + } + else + { + // Renderbuffers cannot be created with an unsized internal format, so this must be an unsized-format + // texture. We can use the same table we use when creating textures to get its effective sized format. + GLenum effectiveFormat = gl::GetSizedInternalFormat(framebufferInternalFormatInfo.mFormat, + framebufferInternalFormatInfo.mType); + gl::GetInternalFormatInfo(effectiveFormat, &sourceEffectiveFormat); + } + } + else + { + // The effective internal format must be derived from the source framebuffer's channel sizes. + // This is done in GetEffectiveInternalFormat for linear buffers (table 3.17) + if (framebufferInternalFormatInfo.mColorEncoding == GL_LINEAR) + { + GLenum effectiveFormat; + if (GetEffectiveInternalFormat(framebufferInternalFormatInfo, textureInternalFormatInfo, &effectiveFormat)) + { + gl::GetInternalFormatInfo(effectiveFormat, &sourceEffectiveFormat); + } + else + { + return false; + } + } + else if (framebufferInternalFormatInfo.mColorEncoding == GL_SRGB) + { + // SRGB buffers can only be copied to sized format destinations according to table 3.18 + if (gl::IsSizedInternalFormat(textureInternalFormat) && + (framebufferInternalFormatInfo.mRedBits >= 1 && framebufferInternalFormatInfo.mRedBits <= 8) && + (framebufferInternalFormatInfo.mGreenBits >= 1 && framebufferInternalFormatInfo.mGreenBits <= 8) && + (framebufferInternalFormatInfo.mBlueBits >= 1 && framebufferInternalFormatInfo.mBlueBits <= 8) && + (framebufferInternalFormatInfo.mAlphaBits >= 1 && framebufferInternalFormatInfo.mAlphaBits <= 8)) + { + gl::GetInternalFormatInfo(GL_SRGB8_ALPHA8, &sourceEffectiveFormat); + } + else + { + return false; + } + } + else + { + UNREACHABLE(); + } + } + + if (gl::IsSizedInternalFormat(textureInternalFormatInfo.mFormat)) + { + // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination format is sized, + // component sizes of the source and destination formats must exactly match + if (textureInternalFormatInfo.mRedBits != sourceEffectiveFormat.mRedBits || + textureInternalFormatInfo.mGreenBits != sourceEffectiveFormat.mGreenBits || + textureInternalFormatInfo.mBlueBits != sourceEffectiveFormat.mBlueBits || + textureInternalFormatInfo.mAlphaBits != sourceEffectiveFormat.mAlphaBits) + { + return false; + } + } + + + return true; // A conversion function exists, and no rule in the specification has precluded conversion + // between these formats. + } + + return false; + } + else + { + UNREACHABLE(); + return false; + } + } + else + { + UNREACHABLE(); + return false; + } +} + +bool IsRenderingSupported(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + ASSERT(internalFormatInfo.mTextureSupportFunction != NULL); + ASSERT(internalFormatInfo.mRenderSupportFunction != NULL); + return internalFormatInfo.mTextureSupportFunction(clientVersion, extensions) && + internalFormatInfo.mRenderSupportFunction(clientVersion, extensions); + } + else + { + return false; + } +} + +bool IsFilteringSupported(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + ASSERT(internalFormatInfo.mTextureSupportFunction != NULL); + ASSERT(internalFormatInfo.mFilterSupportFunction != NULL); + return internalFormatInfo.mTextureSupportFunction(clientVersion, extensions) && + internalFormatInfo.mFilterSupportFunction(clientVersion, extensions); + } + else + { + return false; + } +} + +bool IsSizedInternalFormat(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mPixelBits > 0; + } + else + { + UNREACHABLE(); + return false; + } +} + +GLenum GetSizedInternalFormat(GLenum format, GLenum type) +{ + const FormatMap &formats = GetFormatMap(); + FormatMap::const_iterator iter = formats.find(FormatTypePair(format, type)); + return (iter != formats.end()) ? iter->second.mInternalFormat : GL_NONE; +} + +GLuint GetPixelBytes(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mPixelBits / 8; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetAlphaBits(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mAlphaBits; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetRedBits(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mRedBits; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetGreenBits(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mGreenBits; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetBlueBits(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mBlueBits; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetLuminanceBits(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mLuminanceBits; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetDepthBits(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mDepthBits; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetStencilBits(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mStencilBits; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetTypeBytes(GLenum type) +{ + TypeInfo typeInfo; + if (GetTypeInfo(type, &typeInfo)) + { + return typeInfo.mTypeBytes; + } + else + { + UNREACHABLE(); + return 0; + } +} + +bool IsSpecialInterpretationType(GLenum type) +{ + TypeInfo typeInfo; + if (GetTypeInfo(type, &typeInfo)) + { + return typeInfo.mSpecialInterpretation; + } + else + { + UNREACHABLE(); + return false; + } +} + +bool IsFloatOrFixedComponentType(GLenum type) +{ + if (type == GL_UNSIGNED_NORMALIZED || + type == GL_SIGNED_NORMALIZED || + type == GL_FLOAT) + { + return true; + } + else + { + return false; + } +} + +GLenum GetFormat(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mFormat; + } + else + { + UNREACHABLE(); + return GL_NONE; + } +} + +GLenum GetType(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mType; + } + else + { + UNREACHABLE(); + return GL_NONE; + } +} + +GLenum GetComponentType(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mComponentType; + } + else + { + UNREACHABLE(); + return GL_NONE; + } +} + +GLuint GetComponentCount(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mComponentCount; + } + else + { + UNREACHABLE(); + return false; + } +} + +GLenum GetColorEncoding(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mColorEncoding; + } + else + { + UNREACHABLE(); + return false; + } +} + +GLuint GetRowPitch(GLenum internalFormat, GLenum type, GLsizei width, GLint alignment) +{ + ASSERT(alignment > 0 && isPow2(alignment)); + return rx::roundUp(GetBlockSize(internalFormat, type, width, 1), static_cast<GLuint>(alignment)); +} + +GLuint GetDepthPitch(GLenum internalFormat, GLenum type, GLsizei width, GLsizei height, GLint alignment) +{ + return GetRowPitch(internalFormat, type, width, alignment) * height; +} + +GLuint GetBlockSize(GLenum internalFormat, GLenum type, GLsizei width, GLsizei height) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + if (internalFormatInfo.mIsCompressed) + { + GLsizei numBlocksWide = (width + internalFormatInfo.mCompressedBlockWidth - 1) / internalFormatInfo.mCompressedBlockWidth; + GLsizei numBlocksHight = (height + internalFormatInfo.mCompressedBlockHeight - 1) / internalFormatInfo.mCompressedBlockHeight; + + return (internalFormatInfo.mPixelBits * numBlocksWide * numBlocksHight) / 8; + } + else + { + TypeInfo typeInfo; + if (GetTypeInfo(type, &typeInfo)) + { + if (typeInfo.mSpecialInterpretation) + { + return typeInfo.mTypeBytes * width * height; + } + else + { + return internalFormatInfo.mComponentCount * typeInfo.mTypeBytes * width * height; + } + } + else + { + UNREACHABLE(); + return 0; + } + } + } + else + { + UNREACHABLE(); + return 0; + } +} + +bool IsFormatCompressed(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mIsCompressed; + } + else + { + UNREACHABLE(); + return false; + } +} + +GLuint GetCompressedBlockWidth(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mCompressedBlockWidth; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetCompressedBlockHeight(GLenum internalFormat) +{ + InternalFormatInfo internalFormatInfo; + if (GetInternalFormatInfo(internalFormat, &internalFormatInfo)) + { + return internalFormatInfo.mCompressedBlockHeight; + } + else + { + UNREACHABLE(); + return 0; + } +} + +const FormatSet &GetAllSizedInternalFormats() +{ + static FormatSet formatSet = BuildAllSizedInternalFormatSet(); + return formatSet; +} + +ColorWriteFunction GetColorWriteFunction(GLenum format, GLenum type) +{ + static const FormatMap &formats = GetFormatMap(); + FormatMap::const_iterator iter = formats.find(FormatTypePair(format, type)); + return (iter != formats.end()) ? iter->second.mColorWriteFunction : NULL; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/formatutils.h b/src/3rdparty/angle/src/libGLESv2/formatutils.h new file mode 100644 index 0000000000..2f592798b8 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/formatutils.h @@ -0,0 +1,88 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils.h: Queries for GL image formats. + +#ifndef LIBGLESV2_FORMATUTILS_H_ +#define LIBGLESV2_FORMATUTILS_H_ + +#include "angle_gl.h" + +#include "libGLESv2/Caps.h" +#include "libGLESv2/angletypes.h" + +#include <cstddef> + +typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); + +typedef void (*LoadImageFunction)(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +typedef void (*InitializeTextureDataFunction)(size_t width, size_t height, size_t depth, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +typedef void (*ColorReadFunction)(const void *source, void *dest); +typedef void (*ColorWriteFunction)(const void *source, void *dest); +typedef void (*ColorCopyFunction)(const void *source, void *dest); + +typedef void (*VertexCopyFunction)(const void *input, size_t stride, size_t count, void *output); + +namespace gl +{ + +typedef std::set<GLenum> FormatSet; + +bool IsValidInternalFormat(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion); +bool IsValidFormat(GLenum format, const Extensions &extensions, GLuint clientVersion); +bool IsValidType(GLenum type, const Extensions &extensions, GLuint clientVersion); + +bool IsValidFormatCombination(GLenum internalFormat, GLenum format, GLenum type, const Extensions &extensions, GLuint clientVersion); +bool IsValidCopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle, GLuint clientVersion); + +bool IsRenderingSupported(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion); +bool IsFilteringSupported(GLenum internalFormat, const Extensions &extensions, GLuint clientVersion); + +bool IsSizedInternalFormat(GLenum internalFormat); +GLenum GetSizedInternalFormat(GLenum format, GLenum type); + +GLuint GetPixelBytes(GLenum internalFormat); +GLuint GetAlphaBits(GLenum internalFormat); +GLuint GetRedBits(GLenum internalFormat); +GLuint GetGreenBits(GLenum internalFormat); +GLuint GetBlueBits(GLenum internalFormat); +GLuint GetLuminanceBits(GLenum internalFormat); +GLuint GetDepthBits(GLenum internalFormat); +GLuint GetStencilBits(GLenum internalFormat); + +GLuint GetTypeBytes(GLenum type); +bool IsSpecialInterpretationType(GLenum type); +bool IsFloatOrFixedComponentType(GLenum type); + +GLenum GetFormat(GLenum internalFormat); +GLenum GetType(GLenum internalFormat); + +GLenum GetComponentType(GLenum internalFormat); +GLuint GetComponentCount(GLenum internalFormat); +GLenum GetColorEncoding(GLenum internalFormat); + +GLuint GetRowPitch(GLenum internalFormat, GLenum type, GLsizei width, GLint alignment); +GLuint GetDepthPitch(GLenum internalFormat, GLenum type, GLsizei width, GLsizei height, GLint alignment); +GLuint GetBlockSize(GLenum internalFormat, GLenum type, GLsizei width, GLsizei height); + +bool IsFormatCompressed(GLenum internalFormat); +GLuint GetCompressedBlockWidth(GLenum internalFormat); +GLuint GetCompressedBlockHeight(GLenum internalFormat); + +const FormatSet &GetAllSizedInternalFormats(); + +ColorWriteFunction GetColorWriteFunction(GLenum format, GLenum type); + +} + +#endif // LIBGLESV2_FORMATUTILS_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp index 814dfbf965..5e2ec4a4ee 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,7 +10,8 @@ #include "common/version.h" #include "libGLESv2/main.h" -#include "libGLESv2/utilities.h" +#include "common/utilities.h" +#include "libGLESv2/formatutils.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/Fence.h" #include "libGLESv2/Framebuffer.h" @@ -20,345 +21,94 @@ #include "libGLESv2/Texture.h" #include "libGLESv2/Query.h" #include "libGLESv2/Context.h" +#include "libGLESv2/VertexArray.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/TransformFeedback.h" +#include "libGLESv2/FramebufferAttachment.h" -bool validImageSize(GLint level, GLsizei width, GLsizei height) -{ - if (level < 0 || width < 0 || height < 0) - { - return false; - } - - if (gl::getContext() && gl::getContext()->supportsNonPower2Texture()) - { - return true; - } - - if (level == 0) - { - return true; - } - - if (gl::isPow2(width) && gl::isPow2(height)) - { - return true; - } - - return false; -} +#include "libGLESv2/validationES.h" +#include "libGLESv2/validationES2.h" +#include "libGLESv2/validationES3.h" +#include "libGLESv2/queryconversions.h" -// Verify that format/type are one of the combinations from table 3.4. -bool checkTextureFormatType(GLenum format, GLenum type) -{ - // validate <format> by itself (used as secondary key below) - switch (format) - { - case GL_RGBA: - case GL_BGRA_EXT: - case GL_RGB: - case GL_ALPHA: - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - case GL_DEPTH_COMPONENT: - case GL_DEPTH_STENCIL_OES: - break; - default: - return gl::error(GL_INVALID_ENUM, false); - } - - // invalid <type> -> sets INVALID_ENUM - // invalid <format>+<type> combination -> sets INVALID_OPERATION - switch (type) - { - case GL_UNSIGNED_BYTE: - switch (format) - { - case GL_RGBA: - case GL_BGRA_EXT: - case GL_RGB: - case GL_ALPHA: - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - return true; - default: - return gl::error(GL_INVALID_OPERATION, false); - } - - case GL_FLOAT: - case GL_HALF_FLOAT_OES: - switch (format) - { - case GL_RGBA: - case GL_RGB: - case GL_ALPHA: - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - return true; - default: - return gl::error(GL_INVALID_OPERATION, false); - } - - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_5_5_5_1: - switch (format) - { - case GL_RGBA: - return true; - default: - return gl::error(GL_INVALID_OPERATION, false); - } - - case GL_UNSIGNED_SHORT_5_6_5: - switch (format) - { - case GL_RGB: - return true; - default: - return gl::error(GL_INVALID_OPERATION, false); - } - - case GL_UNSIGNED_SHORT: - case GL_UNSIGNED_INT: - switch (format) - { - case GL_DEPTH_COMPONENT: - return true; - default: - return gl::error(GL_INVALID_OPERATION, false); - } - - case GL_UNSIGNED_INT_24_8_OES: - switch (format) - { - case GL_DEPTH_STENCIL_OES: - return true; - default: - return gl::error(GL_INVALID_OPERATION, false); - } - - default: - return gl::error(GL_INVALID_ENUM, false); - } -} - -bool validateSubImageParams2D(bool compressed, GLsizei width, GLsizei height, - GLint xoffset, GLint yoffset, GLint level, GLenum format, GLenum type, - gl::Texture2D *texture) +extern "C" { - if (!texture) - { - return gl::error(GL_INVALID_OPERATION, false); - } - - if (compressed != texture->isCompressed(level)) - { - return gl::error(GL_INVALID_OPERATION, false); - } - - if (format != GL_NONE) - { - GLenum internalformat = gl::ConvertSizedInternalFormat(format, type); - if (internalformat != texture->getInternalFormat(level)) - { - return gl::error(GL_INVALID_OPERATION, false); - } - } - if (compressed) - { - if ((width % 4 != 0 && width != texture->getWidth(0)) || - (height % 4 != 0 && height != texture->getHeight(0))) - { - return gl::error(GL_INVALID_OPERATION, false); - } - } +// OpenGL ES 2.0 functions - if (xoffset + width > texture->getWidth(level) || - yoffset + height > texture->getHeight(level)) - { - return gl::error(GL_INVALID_VALUE, false); - } - - return true; -} - -bool validateSubImageParamsCube(bool compressed, GLsizei width, GLsizei height, - GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, GLenum type, - gl::TextureCubeMap *texture) +void __stdcall glActiveTexture(GLenum texture) { - if (!texture) - { - return gl::error(GL_INVALID_OPERATION, false); - } - - if (compressed != texture->isCompressed(target, level)) - { - return gl::error(GL_INVALID_OPERATION, false); - } + EVENT("(GLenum texture = 0x%X)", texture); - if (format != GL_NONE) - { - GLenum internalformat = gl::ConvertSizedInternalFormat(format, type); - if (internalformat != texture->getInternalFormat(target, level)) - { - return gl::error(GL_INVALID_OPERATION, false); - } - } + gl::Context *context = gl::getNonLostContext(); - if (compressed) + if (context) { - if ((width % 4 != 0 && width != texture->getWidth(target, 0)) || - (height % 4 != 0 && height != texture->getHeight(target, 0))) + if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getMaximumCombinedTextureImageUnits() - 1) { - return gl::error(GL_INVALID_OPERATION, false); + return gl::error(GL_INVALID_ENUM); } - } - if (xoffset + width > texture->getWidth(target, level) || - yoffset + height > texture->getHeight(target, level)) - { - return gl::error(GL_INVALID_VALUE, false); + context->getState().setActiveSampler(texture - GL_TEXTURE0); } - - return true; } -// check for combinations of format and type that are valid for ReadPixels -bool validReadFormatType(GLenum format, GLenum type) -{ - switch (format) - { - case GL_RGBA: - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - return false; - } - break; - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: - case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: - break; - default: - return false; - } - break; - default: - return false; - } - return true; -} - -extern "C" +void __stdcall glAttachShader(GLuint program, GLuint shader) { + EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); -void __stdcall glActiveTexture(GLenum texture) -{ - EVENT("(GLenum texture = 0x%X)", texture); + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); + gl::Shader *shaderObject = context->getShader(shader); - if (context) + if (!programObject) { - if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getMaximumCombinedTextureImageUnits() - 1) + if (context->getShader(program)) { - return gl::error(GL_INVALID_ENUM); + return gl::error(GL_INVALID_OPERATION); + } + else + { + return gl::error(GL_INVALID_VALUE); } - - context->setActiveSampler(texture - GL_TEXTURE0); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } -} - -void __stdcall glAttachShader(GLuint program, GLuint shader) -{ - EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); - try - { - gl::Context *context = gl::getNonLostContext(); - - if (context) + if (!shaderObject) { - gl::Program *programObject = context->getProgram(program); - gl::Shader *shaderObject = context->getShader(shader); - - if (!programObject) + if (context->getProgram(shader)) { - if (context->getShader(program)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_OPERATION); } - - if (!shaderObject) + else { - if (context->getProgram(shader)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); } + } - if (!programObject->attachShader(shaderObject)) - { - return gl::error(GL_INVALID_OPERATION); - } + if (!programObject->attachShader(shaderObject)) + { + return gl::error(GL_INVALID_OPERATION); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glBeginQueryEXT(GLenum target, GLuint id) { EVENT("(GLenum target = 0x%X, GLuint %d)", target, id); - try - { - switch (target) - { - case GL_ANY_SAMPLES_PASSED_EXT: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - break; - default: - return gl::error(GL_INVALID_ENUM); - } + gl::Context *context = gl::getNonLostContext(); - if (id == 0) + if (context) + { + if (!ValidateBeginQuery(context, target, id)) { - return gl::error(GL_INVALID_OPERATION); + return; } - gl::Context *context = gl::getNonLostContext(); - - if (context) - { - context->beginQuery(target, id); - } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + context->beginQuery(target, id); } } @@ -366,42 +116,35 @@ void __stdcall glBindAttribLocation(GLuint program, GLuint index, const GLchar* { EVENT("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name); - try + if (index >= gl::MAX_VERTEX_ATTRIBS) { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Program *programObject = context->getProgram(program); + if (context) + { + gl::Program *programObject = context->getProgram(program); - if (!programObject) + if (!programObject) + { + if (context->getShader(program)) { - if (context->getShader(program)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_OPERATION); } - - if (strncmp(name, "gl_", 3) == 0) + else { - return gl::error(GL_INVALID_OPERATION); + return gl::error(GL_INVALID_VALUE); } + } - programObject->bindAttributeLocation(index, name); + if (strncmp(name, "gl_", 3) == 0) + { + return gl::error(GL_INVALID_OPERATION); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + programObject->bindAttributeLocation(index, name); } } @@ -409,84 +152,86 @@ void __stdcall glBindBuffer(GLenum target, GLuint buffer) { EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + if (!gl::ValidBufferTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM); + } - if (context) + switch (target) { - switch (target) - { - case GL_ARRAY_BUFFER: - context->bindArrayBuffer(buffer); - return; - case GL_ELEMENT_ARRAY_BUFFER: - context->bindElementArrayBuffer(buffer); - return; - default: - return gl::error(GL_INVALID_ENUM); - } + case GL_ARRAY_BUFFER: + context->bindArrayBuffer(buffer); + return; + case GL_ELEMENT_ARRAY_BUFFER: + context->bindElementArrayBuffer(buffer); + return; + case GL_COPY_READ_BUFFER: + context->bindCopyReadBuffer(buffer); + return; + case GL_COPY_WRITE_BUFFER: + context->bindCopyWriteBuffer(buffer); + return; + case GL_PIXEL_PACK_BUFFER: + context->bindPixelPackBuffer(buffer); + return; + case GL_PIXEL_UNPACK_BUFFER: + context->bindPixelUnpackBuffer(buffer); + return; + case GL_UNIFORM_BUFFER: + context->bindGenericUniformBuffer(buffer); + return; + case GL_TRANSFORM_FEEDBACK_BUFFER: + context->bindGenericTransformFeedbackBuffer(buffer); + return; + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer) { EVENT("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer); - try + if (!gl::ValidFramebufferTarget(target)) { - if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + return gl::error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) { - return gl::error(GL_INVALID_ENUM); + context->bindReadFramebuffer(framebuffer); } - gl::Context *context = gl::getNonLostContext(); - - if (context) + if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) { - if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) - { - context->bindReadFramebuffer(framebuffer); - } - - if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) - { - context->bindDrawFramebuffer(framebuffer); - } + context->bindDrawFramebuffer(framebuffer); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer) { EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer); - try + if (target != GL_RENDERBUFFER) { - if (target != GL_RENDERBUFFER) - { - return gl::error(GL_INVALID_ENUM); - } + return gl::error(GL_INVALID_ENUM); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->bindRenderbuffer(renderbuffer); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->bindRenderbuffer(renderbuffer); } } @@ -494,36 +239,43 @@ void __stdcall glBindTexture(GLenum target, GLuint texture) { EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::Texture *textureObject = context->getTexture(texture); - if (context) + if (textureObject && textureObject->getTarget() != target && texture != 0) { - gl::Texture *textureObject = context->getTexture(texture); + return gl::error(GL_INVALID_OPERATION); + } - if (textureObject && textureObject->getTarget() != target && texture != 0) + switch (target) + { + case GL_TEXTURE_2D: + context->bindTexture2D(texture); + return; + case GL_TEXTURE_CUBE_MAP: + context->bindTextureCubeMap(texture); + return; + case GL_TEXTURE_3D: + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_OPERATION); + return gl::error(GL_INVALID_ENUM); } - - switch (target) + context->bindTexture3D(texture); + return; + case GL_TEXTURE_2D_ARRAY: + if (context->getClientVersion() < 3) { - case GL_TEXTURE_2D: - context->bindTexture2D(texture); - return; - case GL_TEXTURE_CUBE_MAP: - context->bindTextureCubeMap(texture); - return; - default: return gl::error(GL_INVALID_ENUM); } + context->bindTexture2DArray(texture); + return; + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) @@ -531,18 +283,11 @@ void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclamp EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", red, green, blue, alpha); - try - { - gl::Context* context = gl::getNonLostContext(); + gl::Context* context = gl::getNonLostContext(); - if (context) - { - context->setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha)); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha)); } } @@ -555,38 +300,37 @@ void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha); - try + gl::Context *context = gl::getNonLostContext(); + + switch (modeRGB) { - switch (modeRGB) - { - case GL_FUNC_ADD: - case GL_FUNC_SUBTRACT: - case GL_FUNC_REVERSE_SUBTRACT: - break; - default: - return gl::error(GL_INVALID_ENUM); - } + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + case GL_MIN: + case GL_MAX: + break; - switch (modeAlpha) - { - case GL_FUNC_ADD: - case GL_FUNC_SUBTRACT: - case GL_FUNC_REVERSE_SUBTRACT: - break; - default: - return gl::error(GL_INVALID_ENUM); - } + default: + return gl::error(GL_INVALID_ENUM); + } - gl::Context *context = gl::getNonLostContext(); + switch (modeAlpha) + { + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + case GL_MIN: + case GL_MAX: + break; - if (context) - { - context->setBlendEquation(modeRGB, modeAlpha); - } + default: + return gl::error(GL_INVALID_ENUM); } - catch(std::bad_alloc&) + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setBlendEquation(modeRGB, modeAlpha); } } @@ -600,116 +344,125 @@ void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha EVENT("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)", srcRGB, dstRGB, srcAlpha, dstAlpha); - try - { - switch (srcRGB) - { - case GL_ZERO: - case GL_ONE: - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - case GL_SRC_ALPHA_SATURATE: - break; - default: - return gl::error(GL_INVALID_ENUM); - } + gl::Context *context = gl::getNonLostContext(); + + switch (srcRGB) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + case GL_SRC_ALPHA_SATURATE: + break; + default: + return gl::error(GL_INVALID_ENUM); + } - switch (dstRGB) + switch (dstRGB) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + break; + + case GL_SRC_ALPHA_SATURATE: + if (!context || context->getClientVersion() < 3) { - case GL_ZERO: - case GL_ONE: - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - break; - default: return gl::error(GL_INVALID_ENUM); } + break; - switch (srcAlpha) - { - case GL_ZERO: - case GL_ONE: - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - case GL_SRC_ALPHA_SATURATE: - break; - default: - return gl::error(GL_INVALID_ENUM); - } + default: + return gl::error(GL_INVALID_ENUM); + } + + switch (srcAlpha) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + case GL_SRC_ALPHA_SATURATE: + break; + default: + return gl::error(GL_INVALID_ENUM); + } + + switch (dstAlpha) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + break; - switch (dstAlpha) + case GL_SRC_ALPHA_SATURATE: + if (!context || context->getClientVersion() < 3) { - case GL_ZERO: - case GL_ONE: - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - break; - default: return gl::error(GL_INVALID_ENUM); } + break; - bool constantColorUsed = (srcRGB == GL_CONSTANT_COLOR || srcRGB == GL_ONE_MINUS_CONSTANT_COLOR || - dstRGB == GL_CONSTANT_COLOR || dstRGB == GL_ONE_MINUS_CONSTANT_COLOR); - - bool constantAlphaUsed = (srcRGB == GL_CONSTANT_ALPHA || srcRGB == GL_ONE_MINUS_CONSTANT_ALPHA || - dstRGB == GL_CONSTANT_ALPHA || dstRGB == GL_ONE_MINUS_CONSTANT_ALPHA); + default: + return gl::error(GL_INVALID_ENUM); + } - if (constantColorUsed && constantAlphaUsed) - { - ERR("Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA and GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR invalid under WebGL"); - return gl::error(GL_INVALID_OPERATION); - } + bool constantColorUsed = (srcRGB == GL_CONSTANT_COLOR || srcRGB == GL_ONE_MINUS_CONSTANT_COLOR || + dstRGB == GL_CONSTANT_COLOR || dstRGB == GL_ONE_MINUS_CONSTANT_COLOR); - gl::Context *context = gl::getNonLostContext(); + bool constantAlphaUsed = (srcRGB == GL_CONSTANT_ALPHA || srcRGB == GL_ONE_MINUS_CONSTANT_ALPHA || + dstRGB == GL_CONSTANT_ALPHA || dstRGB == GL_ONE_MINUS_CONSTANT_ALPHA); - if (context) - { - context->setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha); - } + if (constantColorUsed && constantAlphaUsed) + { + ERR("Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA and GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR invalid under WebGL"); + return gl::error(GL_INVALID_OPERATION); } - catch(std::bad_alloc&) + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha); } } @@ -718,52 +471,51 @@ void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, EVENT("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)", target, size, data, usage); - try + if (size < 0) { - if (size < 0) + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + switch (usage) + { + case GL_STREAM_DRAW: + case GL_STATIC_DRAW: + case GL_DYNAMIC_DRAW: + break; + + case GL_STREAM_READ: + case GL_STREAM_COPY: + case GL_STATIC_READ: + case GL_STATIC_COPY: + case GL_DYNAMIC_READ: + case GL_DYNAMIC_COPY: + if (context && context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_ENUM); } + break; - switch (usage) + default: + return gl::error(GL_INVALID_ENUM); + } + + if (context) + { + if (!gl::ValidBufferTarget(context, target)) { - case GL_STREAM_DRAW: - case GL_STATIC_DRAW: - case GL_DYNAMIC_DRAW: - break; - default: return gl::error(GL_INVALID_ENUM); } - gl::Context *context = gl::getNonLostContext(); + gl::Buffer *buffer = context->getState().getTargetBuffer(target); - if (context) + if (!buffer) { - gl::Buffer *buffer; - - switch (target) - { - case GL_ARRAY_BUFFER: - buffer = context->getArrayBuffer(); - break; - case GL_ELEMENT_ARRAY_BUFFER: - buffer = context->getElementArrayBuffer(); - break; - default: - return gl::error(GL_INVALID_ENUM); - } - - if (!buffer) - { - return gl::error(GL_INVALID_OPERATION); - } - - buffer->bufferData(data, size, usage); + return gl::error(GL_INVALID_OPERATION); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + buffer->bufferData(data, size, usage); } } @@ -772,52 +524,49 @@ void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)", target, offset, size, data); - try + if (size < 0 || offset < 0) { - if (size < 0 || offset < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - if (data == NULL) + if (data == NULL) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!gl::ValidBufferTarget(context, target)) { - return; + return gl::error(GL_INVALID_ENUM); } - gl::Context *context = gl::getNonLostContext(); + gl::Buffer *buffer = context->getState().getTargetBuffer(target); - if (context) + if (!buffer) { - gl::Buffer *buffer; - - switch (target) - { - case GL_ARRAY_BUFFER: - buffer = context->getArrayBuffer(); - break; - case GL_ELEMENT_ARRAY_BUFFER: - buffer = context->getElementArrayBuffer(); - break; - default: - return gl::error(GL_INVALID_ENUM); - } + return gl::error(GL_INVALID_OPERATION); + } - if (!buffer) - { - return gl::error(GL_INVALID_OPERATION); - } + if (buffer->isMapped()) + { + return gl::error(GL_INVALID_OPERATION); + } - if ((size_t)size + offset > buffer->size()) - { - return gl::error(GL_INVALID_VALUE); - } + // Check for possible overflow of size + offset + if (!rx::IsUnsignedAdditionSafe<size_t>(size, offset)) + { + return gl::error(GL_OUT_OF_MEMORY); + } - buffer->bufferSubData(data, size, offset); + if (size + offset > buffer->getSize()) + { + return gl::error(GL_INVALID_VALUE); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + buffer->bufferSubData(data, size, offset); } } @@ -825,33 +574,18 @@ GLenum __stdcall glCheckFramebufferStatus(GLenum target) { EVENT("(GLenum target = 0x%X)", target); - try + if (!gl::ValidFramebufferTarget(target)) { - if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) - { - return gl::error(GL_INVALID_ENUM, 0); - } - - gl::Context *context = gl::getNonLostContext(); + return gl::error(GL_INVALID_ENUM, 0); + } - if (context) - { - gl::Framebuffer *framebuffer = NULL; - if (target == GL_READ_FRAMEBUFFER_ANGLE) - { - framebuffer = context->getReadFramebuffer(); - } - else - { - framebuffer = context->getDrawFramebuffer(); - } + gl::Context *context = gl::getNonLostContext(); - return framebuffer->completeness(); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY, 0); + gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); + return framebuffer->completeness(); } return 0; @@ -859,20 +593,25 @@ GLenum __stdcall glCheckFramebufferStatus(GLenum target) void __stdcall glClear(GLbitfield mask) { - EVENT("(GLbitfield mask = %X)", mask); + EVENT("(GLbitfield mask = 0x%X)", mask); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::Framebuffer *framebufferObject = context->getState().getDrawFramebuffer(); - if (context) + if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) { - context->clear(mask); + return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) + { + return gl::error(GL_INVALID_VALUE); + } + + context->clear(mask); } } @@ -881,18 +620,11 @@ void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclamp EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", red, green, blue, alpha); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setClearColor(red, green, blue, alpha); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setClearColor(red, green, blue, alpha); } } @@ -900,18 +632,11 @@ void __stdcall glClearDepthf(GLclampf depth) { EVENT("(GLclampf depth = %f)", depth); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setClearDepth(depth); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setClearDepth(depth); } } @@ -919,38 +644,24 @@ void __stdcall glClearStencil(GLint s) { EVENT("(GLint s = %d)", s); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setClearStencil(s); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setClearStencil(s); } } void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { - EVENT("(GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d)", + EVENT("(GLboolean red = %d, GLboolean green = %u, GLboolean blue = %u, GLboolean alpha = %u)", red, green, blue, alpha); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE); } } @@ -958,191 +669,82 @@ void __stdcall glCompileShader(GLuint shader) { EVENT("(GLuint shader = %d)", shader); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::Shader *shaderObject = context->getShader(shader); - if (context) + if (!shaderObject) { - gl::Shader *shaderObject = context->getShader(shader); - - if (!shaderObject) + if (context->getProgram(shader)) { - if (context->getProgram(shader)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_OPERATION); + } + else + { + return gl::error(GL_INVALID_VALUE); } - - shaderObject->compile(); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + shaderObject->compile(); } } -void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, +void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) { - EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " + EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " "GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", target, level, internalformat, width, height, border, imageSize, data); - try - { - if (!validImageSize(level, width, height) || border != 0 || imageSize < 0) - { - return gl::error(GL_INVALID_VALUE); - } - - switch (internalformat) - { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - break; - default: - return gl::error(GL_INVALID_ENUM); - } + gl::Context *context = gl::getNonLostContext(); - if (border != 0) + if (context) + { + if (context->getClientVersion() < 3 && + !ValidateES2TexImageParameters(context, target, level, internalformat, true, false, + 0, 0, width, height, border, GL_NONE, GL_NONE, data)) { - return gl::error(GL_INVALID_OPERATION); + return; } - if (width != 1 && width != 2 && width % 4 != 0) + if (context->getClientVersion() >= 3 && + !ValidateES3TexImageParameters(context, target, level, internalformat, true, false, + 0, 0, 0, width, height, 1, border, GL_NONE, GL_NONE, data)) { - return gl::error(GL_INVALID_OPERATION); + return; } - if (height != 1 && height != 2 && height % 4 != 0) + if (imageSize < 0 || imageSize != (GLsizei)gl::GetBlockSize(internalformat, GL_UNSIGNED_BYTE, width, height)) { - return gl::error(GL_INVALID_OPERATION); + return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); - - if (context) + switch (target) { - if (level > context->getMaximumTextureLevel()) - { - return gl::error(GL_INVALID_VALUE); - } - - switch (target) - { - case GL_TEXTURE_2D: - if (width > (context->getMaximumTextureDimension() >> level) || - height > (context->getMaximumTextureDimension() >> level)) - { - return gl::error(GL_INVALID_VALUE); - } - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - if (width != height) - { - return gl::error(GL_INVALID_VALUE); - } - - if (width > (context->getMaximumCubeTextureDimension() >> level) || - height > (context->getMaximumCubeTextureDimension() >> level)) - { - return gl::error(GL_INVALID_VALUE); - } - break; - default: - return gl::error(GL_INVALID_ENUM); - } - - switch (internalformat) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (!context->supportsDXT1Textures()) - { - return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (!context->supportsDXT3Textures()) - { - return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (!context->supportsDXT5Textures()) - { - return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed - } - break; - default: UNREACHABLE(); - } - - if (imageSize != gl::ComputeCompressedSize(width, height, internalformat)) - { - return gl::error(GL_INVALID_VALUE); - } - - if (target == GL_TEXTURE_2D) + case GL_TEXTURE_2D: { gl::Texture2D *texture = context->getTexture2D(); - - if (!texture) - { - return gl::error(GL_INVALID_OPERATION); - } - - if (texture->isImmutable()) - { - return gl::error(GL_INVALID_OPERATION); - } - texture->setCompressedImage(level, internalformat, width, height, imageSize, data); } - else + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { gl::TextureCubeMap *texture = context->getTextureCubeMap(); - - if (!texture) - { - return gl::error(GL_INVALID_OPERATION); - } - - if (texture->isImmutable()) - { - return gl::error(GL_INVALID_OPERATION); - } - - switch (target) - { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data); - break; - default: UNREACHABLE(); - } + texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data); } - } + break; - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + default: + return gl::error(GL_INVALID_ENUM); + } } } @@ -1154,103 +756,54 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs "GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", target, level, xoffset, yoffset, width, height, format, imageSize, data); - try - { - if (!gl::IsInternalTextureTarget(target)) - { - return gl::error(GL_INVALID_ENUM); - } + gl::Context *context = gl::getNonLostContext(); - if (xoffset < 0 || yoffset < 0 || !validImageSize(level, width, height) || imageSize < 0) + if (context) + { + if (context->getClientVersion() < 3 && + !ValidateES2TexImageParameters(context, target, level, GL_NONE, true, true, + xoffset, yoffset, width, height, 0, GL_NONE, GL_NONE, data)) { - return gl::error(GL_INVALID_VALUE); + return; } - switch (format) + if (context->getClientVersion() >= 3 && + !ValidateES3TexImageParameters(context, target, level, GL_NONE, true, true, + xoffset, yoffset, 0, width, height, 1, 0, GL_NONE, GL_NONE, data)) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - break; - default: - return gl::error(GL_INVALID_ENUM); + return; } - if (width == 0 || height == 0 || data == NULL) + if (imageSize < 0 || imageSize != (GLsizei)gl::GetBlockSize(format, GL_UNSIGNED_BYTE, width, height)) { - return; + return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); - - if (context) + switch (target) { - if (level > context->getMaximumTextureLevel()) - { - return gl::error(GL_INVALID_VALUE); - } - - switch (format) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (!context->supportsDXT1Textures()) - { - return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (!context->supportsDXT3Textures()) - { - return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (!context->supportsDXT5Textures()) - { - return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed - } - break; - default: UNREACHABLE(); - } - - if (imageSize != gl::ComputeCompressedSize(width, height, format)) - { - return gl::error(GL_INVALID_VALUE); - } - - if (xoffset % 4 != 0 || yoffset % 4 != 0) - { - return gl::error(GL_INVALID_OPERATION); // we wait to check the offsets until this point, because the multiple-of-four restriction - // does not exist unless DXT textures are supported. - } - - if (target == GL_TEXTURE_2D) + case GL_TEXTURE_2D: { gl::Texture2D *texture = context->getTexture2D(); - if (validateSubImageParams2D(true, width, height, xoffset, yoffset, level, format, GL_NONE, texture)) - { - texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data); - } + texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data); } - else if (gl::IsCubemapTextureTarget(target)) + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { gl::TextureCubeMap *texture = context->getTextureCubeMap(); - if (validateSubImageParamsCube(true, width, height, xoffset, yoffset, target, level, format, GL_NONE, texture)) - { - texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data); - } - } - else - { - UNREACHABLE(); + texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data); } + break; + + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) @@ -1259,194 +812,51 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)", target, level, internalformat, x, y, width, height, border); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (!validImageSize(level, width, height)) + if (context->getClientVersion() < 3 && + !ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, + 0, 0, x, y, width, height, border)) { - return gl::error(GL_INVALID_VALUE); + return; } - if (border != 0) + if (context->getClientVersion() >= 3 && + !ValidateES3CopyTexImageParameters(context, target, level, internalformat, false, + 0, 0, 0, x, y, width, height, border)) { - return gl::error(GL_INVALID_VALUE); + return; } - gl::Context *context = gl::getNonLostContext(); + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - if (context) + switch (target) { - if (level > context->getMaximumTextureLevel()) - { - return gl::error(GL_INVALID_VALUE); - } - - switch (target) - { - case GL_TEXTURE_2D: - if (width > (context->getMaximumTextureDimension() >> level) || - height > (context->getMaximumTextureDimension() >> level)) - { - return gl::error(GL_INVALID_VALUE); - } - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - if (width != height) - { - return gl::error(GL_INVALID_VALUE); - } - - if (width > (context->getMaximumCubeTextureDimension() >> level) || - height > (context->getMaximumCubeTextureDimension() >> level)) - { - return gl::error(GL_INVALID_VALUE); - } - break; - default: - return gl::error(GL_INVALID_ENUM); - } - - gl::Framebuffer *framebuffer = context->getReadFramebuffer(); - - if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) - { - return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION); - } - - if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0) - { - return gl::error(GL_INVALID_OPERATION); - } - - gl::Renderbuffer *source = framebuffer->getReadColorbuffer(); - GLenum colorbufferFormat = source->getInternalFormat(); - - // [OpenGL ES 2.0.24] table 3.9 - switch (internalformat) - { - case GL_ALPHA: - if (colorbufferFormat != GL_ALPHA8_EXT && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES) - { - return gl::error(GL_INVALID_OPERATION); - } - break; - case GL_LUMINANCE: - case GL_RGB: - if (colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES) - { - return gl::error(GL_INVALID_OPERATION); - } - break; - case GL_LUMINANCE_ALPHA: - case GL_RGBA: - if (colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES) - { - return gl::error(GL_INVALID_OPERATION); - } - break; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (context->supportsDXT1Textures()) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (context->supportsDXT3Textures()) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (context->supportsDXT5Textures()) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT32_OES: - case GL_DEPTH_STENCIL_OES: - case GL_DEPTH24_STENCIL8_OES: - if (context->supportsDepthTextures()) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_ENUM); - } - default: - return gl::error(GL_INVALID_ENUM); - } - - if (target == GL_TEXTURE_2D) + case GL_TEXTURE_2D: { gl::Texture2D *texture = context->getTexture2D(); - - if (!texture) - { - return gl::error(GL_INVALID_OPERATION); - } - - if (texture->isImmutable()) - { - return gl::error(GL_INVALID_OPERATION); - } - texture->copyImage(level, internalformat, x, y, width, height, framebuffer); } - else if (gl::IsCubemapTextureTarget(target)) + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { gl::TextureCubeMap *texture = context->getTextureCubeMap(); - - if (!texture) - { - return gl::error(GL_INVALID_OPERATION); - } - - if (texture->isImmutable()) - { - return gl::error(GL_INVALID_OPERATION); - } - texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer); } - else UNREACHABLE(); + break; + + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) @@ -1455,148 +865,61 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", target, level, xoffset, yoffset, x, y, width, height); - try - { - if (!gl::IsInternalTextureTarget(target)) - { - return gl::error(GL_INVALID_ENUM); - } + gl::Context *context = gl::getNonLostContext(); - if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) + if (context) + { + if (context->getClientVersion() < 3 && + !ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, + xoffset, yoffset, x, y, width, height, 0)) { - return gl::error(GL_INVALID_VALUE); + return; } - if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height) - { - return gl::error(GL_INVALID_VALUE); - } - - if (width == 0 || height == 0) + if (context->getClientVersion() >= 3 && + !ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, + xoffset, yoffset, 0, x, y, width, height, 0)) { return; } - gl::Context *context = gl::getNonLostContext(); + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - if (context) + switch (target) { - if (level > context->getMaximumTextureLevel()) - { - return gl::error(GL_INVALID_VALUE); - } - - gl::Framebuffer *framebuffer = context->getReadFramebuffer(); - - if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) - { - return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION); - } - - if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0) + case GL_TEXTURE_2D: { - return gl::error(GL_INVALID_OPERATION); - } - - gl::Renderbuffer *source = framebuffer->getReadColorbuffer(); - GLenum colorbufferFormat = source->getInternalFormat(); - gl::Texture *texture = NULL; - GLenum textureFormat = GL_RGBA; - - if (target == GL_TEXTURE_2D) - { - gl::Texture2D *tex2d = context->getTexture2D(); - - if (!validateSubImageParams2D(false, width, height, xoffset, yoffset, level, GL_NONE, GL_NONE, tex2d)) - { - return; // error already registered by validateSubImageParams - } - textureFormat = gl::ExtractFormat(tex2d->getInternalFormat(level)); - texture = tex2d; - } - else if (gl::IsCubemapTextureTarget(target)) - { - gl::TextureCubeMap *texcube = context->getTextureCubeMap(); - - if (!validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, GL_NONE, GL_NONE, texcube)) - { - return; // error already registered by validateSubImageParams - } - textureFormat = gl::ExtractFormat(texcube->getInternalFormat(target, level)); - texture = texcube; + gl::Texture2D *texture = context->getTexture2D(); + texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer); } - else UNREACHABLE(); + break; - // [OpenGL ES 2.0.24] table 3.9 - switch (textureFormat) + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { - case GL_ALPHA: - if (colorbufferFormat != GL_ALPHA8_EXT && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES) - { - return gl::error(GL_INVALID_OPERATION); - } - break; - case GL_LUMINANCE: - case GL_RGB: - if (colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES) - { - return gl::error(GL_INVALID_OPERATION); - } - break; - case GL_LUMINANCE_ALPHA: - case GL_RGBA: - if (colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES) - { - return gl::error(GL_INVALID_OPERATION); - } - break; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - return gl::error(GL_INVALID_OPERATION); - case GL_DEPTH_COMPONENT: - case GL_DEPTH_STENCIL_OES: - return gl::error(GL_INVALID_OPERATION); - default: - return gl::error(GL_INVALID_OPERATION); + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer); } + break; - texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, framebuffer); + default: + return gl::error(GL_INVALID_ENUM); } } - - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } GLuint __stdcall glCreateProgram(void) { EVENT("()"); - try - { - gl::Context *context = gl::getNonLostContext(); - - if (context) - { - return context->createProgram(); - } - } - catch(std::bad_alloc&) + gl::Context *context = gl::getNonLostContext(); + if (context) { - return gl::error(GL_OUT_OF_MEMORY, 0); + return context->createProgram(); } return 0; @@ -1606,26 +929,19 @@ GLuint __stdcall glCreateShader(GLenum type) { EVENT("(GLenum type = 0x%X)", type); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + switch (type) { - switch (type) - { - case GL_FRAGMENT_SHADER: - case GL_VERTEX_SHADER: - return context->createShader(type); - default: - return gl::error(GL_INVALID_ENUM, 0); - } + case GL_FRAGMENT_SHADER: + case GL_VERTEX_SHADER: + return context->createShader(type); + default: + return gl::error(GL_INVALID_ENUM, 0); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, 0); - } return 0; } @@ -1634,29 +950,22 @@ void __stdcall glCullFace(GLenum mode) { EVENT("(GLenum mode = 0x%X)", mode); - try + switch (mode) { - switch (mode) + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setCullMode(mode); - } + if (context) + { + context->getState().setCullMode(mode); } - break; - default: - return gl::error(GL_INVALID_ENUM); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + break; + default: + return gl::error(GL_INVALID_ENUM); } } @@ -1664,119 +973,91 @@ void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers) { EVENT("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers); - try + if (n < 0) { - if (n < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) - { - context->deleteBuffer(buffers[i]); - } + context->deleteBuffer(buffers[i]); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences) { EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences); - try + if (n < 0) { - if (n < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) - { - context->deleteFence(fences[i]); - } + context->deleteFenceNV(fences[i]); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) { EVENT("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers); - try + if (n < 0) { - if (n < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) + if (framebuffers[i] != 0) { - if (framebuffers[i] != 0) - { - context->deleteFramebuffer(framebuffers[i]); - } + context->deleteFramebuffer(framebuffers[i]); } } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glDeleteProgram(GLuint program) { EVENT("(GLuint program = %d)", program); - try + if (program == 0) { - if (program == 0) - { - return; - } + return; + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (!context->getProgram(program)) { - if (!context->getProgram(program)) + if(context->getShader(program)) { - if(context->getShader(program)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_OPERATION); + } + else + { + return gl::error(GL_INVALID_VALUE); } - - context->deleteProgram(program); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + context->deleteProgram(program); } } @@ -1784,89 +1065,68 @@ void __stdcall glDeleteQueriesEXT(GLsizei n, const GLuint *ids) { EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids); - try + if (n < 0) { - if (n < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) - { - context->deleteQuery(ids[i]); - } + context->deleteQuery(ids[i]); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { EVENT("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); - try + if (n < 0) { - if (n < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) - { - context->deleteRenderbuffer(renderbuffers[i]); - } + context->deleteRenderbuffer(renderbuffers[i]); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glDeleteShader(GLuint shader) { EVENT("(GLuint shader = %d)", shader); - try + if (shader == 0) { - if (shader == 0) - { - return; - } + return; + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (!context->getShader(shader)) { - if (!context->getShader(shader)) + if(context->getProgram(shader)) { - if(context->getProgram(shader)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_OPERATION); + } + else + { + return gl::error(GL_INVALID_VALUE); } - - context->deleteShader(shader); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + context->deleteShader(shader); } } @@ -1874,82 +1134,61 @@ void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures) { EVENT("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures); - try + if (n < 0) { - if (n < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) + if (textures[i] != 0) { - if (textures[i] != 0) - { - context->deleteTexture(textures[i]); - } + context->deleteTexture(textures[i]); } } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glDepthFunc(GLenum func) { EVENT("(GLenum func = 0x%X)", func); - try + switch (func) { - switch (func) - { - case GL_NEVER: - case GL_ALWAYS: - case GL_LESS: - case GL_LEQUAL: - case GL_EQUAL: - case GL_GREATER: - case GL_GEQUAL: - case GL_NOTEQUAL: - break; - default: - return gl::error(GL_INVALID_ENUM); - } + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GREATER: + case GL_GEQUAL: + case GL_NOTEQUAL: + break; + default: + return gl::error(GL_INVALID_ENUM); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setDepthFunc(func); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setDepthFunc(func); } } void __stdcall glDepthMask(GLboolean flag) { - EVENT("(GLboolean flag = %d)", flag); + EVENT("(GLboolean flag = %u)", flag); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setDepthMask(flag != GL_FALSE); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setDepthMask(flag != GL_FALSE); } } @@ -1957,18 +1196,11 @@ void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar) { EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setDepthRange(zNear, zFar); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setDepthRange(zNear, zFar); } } @@ -1976,52 +1208,45 @@ void __stdcall glDetachShader(GLuint program, GLuint shader) { EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); - if (context) - { + gl::Program *programObject = context->getProgram(program); + gl::Shader *shaderObject = context->getShader(shader); - gl::Program *programObject = context->getProgram(program); - gl::Shader *shaderObject = context->getShader(shader); - - if (!programObject) + if (!programObject) + { + gl::Shader *shaderByProgramHandle; + shaderByProgramHandle = context->getShader(program); + if (!shaderByProgramHandle) { - gl::Shader *shaderByProgramHandle; - shaderByProgramHandle = context->getShader(program); - if (!shaderByProgramHandle) - { - return gl::error(GL_INVALID_VALUE); - } - else - { - return gl::error(GL_INVALID_OPERATION); - } + return gl::error(GL_INVALID_VALUE); } - - if (!shaderObject) + else { - gl::Program *programByShaderHandle = context->getProgram(shader); - if (!programByShaderHandle) - { - return gl::error(GL_INVALID_VALUE); - } - else - { - return gl::error(GL_INVALID_OPERATION); - } + return gl::error(GL_INVALID_OPERATION); } + } - if (!programObject->detachShader(shaderObject)) + if (!shaderObject) + { + gl::Program *programByShaderHandle = context->getProgram(shader); + if (!programByShaderHandle) + { + return gl::error(GL_INVALID_VALUE); + } + else { return gl::error(GL_INVALID_OPERATION); } } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + if (!programObject->detachShader(shaderObject)) + { + return gl::error(GL_INVALID_OPERATION); + } } } @@ -2029,31 +1254,16 @@ void __stdcall glDisable(GLenum cap) { EVENT("(GLenum cap = 0x%X)", cap); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (!ValidCap(context, cap)) { - switch (cap) - { - case GL_CULL_FACE: context->setCullFace(false); break; - case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFill(false); break; - case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(false); break; - case GL_SAMPLE_COVERAGE: context->setSampleCoverage(false); break; - case GL_SCISSOR_TEST: context->setScissorTest(false); break; - case GL_STENCIL_TEST: context->setStencilTest(false); break; - case GL_DEPTH_TEST: context->setDepthTest(false); break; - case GL_BLEND: context->setBlend(false); break; - case GL_DITHER: context->setDither(false); break; - default: - return gl::error(GL_INVALID_ENUM); - } + return gl::error(GL_INVALID_ENUM); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + context->getState().setEnableFeature(cap, false); } } @@ -2061,23 +1271,16 @@ void __stdcall glDisableVertexAttribArray(GLuint index) { EVENT("(GLuint index = %d)", index); - try + if (index >= gl::MAX_VERTEX_ATTRIBS) { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setEnableVertexAttribArray(index, false); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setEnableVertexAttribArray(index, false); } } @@ -2085,23 +1288,16 @@ void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count) { EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (count < 0 || first < 0) + if (!ValidateDrawArrays(context, mode, first, count)) { - return gl::error(GL_INVALID_VALUE); + return; } - gl::Context *context = gl::getNonLostContext(); - - if (context) - { - context->drawArrays(mode, first, count, 0); - } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + context->drawArrays(mode, first, count, 0); } } @@ -2109,26 +1305,16 @@ void __stdcall glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei coun { EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei primcount = %d)", mode, first, count, primcount); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (count < 0 || first < 0 || primcount < 0) + if (!ValidateDrawArraysInstanced(context, mode, first, count, primcount)) { - return gl::error(GL_INVALID_VALUE); + return; } - if (primcount > 0) - { - gl::Context *context = gl::getNonLostContext(); - - if (context) - { - context->drawArrays(mode, first, count, primcount); - } - } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + context->drawArrays(mode, first, count, primcount); } } @@ -2137,38 +1323,16 @@ void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLv EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)", mode, count, type, indices); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (count < 0) + if (!ValidateDrawElements(context, mode, count, type, indices)) { - return gl::error(GL_INVALID_VALUE); + return; } - gl::Context *context = gl::getNonLostContext(); - - if (context) - { - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT: - break; - case GL_UNSIGNED_INT: - if (!context->supports32bitIndices()) - { - return gl::error(GL_INVALID_ENUM); - } - break; - default: - return gl::error(GL_INVALID_ENUM); - } - - context->drawElements(mode, count, type, indices, 0); - } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + context->drawElements(mode, count, type, indices, 0); } } @@ -2177,41 +1341,16 @@ void __stdcall glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum t EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei primcount = %d)", mode, count, type, indices, primcount); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (count < 0 || primcount < 0) + if (!ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount)) { - return gl::error(GL_INVALID_VALUE); + return; } - if (primcount > 0) - { - gl::Context *context = gl::getNonLostContext(); - - if (context) - { - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT: - break; - case GL_UNSIGNED_INT: - if (!context->supports32bitIndices()) - { - return gl::error(GL_INVALID_ENUM); - } - break; - default: - return gl::error(GL_INVALID_ENUM); - } - - context->drawElements(mode, count, type, indices, primcount); - } - } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + context->drawElements(mode, count, type, indices, primcount); } } @@ -2219,31 +1358,16 @@ void __stdcall glEnable(GLenum cap) { EVENT("(GLenum cap = 0x%X)", cap); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (!ValidCap(context, cap)) { - switch (cap) - { - case GL_CULL_FACE: context->setCullFace(true); break; - case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFill(true); break; - case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(true); break; - case GL_SAMPLE_COVERAGE: context->setSampleCoverage(true); break; - case GL_SCISSOR_TEST: context->setScissorTest(true); break; - case GL_STENCIL_TEST: context->setStencilTest(true); break; - case GL_DEPTH_TEST: context->setDepthTest(true); break; - case GL_BLEND: context->setBlend(true); break; - case GL_DITHER: context->setDither(true); break; - default: - return gl::error(GL_INVALID_ENUM); - } + return gl::error(GL_INVALID_ENUM); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + context->getState().setEnableFeature(cap, true); } } @@ -2251,23 +1375,16 @@ void __stdcall glEnableVertexAttribArray(GLuint index) { EVENT("(GLuint index = %d)", index); - try + if (index >= gl::MAX_VERTEX_ATTRIBS) { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setEnableVertexAttribArray(index, true); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setEnableVertexAttribArray(index, true); } } @@ -2275,27 +1392,16 @@ void __stdcall glEndQueryEXT(GLenum target) { EVENT("GLenum target = 0x%X)", target); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - switch (target) + if (!ValidateEndQuery(context, target)) { - case GL_ANY_SAMPLES_PASSED_EXT: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - break; - default: - return gl::error(GL_INVALID_ENUM); + return; } - gl::Context *context = gl::getNonLostContext(); - - if (context) - { - context->endQuery(target); - } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + context->endQuery(target); } } @@ -2303,25 +1409,23 @@ void __stdcall glFinishFenceNV(GLuint fence) { EVENT("(GLuint fence = %d)", fence); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::FenceNV *fenceObject = context->getFenceNV(fence); - if (context) + if (fenceObject == NULL) { - gl::Fence* fenceObject = context->getFence(fence); - - if (fenceObject == NULL) - { - return gl::error(GL_INVALID_OPERATION); - } + return gl::error(GL_INVALID_OPERATION); + } - fenceObject->finishFence(); + if (fenceObject->isFence() != GL_TRUE) + { + return gl::error(GL_INVALID_OPERATION); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + fenceObject->finishFence(); } } @@ -2329,18 +1433,11 @@ void __stdcall glFinish(void) { EVENT("()"); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->sync(true); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->sync(true); } } @@ -2348,18 +1445,11 @@ void __stdcall glFlush(void) { EVENT("()"); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->sync(false); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->sync(false); } } @@ -2368,67 +1458,47 @@ void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, " "GLuint renderbuffer = %d)", target, attachment, renderbuffertarget, renderbuffer); - try + if (!gl::ValidFramebufferTarget(target) || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0)) { - if ((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) - || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0)) - { - return gl::error(GL_INVALID_ENUM); - } + return gl::error(GL_INVALID_ENUM); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (!gl::ValidateFramebufferRenderbufferParameters(context, target, attachment, renderbuffertarget, renderbuffer)) { - gl::Framebuffer *framebuffer = NULL; - GLuint framebufferHandle = 0; - if (target == GL_READ_FRAMEBUFFER_ANGLE) - { - framebuffer = context->getReadFramebuffer(); - framebufferHandle = context->getReadFramebufferHandle(); - } - else - { - framebuffer = context->getDrawFramebuffer(); - framebufferHandle = context->getDrawFramebufferHandle(); - } - - if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0)) - { - return gl::error(GL_INVALID_OPERATION); - } + return; + } - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) - { - const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); - if (colorAttachment >= context->getMaximumRenderTargets()) - { - return gl::error(GL_INVALID_VALUE); - } - - framebuffer->setColorbuffer(colorAttachment, GL_RENDERBUFFER, renderbuffer); - } - else + if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + { + unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + framebuffer->setColorbuffer(colorAttachment, GL_RENDERBUFFER, renderbuffer, 0, 0); + } + else + { + switch (attachment) { - switch (attachment) - { - case GL_DEPTH_ATTACHMENT: - framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer); - break; - case GL_STENCIL_ATTACHMENT: - framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer); - break; - default: - return gl::error(GL_INVALID_ENUM); - } + case GL_DEPTH_ATTACHMENT: + framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer, 0, 0); + break; + case GL_STENCIL_ATTACHMENT: + framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer, 0, 0); + break; + case GL_DEPTH_STENCIL_ATTACHMENT: + framebuffer->setDepthStencilBuffer(GL_RENDERBUFFER, renderbuffer, 0, 0); + break; + default: + UNREACHABLE(); + break; } } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) @@ -2436,167 +1506,57 @@ void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum t EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, " "GLuint texture = %d, GLint level = %d)", target, attachment, textarget, texture, level); - try + gl::Context *context = gl::getNonLostContext(); + if (context) { - if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + if (!ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level)) { - return gl::error(GL_INVALID_ENUM); + return; } - gl::Context *context = gl::getNonLostContext(); - - if (context) + if (texture == 0) { - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) - { - const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); - - if (colorAttachment >= context->getMaximumRenderTargets()) - { - return gl::error(GL_INVALID_VALUE); - } - } - else - { - switch (attachment) - { - case GL_DEPTH_ATTACHMENT: - case GL_STENCIL_ATTACHMENT: - break; - default: - return gl::error(GL_INVALID_ENUM); - } - } - - if (texture == 0) - { - textarget = GL_NONE; - } - else - { - gl::Texture *tex = context->getTexture(texture); - - if (tex == NULL) - { - return gl::error(GL_INVALID_OPERATION); - } - - switch (textarget) - { - case GL_TEXTURE_2D: - { - if (tex->getTarget() != GL_TEXTURE_2D) - { - return gl::error(GL_INVALID_OPERATION); - } - gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex); - if (tex2d->isCompressed(0)) - { - return gl::error(GL_INVALID_OPERATION); - } - break; - } - - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - { - if (tex->getTarget() != GL_TEXTURE_CUBE_MAP) - { - return gl::error(GL_INVALID_OPERATION); - } - gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex); - if (texcube->isCompressed(textarget, level)) - { - return gl::error(GL_INVALID_OPERATION); - } - break; - } - - default: - return gl::error(GL_INVALID_ENUM); - } - - if (level != 0) - { - return gl::error(GL_INVALID_VALUE); - } - } - - gl::Framebuffer *framebuffer = NULL; - GLuint framebufferHandle = 0; - if (target == GL_READ_FRAMEBUFFER_ANGLE) - { - framebuffer = context->getReadFramebuffer(); - framebufferHandle = context->getReadFramebufferHandle(); - } - else - { - framebuffer = context->getDrawFramebuffer(); - framebufferHandle = context->getDrawFramebufferHandle(); - } - - if (framebufferHandle == 0 || !framebuffer) - { - return gl::error(GL_INVALID_OPERATION); - } - - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) - { - const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + textarget = GL_NONE; + } - if (colorAttachment >= context->getMaximumRenderTargets()) - { - return gl::error(GL_INVALID_VALUE); - } + gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - framebuffer->setColorbuffer(colorAttachment, textarget, texture); - } - else + if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + { + const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + framebuffer->setColorbuffer(colorAttachment, textarget, texture, level, 0); + } + else + { + switch (attachment) { - switch (attachment) - { - case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture); break; - case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture); break; - } + case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture, level, 0); break; + case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture, level, 0); break; + case GL_DEPTH_STENCIL_ATTACHMENT: framebuffer->setDepthStencilBuffer(textarget, texture, level, 0); break; } } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glFrontFace(GLenum mode) { EVENT("(GLenum mode = 0x%X)", mode); - try + switch (mode) { - switch (mode) + case GL_CW: + case GL_CCW: { - case GL_CW: - case GL_CCW: - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setFrontFace(mode); - } + if (context) + { + context->getState().setFrontFace(mode); } - break; - default: - return gl::error(GL_INVALID_ENUM); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + break; + default: + return gl::error(GL_INVALID_ENUM); } } @@ -2604,79 +1564,87 @@ void __stdcall glGenBuffers(GLsizei n, GLuint* buffers) { EVENT("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers); - try + if (n < 0) { - if (n < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) - { - buffers[i] = context->createBuffer(); - } + buffers[i] = context->createBuffer(); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGenerateMipmap(GLenum target) { EVENT("(GLenum target = 0x%X)", target); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + if (!ValidTextureTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM); + } + + gl::Texture *texture = context->getTargetTexture(target); - if (context) + if (texture == NULL) { - switch (target) - { - case GL_TEXTURE_2D: - { - gl::Texture2D *tex2d = context->getTexture2D(); + return gl::error(GL_INVALID_OPERATION); + } - if (tex2d->isCompressed(0)) - { - return gl::error(GL_INVALID_OPERATION); - } - if (tex2d->isDepth(0)) - { - return gl::error(GL_INVALID_OPERATION); - } + GLenum internalFormat = texture->getBaseLevelInternalFormat(); + const gl::TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat); - tex2d->generateMipmaps(); - break; - } + // GenerateMipmap should not generate an INVALID_OPERATION for textures created with + // unsized formats or that are color renderable and filterable. Since we do not track if + // the texture was created with sized or unsized format (only sized formats are stored), + // it is not possible to make sure the the LUMA formats can generate mipmaps (they should + // be able to) because they aren't color renderable. Simply do a special case for LUMA + // textures since they're the only texture format that can be created with unsized formats + // that is not color renderable. New unsized formats are unlikely to be added, since ES2 + // was the last version to use add them. + bool isLUMA = internalFormat == GL_LUMINANCE8_EXT || + internalFormat == GL_LUMINANCE8_ALPHA8_EXT || + internalFormat == GL_ALPHA8_EXT; - case GL_TEXTURE_CUBE_MAP: - { - gl::TextureCubeMap *texcube = context->getTextureCubeMap(); + if (gl::GetDepthBits(internalFormat) > 0 || gl::GetStencilBits(internalFormat) > 0 || !formatCaps.filterable || + (!formatCaps.renderable && !isLUMA) || gl::IsFormatCompressed(internalFormat)) + { + return gl::error(GL_INVALID_OPERATION); + } - if (texcube->isCompressed(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) - { - return gl::error(GL_INVALID_OPERATION); - } + // GL_EXT_sRGB does not support mipmap generation on sRGB textures + if (context->getClientVersion() == 2 && gl::GetColorEncoding(internalFormat) == GL_SRGB) + { + return gl::error(GL_INVALID_OPERATION); + } - texcube->generateMipmaps(); - break; - } + // Non-power of 2 ES2 check + if (!context->getExtensions().textureNPOT && (!gl::isPow2(texture->getBaseLevelWidth()) || !gl::isPow2(texture->getBaseLevelHeight()))) + { + ASSERT(context->getClientVersion() <= 2 && (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP)); + return gl::error(GL_INVALID_OPERATION); + } - default: - return gl::error(GL_INVALID_ENUM); + // Cube completeness check + if (target == GL_TEXTURE_CUBE_MAP) + { + gl::TextureCubeMap *textureCube = static_cast<gl::TextureCubeMap *>(texture); + if (!textureCube->isCubeComplete()) + { + return gl::error(GL_INVALID_OPERATION); } } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + texture->generateMipmaps(); } } @@ -2684,135 +1652,100 @@ void __stdcall glGenFencesNV(GLsizei n, GLuint* fences) { EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences); - try + if (n < 0) { - if (n < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) - { - fences[i] = context->createFence(); - } + fences[i] = context->createFenceNV(); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers) { EVENT("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers); - try + if (n < 0) { - if (n < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) - { - framebuffers[i] = context->createFramebuffer(); - } + framebuffers[i] = context->createFramebuffer(); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGenQueriesEXT(GLsizei n, GLuint* ids) { EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { if (n < 0) { return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); - - if (context) + for (GLsizei i = 0; i < n; i++) { - for (int i = 0; i < n; i++) - { - ids[i] = context->createQuery(); - } + ids[i] = context->createQuery(); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) { EVENT("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); - try + if (n < 0) { - if (n < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) - { - renderbuffers[i] = context->createRenderbuffer(); - } + renderbuffers[i] = context->createRenderbuffer(); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGenTextures(GLsizei n, GLuint* textures) { - EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures); + EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures); - try + if (n < 0) { - if (n < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) - { - textures[i] = context->createTexture(); - } + textures[i] = context->createTexture(); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) @@ -2821,42 +1754,35 @@ void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, "GLint *size = 0x%0.8p, GLenum *type = %0.8p, GLchar *name = %0.8p)", program, index, bufsize, length, size, type, name); - try + if (bufsize < 0) { - if (bufsize < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Program *programObject = context->getProgram(program); + if (context) + { + gl::Program *programObject = context->getProgram(program); - if (!programObject) + if (!programObject) + { + if (context->getShader(program)) { - if (context->getShader(program)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_OPERATION); } - - if (index >= (GLuint)programObject->getActiveAttributeCount()) + else { return gl::error(GL_INVALID_VALUE); } + } - programObject->getActiveAttribute(index, bufsize, length, size, type, name); + if (index >= (GLuint)programObject->getActiveAttributeCount()) + { + return gl::error(GL_INVALID_VALUE); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + programObject->getActiveAttribute(index, bufsize, length, size, type, name); } } @@ -2866,42 +1792,35 @@ void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, "GLsizei* length = 0x%0.8p, GLint* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)", program, index, bufsize, length, size, type, name); - try + if (bufsize < 0) { - if (bufsize < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Program *programObject = context->getProgram(program); + if (context) + { + gl::Program *programObject = context->getProgram(program); - if (!programObject) + if (!programObject) + { + if (context->getShader(program)) { - if (context->getShader(program)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_OPERATION); } - - if (index >= (GLuint)programObject->getActiveUniformCount()) + else { return gl::error(GL_INVALID_VALUE); } + } - programObject->getActiveUniform(index, bufsize, length, size, type, name); + if (index >= (GLuint)programObject->getActiveUniformCount()) + { + return gl::error(GL_INVALID_VALUE); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + programObject->getActiveUniform(index, bufsize, length, size, type, name); } } @@ -2910,37 +1829,30 @@ void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* c EVENT("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)", program, maxcount, count, shaders); - try + if (maxcount < 0) { - if (maxcount < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Program *programObject = context->getProgram(program); + if (context) + { + gl::Program *programObject = context->getProgram(program); - if (!programObject) + if (!programObject) + { + if (context->getShader(program)) { - if (context->getShader(program)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_OPERATION); + } + else + { + return gl::error(GL_INVALID_VALUE); } - - return programObject->getAttachedShaders(maxcount, count, shaders); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + return programObject->getAttachedShaders(maxcount, count, shaders); } } @@ -2948,39 +1860,32 @@ int __stdcall glGetAttribLocation(GLuint program, const GLchar* name) { EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { + if (context) + { - gl::Program *programObject = context->getProgram(program); + gl::Program *programObject = context->getProgram(program); - if (!programObject) + if (!programObject) + { + if (context->getShader(program)) { - if (context->getShader(program)) - { - return gl::error(GL_INVALID_OPERATION, -1); - } - else - { - return gl::error(GL_INVALID_VALUE, -1); - } + return gl::error(GL_INVALID_OPERATION, -1); } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programObject->isLinked() || !programBinary) + else { - return gl::error(GL_INVALID_OPERATION, -1); + return gl::error(GL_INVALID_VALUE, -1); } + } - return programBinary->getAttributeLocation(name); + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programObject->isLinked() || !programBinary) + { + return gl::error(GL_INVALID_OPERATION, -1); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, -1); + + return programBinary->getAttributeLocation(name); } return -1; @@ -2990,62 +1895,25 @@ void __stdcall glGetBooleanv(GLenum pname, GLboolean* params) { EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) { - if (!(context->getBooleanv(pname, params))) - { - GLenum nativeType; - unsigned int numParams = 0; - if (!context->getQueryParameterInfo(pname, &nativeType, &numParams)) - return gl::error(GL_INVALID_ENUM); - - if (numParams == 0) - return; // it is known that the pname is valid, but there are no parameters to return - - if (nativeType == GL_FLOAT) - { - GLfloat *floatParams = NULL; - floatParams = new GLfloat[numParams]; - - context->getFloatv(pname, floatParams); - - for (unsigned int i = 0; i < numParams; ++i) - { - if (floatParams[i] == 0.0f) - params[i] = GL_FALSE; - else - params[i] = GL_TRUE; - } - - delete [] floatParams; - } - else if (nativeType == GL_INT) - { - GLint *intParams = NULL; - intParams = new GLint[numParams]; - - context->getIntegerv(pname, intParams); - - for (unsigned int i = 0; i < numParams; ++i) - { - if (intParams[i] == 0) - params[i] = GL_FALSE; - else - params[i] = GL_TRUE; - } + return; + } - delete [] intParams; - } - } + if (nativeType == GL_BOOL) + { + context->getBooleanv(pname, params); + } + else + { + CastStateValues(context, nativeType, pname, numParams, params); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); } } @@ -3053,47 +1921,51 @@ void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + if (!gl::ValidBufferTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM); + } - if (context) + if (!gl::ValidBufferParameter(context, pname)) { - gl::Buffer *buffer; + return gl::error(GL_INVALID_ENUM); + } - switch (target) - { - case GL_ARRAY_BUFFER: - buffer = context->getArrayBuffer(); - break; - case GL_ELEMENT_ARRAY_BUFFER: - buffer = context->getElementArrayBuffer(); - break; - default: return gl::error(GL_INVALID_ENUM); - } + gl::Buffer *buffer = context->getState().getTargetBuffer(target); - if (!buffer) - { - // A null buffer means that "0" is bound to the requested buffer target - return gl::error(GL_INVALID_OPERATION); - } + if (!buffer) + { + // A null buffer means that "0" is bound to the requested buffer target + return gl::error(GL_INVALID_OPERATION); + } - switch (pname) - { - case GL_BUFFER_USAGE: - *params = buffer->usage(); - break; - case GL_BUFFER_SIZE: - *params = buffer->size(); - break; - default: return gl::error(GL_INVALID_ENUM); - } + switch (pname) + { + case GL_BUFFER_USAGE: + *params = static_cast<GLint>(buffer->getUsage()); + break; + case GL_BUFFER_SIZE: + *params = gl::clampCast<GLint>(buffer->getSize()); + break; + case GL_BUFFER_ACCESS_FLAGS: + *params = buffer->getAccessFlags(); + break; + case GL_BUFFER_MAPPED: + *params = static_cast<GLint>(buffer->isMapped()); + break; + case GL_BUFFER_MAP_OFFSET: + *params = gl::clampCast<GLint>(buffer->getMapOffset()); + break; + case GL_BUFFER_MAP_LENGTH: + *params = gl::clampCast<GLint>(buffer->getMapLength()); + break; + default: UNREACHABLE(); break; } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } GLenum __stdcall glGetError(void) @@ -3114,26 +1986,33 @@ void __stdcall glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) { EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params); - try + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - - gl::Context *context = gl::getNonLostContext(); + gl::FenceNV *fenceObject = context->getFenceNV(fence); - if (context) + if (fenceObject == NULL) { - gl::Fence *fenceObject = context->getFence(fence); + return gl::error(GL_INVALID_OPERATION); + } - if (fenceObject == NULL) - { - return gl::error(GL_INVALID_OPERATION); - } + if (fenceObject->isFence() != GL_TRUE) + { + return gl::error(GL_INVALID_OPERATION); + } - fenceObject->getFenceiv(pname, params); + switch (pname) + { + case GL_FENCE_STATUS_NV: + case GL_FENCE_CONDITION_NV: + break; + + default: return gl::error(GL_INVALID_ENUM); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + params[0] = fenceObject->getFencei(pname); } } @@ -3141,59 +2020,25 @@ void __stdcall glGetFloatv(GLenum pname, GLfloat* params) { EVENT("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) { - if (!(context->getFloatv(pname, params))) - { - GLenum nativeType; - unsigned int numParams = 0; - if (!context->getQueryParameterInfo(pname, &nativeType, &numParams)) - return gl::error(GL_INVALID_ENUM); - - if (numParams == 0) - return; // it is known that the pname is valid, but that there are no parameters to return. - - if (nativeType == GL_BOOL) - { - GLboolean *boolParams = NULL; - boolParams = new GLboolean[numParams]; - - context->getBooleanv(pname, boolParams); - - for (unsigned int i = 0; i < numParams; ++i) - { - if (boolParams[i] == GL_FALSE) - params[i] = 0.0f; - else - params[i] = 1.0f; - } - - delete [] boolParams; - } - else if (nativeType == GL_INT) - { - GLint *intParams = NULL; - intParams = new GLint[numParams]; - - context->getIntegerv(pname, intParams); - - for (unsigned int i = 0; i < numParams; ++i) - { - params[i] = (GLfloat)intParams[i]; - } + return; + } - delete [] intParams; - } - } + if (nativeType == GL_FLOAT) + { + context->getFloatv(pname, params); + } + else + { + CastStateValues(context, nativeType, pname, numParams, params); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); } } @@ -3202,219 +2047,313 @@ void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attac EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, attachment, pname, params); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + if (!gl::ValidFramebufferTarget(target)) + { + return gl::error(GL_INVALID_ENUM); + } - if (context) + int clientVersion = context->getClientVersion(); + + switch (pname) { - if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + break; + case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: + if (clientVersion < 3 && !context->getExtensions().sRGB) { return gl::error(GL_INVALID_ENUM); } - - gl::Framebuffer *framebuffer = NULL; - if (target == GL_READ_FRAMEBUFFER_ANGLE) + break; + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: + if (clientVersion < 3) { - if(context->getReadFramebufferHandle() == 0) - { - return gl::error(GL_INVALID_OPERATION); - } - - framebuffer = context->getReadFramebuffer(); + return gl::error(GL_INVALID_ENUM); } - else - { - if (context->getDrawFramebufferHandle() == 0) - { - return gl::error(GL_INVALID_OPERATION); - } + break; + default: + return gl::error(GL_INVALID_ENUM); + } - framebuffer = context->getDrawFramebuffer(); + // Determine if the attachment is a valid enum + switch (attachment) + { + case GL_BACK: + case GL_FRONT: + case GL_DEPTH: + case GL_STENCIL: + case GL_DEPTH_STENCIL_ATTACHMENT: + if (clientVersion < 3) + { + return gl::error(GL_INVALID_ENUM); } + break; - GLenum attachmentType; - GLuint attachmentHandle; + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + default: + if (attachment < GL_COLOR_ATTACHMENT0_EXT || + (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments) { - const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + return gl::error(GL_INVALID_ENUM); + } + break; + } - if (colorAttachment >= context->getMaximumRenderTargets()) - { - return gl::error(GL_INVALID_ENUM); - } + GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id(); + gl::Framebuffer *framebuffer = context->getFramebuffer(framebufferHandle); - attachmentType = framebuffer->getColorbufferType(colorAttachment); - attachmentHandle = framebuffer->getColorbufferHandle(colorAttachment); + if (framebufferHandle == 0) + { + if (clientVersion < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + switch (attachment) + { + case GL_BACK: + case GL_DEPTH: + case GL_STENCIL: + break; + default: + return gl::error(GL_INVALID_OPERATION); + } + } + else + { + if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + { + // Valid attachment query } else { switch (attachment) { case GL_DEPTH_ATTACHMENT: - attachmentType = framebuffer->getDepthbufferType(); - attachmentHandle = framebuffer->getDepthbufferHandle(); - break; case GL_STENCIL_ATTACHMENT: - attachmentType = framebuffer->getStencilbufferType(); - attachmentHandle = framebuffer->getStencilbufferHandle(); break; - default: return gl::error(GL_INVALID_ENUM); + case GL_DEPTH_STENCIL_ATTACHMENT: + if (framebuffer->hasValidDepthStencil()) + { + return gl::error(GL_INVALID_OPERATION); + } + break; + default: + return gl::error(GL_INVALID_OPERATION); } } + } - GLenum attachmentObjectType; // Type category - if (attachmentType == GL_NONE || attachmentType == GL_RENDERBUFFER) - { - attachmentObjectType = attachmentType; - } - else if (gl::IsInternalTextureTarget(attachmentType)) - { - attachmentObjectType = GL_TEXTURE; - } - else - { - UNREACHABLE(); - return; - } + GLenum attachmentType = GL_NONE; + GLuint attachmentHandle = 0; + GLuint attachmentLevel = 0; + GLuint attachmentLayer = 0; + + const gl::FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment); + + if (attachmentObject) + { + attachmentType = attachmentObject->type(); + attachmentHandle = attachmentObject->id(); + attachmentLevel = attachmentObject->mipLevel(); + attachmentLayer = attachmentObject->layer(); + } + + GLenum attachmentObjectType; // Type category + if (framebufferHandle == 0) + { + attachmentObjectType = GL_FRAMEBUFFER_DEFAULT; + } + else if (attachmentType == GL_NONE || attachmentType == GL_RENDERBUFFER) + { + attachmentObjectType = attachmentType; + } + else if (gl::ValidTexture2DDestinationTarget(context, attachmentType)) + { + attachmentObjectType = GL_TEXTURE; + } + else + { + UNREACHABLE(); + return; + } + + if (attachmentObjectType == GL_NONE) + { + // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE + // is NONE, then querying any other pname will generate INVALID_ENUM. + + // ES 3.0.2 spec pg 235 states that if the attachment type is none, + // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an + // INVALID_OPERATION for all other pnames switch (pname) { case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: *params = attachmentObjectType; break; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: - if (attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE) + if (clientVersion < 3) { - *params = attachmentHandle; + return gl::error(GL_INVALID_ENUM); + } + *params = 0; + break; + + default: + if (clientVersion < 3) + { + return gl::error(GL_INVALID_ENUM); } else { + gl::error(GL_INVALID_OPERATION); + } + } + } + else + { + ASSERT(attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE || + attachmentObjectType == GL_FRAMEBUFFER_DEFAULT); + ASSERT(attachmentObject != NULL); + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + *params = attachmentObjectType; + break; + + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + if (attachmentObjectType != GL_RENDERBUFFER && attachmentObjectType != GL_TEXTURE) + { return gl::error(GL_INVALID_ENUM); } + *params = attachmentHandle; break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: - if (attachmentObjectType == GL_TEXTURE) + if (attachmentObjectType != GL_TEXTURE) { - *params = 0; // FramebufferTexture2D will not allow level to be set to anything else in GL ES 2.0 + return gl::error(GL_INVALID_ENUM); } - else + *params = attachmentLevel; + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + if (attachmentObjectType != GL_TEXTURE) { return gl::error(GL_INVALID_ENUM); } + *params = gl::IsCubemapTextureTarget(attachmentType) ? attachmentType : 0; break; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: - if (attachmentObjectType == GL_TEXTURE) + + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + *params = attachmentObject->getRedSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + *params = attachmentObject->getGreenSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + *params = attachmentObject->getBlueSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + *params = attachmentObject->getAlphaSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + *params = attachmentObject->getDepthSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + *params = attachmentObject->getStencilSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + if (attachment == GL_DEPTH_STENCIL) { - if (gl::IsCubemapTextureTarget(attachmentType)) - { - *params = attachmentType; - } - else - { - *params = 0; - } + gl::error(GL_INVALID_OPERATION); } - else + *params = attachmentObject->getComponentType(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: + *params = attachmentObject->getColorEncoding(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: + if (attachmentObjectType != GL_TEXTURE) { return gl::error(GL_INVALID_ENUM); } + *params = attachmentLayer; break; + default: - return gl::error(GL_INVALID_ENUM); + UNREACHABLE(); + break; } } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } GLenum __stdcall glGetGraphicsResetStatusEXT(void) { EVENT("()"); - try - { - gl::Context *context = gl::getContext(); - - if (context) - { - return context->getResetStatus(); - } + gl::Context *context = gl::getContext(); - return GL_NO_ERROR; - } - catch(std::bad_alloc&) + if (context) { - return GL_OUT_OF_MEMORY; + return context->getResetStatus(); } + + return GL_NO_ERROR; } void __stdcall glGetIntegerv(GLenum pname, GLint* params) { EVENT("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + GLenum nativeType; + unsigned int numParams = 0; - if (context) + if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) { - if (!(context->getIntegerv(pname, params))) - { - GLenum nativeType; - unsigned int numParams = 0; - if (!context->getQueryParameterInfo(pname, &nativeType, &numParams)) - return gl::error(GL_INVALID_ENUM); - - if (numParams == 0) - return; // it is known that pname is valid, but there are no parameters to return - - if (nativeType == GL_BOOL) - { - GLboolean *boolParams = NULL; - boolParams = new GLboolean[numParams]; - - context->getBooleanv(pname, boolParams); - - for (unsigned int i = 0; i < numParams; ++i) - { - if (boolParams[i] == GL_FALSE) - params[i] = 0; - else - params[i] = 1; - } - - delete [] boolParams; - } - else if (nativeType == GL_FLOAT) - { - GLfloat *floatParams = NULL; - floatParams = new GLfloat[numParams]; - - context->getFloatv(pname, floatParams); - - for (unsigned int i = 0; i < numParams; ++i) - { - if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR) - { - params[i] = (GLint)(((GLfloat)(0xFFFFFFFF) * floatParams[i] - 1.0f) / 2.0f); - } - else - params[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5)); - } + return; + } - delete [] floatParams; - } - } + if (nativeType == GL_INT) + { + context->getIntegerv(pname, params); + } + else + { + CastStateValues(context, nativeType, pname, numParams, params); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); } } @@ -3422,59 +2361,80 @@ void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params) { EVENT("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); - if (context) + if (!programObject) { - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } + if (context->getClientVersion() < 3) + { switch (pname) { - case GL_DELETE_STATUS: - *params = programObject->isFlaggedForDeletion(); - return; - case GL_LINK_STATUS: - *params = programObject->isLinked(); - return; - case GL_VALIDATE_STATUS: - *params = programObject->isValidated(); - return; - case GL_INFO_LOG_LENGTH: - *params = programObject->getInfoLogLength(); - return; - case GL_ATTACHED_SHADERS: - *params = programObject->getAttachedShadersCount(); - return; - case GL_ACTIVE_ATTRIBUTES: - *params = programObject->getActiveAttributeCount(); - return; - case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: - *params = programObject->getActiveAttributeMaxLength(); - return; - case GL_ACTIVE_UNIFORMS: - *params = programObject->getActiveUniformCount(); - return; - case GL_ACTIVE_UNIFORM_MAX_LENGTH: - *params = programObject->getActiveUniformMaxLength(); - return; - case GL_PROGRAM_BINARY_LENGTH_OES: - *params = programObject->getProgramBinaryLength(); - return; - default: + case GL_ACTIVE_UNIFORM_BLOCKS: + case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + case GL_TRANSFORM_FEEDBACK_VARYINGS: + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: return gl::error(GL_INVALID_ENUM); } } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + switch (pname) + { + case GL_DELETE_STATUS: + *params = programObject->isFlaggedForDeletion(); + return; + case GL_LINK_STATUS: + *params = programObject->isLinked(); + return; + case GL_VALIDATE_STATUS: + *params = programObject->isValidated(); + return; + case GL_INFO_LOG_LENGTH: + *params = programObject->getInfoLogLength(); + return; + case GL_ATTACHED_SHADERS: + *params = programObject->getAttachedShadersCount(); + return; + case GL_ACTIVE_ATTRIBUTES: + *params = programObject->getActiveAttributeCount(); + return; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = programObject->getActiveAttributeMaxLength(); + return; + case GL_ACTIVE_UNIFORMS: + *params = programObject->getActiveUniformCount(); + return; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + *params = programObject->getActiveUniformMaxLength(); + return; + case GL_PROGRAM_BINARY_LENGTH_OES: + *params = programObject->getProgramBinaryLength(); + return; + case GL_ACTIVE_UNIFORM_BLOCKS: + *params = programObject->getActiveUniformBlockCount(); + return; + case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: + *params = programObject->getActiveUniformBlockMaxLength(); + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + *params = programObject->getTransformFeedbackBufferMode(); + break; + case GL_TRANSFORM_FEEDBACK_VARYINGS: + *params = programObject->getTransformFeedbackVaryingCount(); + break; + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: + *params = programObject->getTransformFeedbackVaryingMaxLength(); + break; + default: + return gl::error(GL_INVALID_ENUM); + } } } @@ -3483,30 +2443,23 @@ void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* len EVENT("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", program, bufsize, length, infolog); - try + if (bufsize < 0) { - if (bufsize < 0) - { - return gl::error(GL_INVALID_VALUE); - } - - gl::Context *context = gl::getNonLostContext(); + return gl::error(GL_INVALID_VALUE); + } - if (context) - { - gl::Program *programObject = context->getProgram(program); + gl::Context *context = gl::getNonLostContext(); - if (!programObject) - { - return gl::error(GL_INVALID_VALUE); - } + if (context) + { + gl::Program *programObject = context->getProgram(program); - programObject->getInfoLog(bufsize, length, infolog); + if (!programObject) + { + return gl::error(GL_INVALID_VALUE); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + programObject->getInfoLog(bufsize, length, infolog); } } @@ -3514,26 +2467,24 @@ void __stdcall glGetQueryivEXT(GLenum target, GLenum pname, GLint *params) { EVENT("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", target, pname, params); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { + if (!ValidQueryType(context, target)) + { + return gl::error(GL_INVALID_ENUM); + } + switch (pname) { case GL_CURRENT_QUERY_EXT: + params[0] = context->getState().getActiveQueryId(target); break; + default: return gl::error(GL_INVALID_ENUM); } - - gl::Context *context = gl::getNonLostContext(); - - if (context) - { - params[0] = context->getActiveQuery(target); - } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); } } @@ -3541,48 +2492,33 @@ void __stdcall glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) { EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - switch (pname) + gl::Query *queryObject = context->getQuery(id, false, GL_NONE); + + if (!queryObject) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (context->getState().getActiveQueryId(queryObject->getType()) == id) + { + return gl::error(GL_INVALID_OPERATION); + } + + switch(pname) { case GL_QUERY_RESULT_EXT: + params[0] = queryObject->getResult(); + break; case GL_QUERY_RESULT_AVAILABLE_EXT: + params[0] = queryObject->isResultAvailable(); break; default: return gl::error(GL_INVALID_ENUM); } - gl::Context *context = gl::getNonLostContext(); - - if (context) - { - gl::Query *queryObject = context->getQuery(id, false, GL_NONE); - - if (!queryObject) - { - return gl::error(GL_INVALID_OPERATION); - } - - if (context->getActiveQuery(queryObject->getType()) == id) - { - return gl::error(GL_INVALID_OPERATION); - } - - switch(pname) - { - case GL_QUERY_RESULT_EXT: - params[0] = queryObject->getResult(); - break; - case GL_QUERY_RESULT_AVAILABLE_EXT: - params[0] = queryObject->isResultAvailable(); - break; - default: - ASSERT(false); - } - } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); } } @@ -3590,102 +2526,85 @@ void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (target != GL_RENDERBUFFER) { - if (target != GL_RENDERBUFFER) - { - return gl::error(GL_INVALID_ENUM); - } + return gl::error(GL_INVALID_ENUM); + } - if (context->getRenderbufferHandle() == 0) - { - return gl::error(GL_INVALID_OPERATION); - } + if (context->getState().getRenderbufferId() == 0) + { + return gl::error(GL_INVALID_OPERATION); + } - gl::Renderbuffer *renderbuffer = context->getRenderbuffer(context->getRenderbufferHandle()); + gl::Renderbuffer *renderbuffer = context->getRenderbuffer(context->getState().getRenderbufferId()); - switch (pname) + switch (pname) + { + case GL_RENDERBUFFER_WIDTH: *params = renderbuffer->getWidth(); break; + case GL_RENDERBUFFER_HEIGHT: *params = renderbuffer->getHeight(); break; + case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getInternalFormat(); break; + case GL_RENDERBUFFER_RED_SIZE: *params = renderbuffer->getRedSize(); break; + case GL_RENDERBUFFER_GREEN_SIZE: *params = renderbuffer->getGreenSize(); break; + case GL_RENDERBUFFER_BLUE_SIZE: *params = renderbuffer->getBlueSize(); break; + case GL_RENDERBUFFER_ALPHA_SIZE: *params = renderbuffer->getAlphaSize(); break; + case GL_RENDERBUFFER_DEPTH_SIZE: *params = renderbuffer->getDepthSize(); break; + case GL_RENDERBUFFER_STENCIL_SIZE: *params = renderbuffer->getStencilSize(); break; + case GL_RENDERBUFFER_SAMPLES_ANGLE: + if (!context->getExtensions().framebufferMultisample) { - case GL_RENDERBUFFER_WIDTH: *params = renderbuffer->getWidth(); break; - case GL_RENDERBUFFER_HEIGHT: *params = renderbuffer->getHeight(); break; - case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getInternalFormat(); break; - case GL_RENDERBUFFER_RED_SIZE: *params = renderbuffer->getRedSize(); break; - case GL_RENDERBUFFER_GREEN_SIZE: *params = renderbuffer->getGreenSize(); break; - case GL_RENDERBUFFER_BLUE_SIZE: *params = renderbuffer->getBlueSize(); break; - case GL_RENDERBUFFER_ALPHA_SIZE: *params = renderbuffer->getAlphaSize(); break; - case GL_RENDERBUFFER_DEPTH_SIZE: *params = renderbuffer->getDepthSize(); break; - case GL_RENDERBUFFER_STENCIL_SIZE: *params = renderbuffer->getStencilSize(); break; - case GL_RENDERBUFFER_SAMPLES_ANGLE: - if (context->getMaxSupportedSamples() != 0) - { - *params = renderbuffer->getSamples(); - } - else - { - return gl::error(GL_INVALID_ENUM); - } - break; - default: return gl::error(GL_INVALID_ENUM); } + *params = renderbuffer->getSamples(); + break; + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params) { EVENT("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::Shader *shaderObject = context->getShader(shader); - if (context) + if (!shaderObject) { - gl::Shader *shaderObject = context->getShader(shader); - - if (!shaderObject) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - switch (pname) - { - case GL_SHADER_TYPE: - *params = shaderObject->getType(); - return; - case GL_DELETE_STATUS: - *params = shaderObject->isFlaggedForDeletion(); - return; - case GL_COMPILE_STATUS: - *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE; - return; - case GL_INFO_LOG_LENGTH: - *params = shaderObject->getInfoLogLength(); - return; - case GL_SHADER_SOURCE_LENGTH: - *params = shaderObject->getSourceLength(); - return; - case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: - *params = shaderObject->getTranslatedSourceLength(); - return; - default: - return gl::error(GL_INVALID_ENUM); - } + switch (pname) + { + case GL_SHADER_TYPE: + *params = shaderObject->getType(); + return; + case GL_DELETE_STATUS: + *params = shaderObject->isFlaggedForDeletion(); + return; + case GL_COMPILE_STATUS: + *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE; + return; + case GL_INFO_LOG_LENGTH: + *params = shaderObject->getInfoLogLength(); + return; + case GL_SHADER_SOURCE_LENGTH: + *params = shaderObject->getSourceLength(); + return; + case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: + *params = shaderObject->getTranslatedSourceLength(); + return; + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) @@ -3693,30 +2612,23 @@ void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* lengt EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", shader, bufsize, length, infolog); - try + if (bufsize < 0) { - if (bufsize < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Shader *shaderObject = context->getShader(shader); - - if (!shaderObject) - { - return gl::error(GL_INVALID_VALUE); - } + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); - shaderObject->getInfoLog(bufsize, length, infolog); + if (!shaderObject) + { + return gl::error(GL_INVALID_VALUE); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + shaderObject->getInfoLog(bufsize, length, infolog); } } @@ -3725,43 +2637,36 @@ void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontyp EVENT("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)", shadertype, precisiontype, range, precision); - try + switch (shadertype) { - switch (shadertype) - { - case GL_VERTEX_SHADER: - case GL_FRAGMENT_SHADER: - break; - default: - return gl::error(GL_INVALID_ENUM); - } - - switch (precisiontype) - { - case GL_LOW_FLOAT: - case GL_MEDIUM_FLOAT: - case GL_HIGH_FLOAT: - // Assume IEEE 754 precision - range[0] = 127; - range[1] = 127; - *precision = 23; - break; - case GL_LOW_INT: - case GL_MEDIUM_INT: - case GL_HIGH_INT: - // Some (most) hardware only supports single-precision floating-point numbers, - // which can accurately represent integers up to +/-16777216 - range[0] = 24; - range[1] = 24; - *precision = 0; - break; - default: - return gl::error(GL_INVALID_ENUM); - } + case GL_VERTEX_SHADER: + case GL_FRAGMENT_SHADER: + break; + default: + return gl::error(GL_INVALID_ENUM); } - catch(std::bad_alloc&) + + switch (precisiontype) { - return gl::error(GL_OUT_OF_MEMORY); + case GL_LOW_FLOAT: + case GL_MEDIUM_FLOAT: + case GL_HIGH_FLOAT: + // Assume IEEE 754 precision + range[0] = 127; + range[1] = 127; + *precision = 23; + break; + case GL_LOW_INT: + case GL_MEDIUM_INT: + case GL_HIGH_INT: + // Some (most) hardware only supports single-precision floating-point numbers, + // which can accurately represent integers up to +/-16777216 + range[0] = 24; + range[1] = 24; + *precision = 0; + break; + default: + return gl::error(GL_INVALID_ENUM); } } @@ -3770,30 +2675,23 @@ void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)", shader, bufsize, length, source); - try + if (bufsize < 0) { - if (bufsize < 0) - { - return gl::error(GL_INVALID_VALUE); - } - - gl::Context *context = gl::getNonLostContext(); + return gl::error(GL_INVALID_VALUE); + } - if (context) - { - gl::Shader *shaderObject = context->getShader(shader); + gl::Context *context = gl::getNonLostContext(); - if (!shaderObject) - { - return gl::error(GL_INVALID_OPERATION); - } + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); - shaderObject->getSource(bufsize, length, source); + if (!shaderObject) + { + return gl::error(GL_INVALID_OPERATION); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + shaderObject->getSource(bufsize, length, source); } } @@ -3802,30 +2700,23 @@ void __stdcall glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)", shader, bufsize, length, source); - try + if (bufsize < 0) { - if (bufsize < 0) - { - return gl::error(GL_INVALID_VALUE); - } - - gl::Context *context = gl::getNonLostContext(); + return gl::error(GL_INVALID_VALUE); + } - if (context) - { - gl::Shader *shaderObject = context->getShader(shader); + gl::Context *context = gl::getNonLostContext(); - if (!shaderObject) - { - return gl::error(GL_INVALID_OPERATION); - } + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); - shaderObject->getTranslatedSource(bufsize, length, source); + if (!shaderObject) + { + return gl::error(GL_INVALID_OPERATION); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + shaderObject->getTranslatedSource(bufsize, length, source); } } @@ -3833,29 +2724,36 @@ const GLubyte* __stdcall glGetString(GLenum name) { EVENT("(GLenum name = 0x%X)", name); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - switch (name) + switch (name) + { + case GL_VENDOR: + return (GLubyte*)"Google Inc."; + case GL_RENDERER: + return (GLubyte*)((context != NULL) ? context->getRendererString().c_str() : "ANGLE"); + case GL_VERSION: + if (context->getClientVersion() == 2) { - case GL_VENDOR: - return (GLubyte*)"Google Inc."; - case GL_RENDERER: - return (GLubyte*)((context != NULL) ? context->getRendererString() : "ANGLE"); - case GL_VERSION: return (GLubyte*)"OpenGL ES 2.0 (ANGLE " ANGLE_VERSION_STRING ")"; - case GL_SHADING_LANGUAGE_VERSION: + } + else + { + return (GLubyte*)"OpenGL ES 3.0 (ANGLE " ANGLE_VERSION_STRING ")"; + } + case GL_SHADING_LANGUAGE_VERSION: + if (context->getClientVersion() == 2) + { return (GLubyte*)"OpenGL ES GLSL ES 1.00 (ANGLE " ANGLE_VERSION_STRING ")"; - case GL_EXTENSIONS: - return (GLubyte*)((context != NULL) ? context->getExtensionString() : ""); - default: - return gl::error(GL_INVALID_ENUM, (GLubyte*)NULL); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, (GLubyte*)NULL); + else + { + return (GLubyte*)"OpenGL ES GLSL ES 3.00 (ANGLE " ANGLE_VERSION_STRING ")"; + } + case GL_EXTENSIONS: + return (GLubyte*)((context != NULL) ? context->getExtensionString().c_str() : ""); + default: + return gl::error(GL_INVALID_ENUM, (GLubyte*)NULL); } } @@ -3863,124 +2761,238 @@ void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::Texture *texture = context->getTargetTexture(target); - if (context) + if (!texture) { - gl::Texture *texture; + return gl::error(GL_INVALID_ENUM); + } - switch (target) + switch (pname) + { + case GL_TEXTURE_MAG_FILTER: + *params = (GLfloat)texture->getSamplerState().magFilter; + break; + case GL_TEXTURE_MIN_FILTER: + *params = (GLfloat)texture->getSamplerState().minFilter; + break; + case GL_TEXTURE_WRAP_S: + *params = (GLfloat)texture->getSamplerState().wrapS; + break; + case GL_TEXTURE_WRAP_T: + *params = (GLfloat)texture->getSamplerState().wrapT; + break; + case GL_TEXTURE_WRAP_R: + if (context->getClientVersion() < 3) { - case GL_TEXTURE_2D: - texture = context->getTexture2D(); - break; - case GL_TEXTURE_CUBE_MAP: - texture = context->getTextureCubeMap(); - break; - default: return gl::error(GL_INVALID_ENUM); } - - switch (pname) + *params = (GLfloat)texture->getSamplerState().wrapR; + break; + case GL_TEXTURE_IMMUTABLE_FORMAT: + // Exposed to ES2.0 through EXT_texture_storage, no client version validation. + *params = (GLfloat)(texture->isImmutable() ? GL_TRUE : GL_FALSE); + break; + case GL_TEXTURE_IMMUTABLE_LEVELS: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = (GLfloat)texture->immutableLevelCount(); + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = (GLfloat)texture->getUsage(); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->getExtensions().textureFilterAnisotropic) + { + return gl::error(GL_INVALID_ENUM); + } + *params = (GLfloat)texture->getSamplerState().maxAnisotropy; + break; + case GL_TEXTURE_SWIZZLE_R: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = (GLfloat)texture->getSamplerState().swizzleRed; + break; + case GL_TEXTURE_SWIZZLE_G: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = (GLfloat)texture->getSamplerState().swizzleGreen; + break; + case GL_TEXTURE_SWIZZLE_B: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = (GLfloat)texture->getSamplerState().swizzleBlue; + break; + case GL_TEXTURE_SWIZZLE_A: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = (GLfloat)texture->getSamplerState().swizzleAlpha; + break; + case GL_TEXTURE_BASE_LEVEL: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = (GLfloat)texture->getSamplerState().baseLevel; + break; + case GL_TEXTURE_MAX_LEVEL: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = (GLfloat)texture->getSamplerState().maxLevel; + break; + case GL_TEXTURE_MIN_LOD: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = texture->getSamplerState().minLod; + break; + case GL_TEXTURE_MAX_LOD: + if (context->getClientVersion() < 3) { - case GL_TEXTURE_MAG_FILTER: - *params = (GLfloat)texture->getMagFilter(); - break; - case GL_TEXTURE_MIN_FILTER: - *params = (GLfloat)texture->getMinFilter(); - break; - case GL_TEXTURE_WRAP_S: - *params = (GLfloat)texture->getWrapS(); - break; - case GL_TEXTURE_WRAP_T: - *params = (GLfloat)texture->getWrapT(); - break; - case GL_TEXTURE_IMMUTABLE_FORMAT_EXT: - *params = (GLfloat)(texture->isImmutable() ? GL_TRUE : GL_FALSE); - break; - case GL_TEXTURE_USAGE_ANGLE: - *params = (GLfloat)texture->getUsage(); - break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (!context->supportsTextureFilterAnisotropy()) - { - return gl::error(GL_INVALID_ENUM); - } - *params = (GLfloat)texture->getMaxAnisotropy(); - break; - default: return gl::error(GL_INVALID_ENUM); } + *params = texture->getSamplerState().maxLod; + break; + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::Texture *texture = context->getTargetTexture(target); - if (context) + if (!texture) { - gl::Texture *texture; + return gl::error(GL_INVALID_ENUM); + } - switch (target) + switch (pname) + { + case GL_TEXTURE_MAG_FILTER: + *params = texture->getSamplerState().magFilter; + break; + case GL_TEXTURE_MIN_FILTER: + *params = texture->getSamplerState().minFilter; + break; + case GL_TEXTURE_WRAP_S: + *params = texture->getSamplerState().wrapS; + break; + case GL_TEXTURE_WRAP_T: + *params = texture->getSamplerState().wrapT; + break; + case GL_TEXTURE_WRAP_R: + if (context->getClientVersion() < 3) { - case GL_TEXTURE_2D: - texture = context->getTexture2D(); - break; - case GL_TEXTURE_CUBE_MAP: - texture = context->getTextureCubeMap(); - break; - default: return gl::error(GL_INVALID_ENUM); } - - switch (pname) + *params = texture->getSamplerState().wrapR; + break; + case GL_TEXTURE_IMMUTABLE_FORMAT: + // Exposed to ES2.0 through EXT_texture_storage, no client version validation. + *params = texture->isImmutable() ? GL_TRUE : GL_FALSE; + break; + case GL_TEXTURE_IMMUTABLE_LEVELS: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = texture->immutableLevelCount(); + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = texture->getUsage(); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->getExtensions().textureFilterAnisotropic) { - case GL_TEXTURE_MAG_FILTER: - *params = texture->getMagFilter(); - break; - case GL_TEXTURE_MIN_FILTER: - *params = texture->getMinFilter(); - break; - case GL_TEXTURE_WRAP_S: - *params = texture->getWrapS(); - break; - case GL_TEXTURE_WRAP_T: - *params = texture->getWrapT(); - break; - case GL_TEXTURE_IMMUTABLE_FORMAT_EXT: - *params = texture->isImmutable() ? GL_TRUE : GL_FALSE; - break; - case GL_TEXTURE_USAGE_ANGLE: - *params = texture->getUsage(); - break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (!context->supportsTextureFilterAnisotropy()) - { - return gl::error(GL_INVALID_ENUM); - } - *params = (GLint)texture->getMaxAnisotropy(); - break; - default: return gl::error(GL_INVALID_ENUM); } + *params = (GLint)texture->getSamplerState().maxAnisotropy; + break; + case GL_TEXTURE_SWIZZLE_R: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = texture->getSamplerState().swizzleRed; + break; + case GL_TEXTURE_SWIZZLE_G: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = texture->getSamplerState().swizzleGreen; + break; + case GL_TEXTURE_SWIZZLE_B: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = texture->getSamplerState().swizzleBlue; + break; + case GL_TEXTURE_SWIZZLE_A: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = texture->getSamplerState().swizzleAlpha; + break; + case GL_TEXTURE_BASE_LEVEL: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = texture->getSamplerState().baseLevel; + break; + case GL_TEXTURE_MAX_LEVEL: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = texture->getSamplerState().maxLevel; + break; + case GL_TEXTURE_MIN_LOD: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = (GLint)texture->getSamplerState().minLod; + break; + case GL_TEXTURE_MAX_LOD: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM); + } + *params = (GLint)texture->getSamplerState().maxLod; + break; + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params) @@ -3988,214 +3000,179 @@ void __stdcall glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSiz EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = 0x%0.8p)", program, location, bufSize, params); - try + if (bufSize < 0) { - if (bufSize < 0) + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (program == 0) { return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); - if (context) + if (!programObject || !programObject->isLinked()) { - if (program == 0) - { - return gl::error(GL_INVALID_VALUE); - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject || !programObject->isLinked()) - { - return gl::error(GL_INVALID_OPERATION); - } + return gl::error(GL_INVALID_OPERATION); + } - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programBinary) - { - return gl::error(GL_INVALID_OPERATION); - } + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return gl::error(GL_INVALID_OPERATION); + } - if (!programBinary->getUniformfv(location, &bufSize, params)) - { - return gl::error(GL_INVALID_OPERATION); - } + if (!programBinary->getUniformfv(location, &bufSize, params)) + { + return gl::error(GL_INVALID_OPERATION); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) { EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (program == 0) { - if (program == 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Program *programObject = context->getProgram(program); + gl::Program *programObject = context->getProgram(program); - if (!programObject || !programObject->isLinked()) - { - return gl::error(GL_INVALID_OPERATION); - } + if (!programObject || !programObject->isLinked()) + { + return gl::error(GL_INVALID_OPERATION); + } - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programBinary) - { - return gl::error(GL_INVALID_OPERATION); - } + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return gl::error(GL_INVALID_OPERATION); + } - if (!programBinary->getUniformfv(location, NULL, params)) - { - return gl::error(GL_INVALID_OPERATION); - } + if (!programBinary->getUniformfv(location, NULL, params)) + { + return gl::error(GL_INVALID_OPERATION); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params) { - EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)", + EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)", program, location, bufSize, params); - try + if (bufSize < 0) { - if (bufSize < 0) + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (program == 0) { return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); - if (context) + if (!programObject || !programObject->isLinked()) { - if (program == 0) - { - return gl::error(GL_INVALID_VALUE); - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject || !programObject->isLinked()) - { - return gl::error(GL_INVALID_OPERATION); - } + return gl::error(GL_INVALID_OPERATION); + } - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programBinary) - { - return gl::error(GL_INVALID_OPERATION); - } + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return gl::error(GL_INVALID_OPERATION); + } - if (!programBinary->getUniformiv(location, &bufSize, params)) - { - return gl::error(GL_INVALID_OPERATION); - } + if (!programBinary->getUniformiv(location, &bufSize, params)) + { + return gl::error(GL_INVALID_OPERATION); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) { EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (program == 0) { - if (program == 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Program *programObject = context->getProgram(program); + gl::Program *programObject = context->getProgram(program); - if (!programObject || !programObject->isLinked()) - { - return gl::error(GL_INVALID_OPERATION); - } + if (!programObject || !programObject->isLinked()) + { + return gl::error(GL_INVALID_OPERATION); + } - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programBinary) - { - return gl::error(GL_INVALID_OPERATION); - } + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return gl::error(GL_INVALID_OPERATION); + } - if (!programBinary->getUniformiv(location, NULL, params)) - { - return gl::error(GL_INVALID_OPERATION); - } + if (!programBinary->getUniformiv(location, NULL, params)) + { + return gl::error(GL_INVALID_OPERATION); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } int __stdcall glGetUniformLocation(GLuint program, const GLchar* name) { EVENT("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name); - try + gl::Context *context = gl::getNonLostContext(); + + if (strstr(name, "gl_") == name) { - gl::Context *context = gl::getNonLostContext(); + return -1; + } - if (strstr(name, "gl_") == name) - { - return -1; - } + if (context) + { + gl::Program *programObject = context->getProgram(program); - if (context) + if (!programObject) { - gl::Program *programObject = context->getProgram(program); - - if (!programObject) + if (context->getShader(program)) { - if (context->getShader(program)) - { - return gl::error(GL_INVALID_OPERATION, -1); - } - else - { - return gl::error(GL_INVALID_VALUE, -1); - } + return gl::error(GL_INVALID_OPERATION, -1); } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programObject->isLinked() || !programBinary) + else { - return gl::error(GL_INVALID_OPERATION, -1); + return gl::error(GL_INVALID_VALUE, -1); } + } - return programBinary->getUniformLocation(name); + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programObject->isLinked() || !programBinary) + { + return gl::error(GL_INVALID_OPERATION, -1); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, -1); + + return programBinary->getUniformLocation(name); } return -1; @@ -4205,55 +3182,33 @@ void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) { EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (index >= gl::MAX_VERTEX_ATTRIBS) { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - const gl::VertexAttribute &attribState = context->getVertexAttribState(index); + const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index); + if (!gl::ValidateGetVertexAttribParameters(pname, context->getClientVersion())) + { + return; + } - switch (pname) + if (pname == GL_CURRENT_VERTEX_ATTRIB) + { + const gl::VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); + for (int i = 0; i < 4; ++i) { - case GL_VERTEX_ATTRIB_ARRAY_ENABLED: - *params = (GLfloat)(attribState.mArrayEnabled ? GL_TRUE : GL_FALSE); - break; - case GL_VERTEX_ATTRIB_ARRAY_SIZE: - *params = (GLfloat)attribState.mSize; - break; - case GL_VERTEX_ATTRIB_ARRAY_STRIDE: - *params = (GLfloat)attribState.mStride; - break; - case GL_VERTEX_ATTRIB_ARRAY_TYPE: - *params = (GLfloat)attribState.mType; - break; - case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: - *params = (GLfloat)(attribState.mNormalized ? GL_TRUE : GL_FALSE); - break; - case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: - *params = (GLfloat)attribState.mBoundBuffer.id(); - break; - case GL_CURRENT_VERTEX_ATTRIB: - for (int i = 0; i < 4; ++i) - { - params[i] = attribState.mCurrentValue[i]; - } - break; - case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: - *params = (GLfloat)attribState.mDivisor; - break; - default: return gl::error(GL_INVALID_ENUM); + params[i] = currentValueData.FloatValues[i]; } } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + else + { + *params = gl::QuerySingleVertexAttributeParameter<GLfloat>(attribState, pname); + } } } @@ -4261,56 +3216,35 @@ void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) { EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (index >= gl::MAX_VERTEX_ATTRIBS) { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - const gl::VertexAttribute &attribState = context->getVertexAttribState(index); + const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index); - switch (pname) + if (!gl::ValidateGetVertexAttribParameters(pname, context->getClientVersion())) + { + return; + } + + if (pname == GL_CURRENT_VERTEX_ATTRIB) + { + const gl::VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); + for (int i = 0; i < 4; ++i) { - case GL_VERTEX_ATTRIB_ARRAY_ENABLED: - *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE); - break; - case GL_VERTEX_ATTRIB_ARRAY_SIZE: - *params = attribState.mSize; - break; - case GL_VERTEX_ATTRIB_ARRAY_STRIDE: - *params = attribState.mStride; - break; - case GL_VERTEX_ATTRIB_ARRAY_TYPE: - *params = attribState.mType; - break; - case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: - *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE); - break; - case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: - *params = attribState.mBoundBuffer.id(); - break; - case GL_CURRENT_VERTEX_ATTRIB: - for (int i = 0; i < 4; ++i) - { - float currentValue = attribState.mCurrentValue[i]; - params[i] = (GLint)(currentValue > 0.0f ? floor(currentValue + 0.5f) : ceil(currentValue - 0.5f)); - } - break; - case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: - *params = (GLint)attribState.mDivisor; - break; - default: return gl::error(GL_INVALID_ENUM); + float currentValue = currentValueData.FloatValues[i]; + params[i] = gl::iround<GLint>(currentValue); } } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + else + { + *params = gl::QuerySingleVertexAttributeParameter<GLint>(attribState, pname); + } } } @@ -4318,28 +3252,21 @@ void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** po { EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (index >= gl::MAX_VERTEX_ATTRIBS) { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - return gl::error(GL_INVALID_VALUE); - } - - if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) - { - return gl::error(GL_INVALID_ENUM); - } + return gl::error(GL_INVALID_VALUE); + } - *pointer = const_cast<GLvoid*>(context->getVertexAttribPointer(index)); + if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) + { + return gl::error(GL_INVALID_ENUM); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + *pointer = const_cast<GLvoid*>(context->getState().getVertexAttribPointer(index)); } } @@ -4347,34 +3274,27 @@ void __stdcall glHint(GLenum target, GLenum mode) { EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode); - try + switch (mode) { - switch (mode) - { - case GL_FASTEST: - case GL_NICEST: - case GL_DONT_CARE: - break; - default: - return gl::error(GL_INVALID_ENUM); - } - - gl::Context *context = gl::getNonLostContext(); - switch (target) - { - case GL_GENERATE_MIPMAP_HINT: - if (context) context->setGenerateMipmapHint(mode); - break; - case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: - if (context) context->setFragmentShaderDerivativeHint(mode); - break; - default: - return gl::error(GL_INVALID_ENUM); - } + case GL_FASTEST: + case GL_NICEST: + case GL_DONT_CARE: + break; + default: + return gl::error(GL_INVALID_ENUM); } - catch(std::bad_alloc&) + + gl::Context *context = gl::getNonLostContext(); + switch (target) { - return gl::error(GL_OUT_OF_MEMORY); + case GL_GENERATE_MIPMAP_HINT: + if (context) context->getState().setGenerateMipmapHint(mode); + break; + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: + if (context) context->getState().setFragmentShaderDerivativeHint(mode); + break; + default: + return gl::error(GL_INVALID_ENUM); } } @@ -4382,24 +3302,17 @@ GLboolean __stdcall glIsBuffer(GLuint buffer) { EVENT("(GLuint buffer = %d)", buffer); - try + gl::Context *context = gl::getNonLostContext(); + + if (context && buffer) { - gl::Context *context = gl::getNonLostContext(); + gl::Buffer *bufferObject = context->getBuffer(buffer); - if (context && buffer) + if (bufferObject) { - gl::Buffer *bufferObject = context->getBuffer(buffer); - - if (bufferObject) - { - return GL_TRUE; - } + return GL_TRUE; } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, GL_FALSE); - } return GL_FALSE; } @@ -4408,31 +3321,16 @@ GLboolean __stdcall glIsEnabled(GLenum cap) { EVENT("(GLenum cap = 0x%X)", cap); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (!ValidCap(context, cap)) { - switch (cap) - { - case GL_CULL_FACE: return context->isCullFaceEnabled(); - case GL_POLYGON_OFFSET_FILL: return context->isPolygonOffsetFillEnabled(); - case GL_SAMPLE_ALPHA_TO_COVERAGE: return context->isSampleAlphaToCoverageEnabled(); - case GL_SAMPLE_COVERAGE: return context->isSampleCoverageEnabled(); - case GL_SCISSOR_TEST: return context->isScissorTestEnabled(); - case GL_STENCIL_TEST: return context->isStencilTestEnabled(); - case GL_DEPTH_TEST: return context->isDepthTestEnabled(); - case GL_BLEND: return context->isBlendEnabled(); - case GL_DITHER: return context->isDitherEnabled(); - default: - return gl::error(GL_INVALID_ENUM, false); - } + return gl::error(GL_INVALID_ENUM, false); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, false); + + return context->getState().getEnableFeature(cap); } return false; @@ -4442,25 +3340,18 @@ GLboolean __stdcall glIsFenceNV(GLuint fence) { EVENT("(GLuint fence = %d)", fence); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::FenceNV *fenceObject = context->getFenceNV(fence); - if (context) + if (fenceObject == NULL) { - gl::Fence *fenceObject = context->getFence(fence); - - if (fenceObject == NULL) - { - return GL_FALSE; - } - - return fenceObject->isFence(); + return GL_FALSE; } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, GL_FALSE); + + return fenceObject->isFence(); } return GL_FALSE; @@ -4470,24 +3361,17 @@ GLboolean __stdcall glIsFramebuffer(GLuint framebuffer) { EVENT("(GLuint framebuffer = %d)", framebuffer); - try + gl::Context *context = gl::getNonLostContext(); + + if (context && framebuffer) { - gl::Context *context = gl::getNonLostContext(); + gl::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer); - if (context && framebuffer) + if (framebufferObject) { - gl::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer); - - if (framebufferObject) - { - return GL_TRUE; - } + return GL_TRUE; } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, GL_FALSE); - } return GL_FALSE; } @@ -4496,24 +3380,17 @@ GLboolean __stdcall glIsProgram(GLuint program) { EVENT("(GLuint program = %d)", program); - try + gl::Context *context = gl::getNonLostContext(); + + if (context && program) { - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); - if (context && program) + if (programObject) { - gl::Program *programObject = context->getProgram(program); - - if (programObject) - { - return GL_TRUE; - } + return GL_TRUE; } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, GL_FALSE); - } return GL_FALSE; } @@ -4522,28 +3399,11 @@ GLboolean __stdcall glIsQueryEXT(GLuint id) { EVENT("(GLuint id = %d)", id); - try - { - if (id == 0) - { - return GL_FALSE; - } - - gl::Context *context = gl::getNonLostContext(); - - if (context) - { - gl::Query *queryObject = context->getQuery(id, false, GL_NONE); + gl::Context *context = gl::getNonLostContext(); - if (queryObject) - { - return GL_TRUE; - } - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY, GL_FALSE); + return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE; } return GL_FALSE; @@ -4553,24 +3413,17 @@ GLboolean __stdcall glIsRenderbuffer(GLuint renderbuffer) { EVENT("(GLuint renderbuffer = %d)", renderbuffer); - try + gl::Context *context = gl::getNonLostContext(); + + if (context && renderbuffer) { - gl::Context *context = gl::getNonLostContext(); + gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer); - if (context && renderbuffer) + if (renderbufferObject) { - gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer); - - if (renderbufferObject) - { - return GL_TRUE; - } + return GL_TRUE; } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, GL_FALSE); - } return GL_FALSE; } @@ -4579,24 +3432,17 @@ GLboolean __stdcall glIsShader(GLuint shader) { EVENT("(GLuint shader = %d)", shader); - try + gl::Context *context = gl::getNonLostContext(); + + if (context && shader) { - gl::Context *context = gl::getNonLostContext(); + gl::Shader *shaderObject = context->getShader(shader); - if (context && shader) + if (shaderObject) { - gl::Shader *shaderObject = context->getShader(shader); - - if (shaderObject) - { - return GL_TRUE; - } + return GL_TRUE; } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, GL_FALSE); - } return GL_FALSE; } @@ -4605,24 +3451,17 @@ GLboolean __stdcall glIsTexture(GLuint texture) { EVENT("(GLuint texture = %d)", texture); - try + gl::Context *context = gl::getNonLostContext(); + + if (context && texture) { - gl::Context *context = gl::getNonLostContext(); + gl::Texture *textureObject = context->getTexture(texture); - if (context && texture) + if (textureObject) { - gl::Texture *textureObject = context->getTexture(texture); - - if (textureObject) - { - return GL_TRUE; - } + return GL_TRUE; } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, GL_FALSE); - } return GL_FALSE; } @@ -4631,23 +3470,16 @@ void __stdcall glLineWidth(GLfloat width) { EVENT("(GLfloat width = %f)", width); - try + if (width <= 0.0f) { - if (width <= 0.0f) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setLineWidth(width); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setLineWidth(width); } } @@ -4655,32 +3487,25 @@ void __stdcall glLinkProgram(GLuint program) { EVENT("(GLuint program = %d)", program); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); - if (context) + if (!programObject) { - gl::Program *programObject = context->getProgram(program); - - if (!programObject) + if (context->getShader(program)) { - if (context->getShader(program)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_OPERATION); + } + else + { + return gl::error(GL_INVALID_VALUE); } - - context->linkProgram(program); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + context->linkProgram(program); } } @@ -4688,63 +3513,64 @@ void __stdcall glPixelStorei(GLenum pname, GLint param) { EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + switch (pname) { - switch (pname) + case GL_UNPACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) { - case GL_UNPACK_ALIGNMENT: - if (param != 1 && param != 2 && param != 4 && param != 8) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - context->setUnpackAlignment(param); - break; + context->getState().setUnpackAlignment(param); + break; - case GL_PACK_ALIGNMENT: - if (param != 1 && param != 2 && param != 4 && param != 8) - { - return gl::error(GL_INVALID_VALUE); - } + case GL_PACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) + { + return gl::error(GL_INVALID_VALUE); + } - context->setPackAlignment(param); - break; + context->getState().setPackAlignment(param); + break; - case GL_PACK_REVERSE_ROW_ORDER_ANGLE: - context->setPackReverseRowOrder(param != 0); - break; + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + context->getState().setPackReverseRowOrder(param != 0); + break; - default: + case GL_UNPACK_IMAGE_HEIGHT: + case GL_UNPACK_SKIP_IMAGES: + case GL_UNPACK_ROW_LENGTH: + case GL_UNPACK_SKIP_ROWS: + case GL_UNPACK_SKIP_PIXELS: + case GL_PACK_ROW_LENGTH: + case GL_PACK_SKIP_ROWS: + case GL_PACK_SKIP_PIXELS: + if (context->getClientVersion() < 3) + { return gl::error(GL_INVALID_ENUM); } + UNIMPLEMENTED(); + break; + + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } void __stdcall glPolygonOffset(GLfloat factor, GLfloat units) { EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->setPolygonOffsetParams(factor, units); - } - } - catch(std::bad_alloc&) + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setPolygonOffsetParams(factor, units); } } @@ -4756,36 +3582,22 @@ void __stdcall glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, GLvoid *data = 0x%0.8p)", x, y, width, height, format, type, bufSize, data); - try + if (width < 0 || height < 0 || bufSize < 0) { - if (width < 0 || height < 0 || bufSize < 0) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (!gl::ValidateReadPixelsParameters(context, x, y, width, height, + format, type, &bufSize, data)) { - GLenum currentFormat, currentType; - - // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound, - // and attempting to read back if that's the case is an error. The error will be registered - // by getCurrentReadFormat. - if (!context->getCurrentReadFormatType(¤tFormat, ¤tType)) - return; - - if (!(currentFormat == format && currentType == type) && !validReadFormatType(format, type)) - { - return gl::error(GL_INVALID_OPERATION); - } - - context->readPixels(x, y, width, height, format, type, &bufSize, data); + return; } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + context->readPixels(x, y, width, height, format, type, &bufSize, data); } } @@ -4796,2077 +3608,4336 @@ void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, "GLenum format = 0x%X, GLenum type = 0x%X, GLvoid* pixels = 0x%0.8p)", x, y, width, height, format, type, pixels); - try + if (width < 0 || height < 0) { - if (width < 0 || height < 0) + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!gl::ValidateReadPixelsParameters(context, x, y, width, height, + format, type, NULL, pixels)) { - return gl::error(GL_INVALID_VALUE); + return; } - gl::Context *context = gl::getNonLostContext(); + context->readPixels(x, y, width, height, format, type, NULL, pixels); + } +} + +void __stdcall glReleaseShaderCompiler(void) +{ + EVENT("()"); - if (context) + gl::Shader::releaseCompiler(); +} + +void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + target, samples, internalformat, width, height); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!ValidateRenderbufferStorageParameters(context, target, samples, internalformat, + width, height, true)) + { + return; + } + + context->setRenderbufferStorage(width, height, internalformat, samples); + } +} + +void __stdcall glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ + glRenderbufferStorageMultisampleANGLE(target, 0, internalformat, width, height); +} + +void __stdcall glSampleCoverage(GLclampf value, GLboolean invert) +{ + EVENT("(GLclampf value = %f, GLboolean invert = %u)", value, invert); + + gl::Context* context = gl::getNonLostContext(); + + if (context) + { + context->getState().setSampleCoverageParams(gl::clamp01(value), invert == GL_TRUE); + } +} + +void __stdcall glSetFenceNV(GLuint fence, GLenum condition) +{ + EVENT("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition); + + if (condition != GL_ALL_COMPLETED_NV) + { + return gl::error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::FenceNV *fenceObject = context->getFenceNV(fence); + + if (fenceObject == NULL) { - GLenum currentFormat, currentType; - - // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound, - // and attempting to read back if that's the case is an error. The error will be registered - // by getCurrentReadFormat. - if (!context->getCurrentReadFormatType(¤tFormat, ¤tType)) - return; + return gl::error(GL_INVALID_OPERATION); + } + + fenceObject->setFence(condition); + } +} + +void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); + + if (width < 0 || height < 0) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Context* context = gl::getNonLostContext(); + + if (context) + { + context->getState().setScissorParams(x, y, width, height); + } +} + +void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +{ + EVENT("(GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, " + "const GLvoid* binary = 0x%0.8p, GLsizei length = %d)", + n, shaders, binaryformat, binary, length); - if (!(currentFormat == format && currentType == type) && !validReadFormatType(format, type)) + // No binary shader formats are supported. + return gl::error(GL_INVALID_ENUM); +} + +void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length) +{ + EVENT("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)", + shader, count, string, length); + + if (count < 0) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + if (context->getProgram(shader)) { return gl::error(GL_INVALID_OPERATION); } + else + { + return gl::error(GL_INVALID_VALUE); + } + } + + shaderObject->setSource(count, string, length); + } +} + +void __stdcall glStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask); +} + +void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + EVENT("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask); - context->readPixels(x, y, width, height, format, type, NULL, pixels); + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return gl::error(GL_INVALID_ENUM); + } + + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GEQUAL: + case GL_GREATER: + case GL_NOTEQUAL: + break; + default: + return gl::error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilParams(func, ref, mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilBackParams(func, ref, mask); } } - catch(std::bad_alloc&) +} + +void __stdcall glStencilMask(GLuint mask) +{ + glStencilMaskSeparate(GL_FRONT_AND_BACK, mask); +} + +void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask) +{ + EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask); + + switch (face) { - return gl::error(GL_OUT_OF_MEMORY); + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return gl::error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilWritemask(mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilBackWritemask(mask); + } } } -void __stdcall glReleaseShaderCompiler(void) +void __stdcall glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { - EVENT("()"); + glStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass); +} + +void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + EVENT("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)", + face, fail, zfail, zpass); - try + switch (face) { - gl::Shader::releaseCompiler(); + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return gl::error(GL_INVALID_ENUM); } - catch(std::bad_alloc&) + + switch (fail) { - return gl::error(GL_OUT_OF_MEMORY); + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return gl::error(GL_INVALID_ENUM); + } + + switch (zfail) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return gl::error(GL_INVALID_ENUM); + } + + switch (zpass) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return gl::error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilOperations(fail, zfail, zpass); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilBackOperations(fail, zfail, zpass); + } } } -void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +GLboolean __stdcall glTestFenceNV(GLuint fence) { - EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", - target, samples, internalformat, width, height); + EVENT("(GLuint fence = %d)", fence); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - switch (target) + gl::FenceNV *fenceObject = context->getFenceNV(fence); + + if (fenceObject == NULL) { - case GL_RENDERBUFFER: - break; - default: - return gl::error(GL_INVALID_ENUM); + return gl::error(GL_INVALID_OPERATION, GL_TRUE); } - if (!gl::IsColorRenderable(internalformat) && !gl::IsDepthRenderable(internalformat) && !gl::IsStencilRenderable(internalformat)) + if (fenceObject->isFence() != GL_TRUE) { - return gl::error(GL_INVALID_ENUM); + return gl::error(GL_INVALID_OPERATION, GL_TRUE); } - if (width < 0 || height < 0 || samples < 0) + return fenceObject->testFence(); + } + + return GL_TRUE; +} + +void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const GLvoid* pixels) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, " + "GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)", + target, level, internalformat, width, height, border, format, type, pixels); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3 && + !ValidateES2TexImageParameters(context, target, level, internalformat, false, false, + 0, 0, width, height, border, format, type, pixels)) { - return gl::error(GL_INVALID_VALUE); + return; } - gl::Context *context = gl::getNonLostContext(); + if (context->getClientVersion() >= 3 && + !ValidateES3TexImageParameters(context, target, level, internalformat, false, false, + 0, 0, 0, width, height, 1, border, format, type, pixels)) + { + return; + } - if (context) + switch (target) { - if (width > context->getMaximumRenderbufferDimension() || - height > context->getMaximumRenderbufferDimension() || - samples > context->getMaxSupportedSamples()) + case GL_TEXTURE_2D: { - return gl::error(GL_INVALID_VALUE); + gl::Texture2D *texture = context->getTexture2D(); + texture->setImage(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); } - - GLuint handle = context->getRenderbufferHandle(); - if (handle == 0) + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: { - return gl::error(GL_INVALID_OPERATION); + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + texture->setImagePosX(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); } - - switch (internalformat) + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: { - case GL_DEPTH_COMPONENT16: - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGB565: - case GL_RGB8_OES: - case GL_RGBA8_OES: - case GL_STENCIL_INDEX8: - case GL_DEPTH24_STENCIL8_OES: - case GL_BGRA8_EXT: - context->setRenderbufferStorage(width, height, internalformat, samples); - break; - default: - return gl::error(GL_INVALID_ENUM); + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + texture->setImageNegX(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); + } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + texture->setImagePosY(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); + } + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + texture->setImageNegY(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + texture->setImagePosZ(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); + } + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + texture->setImageNegZ(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); + } + break; + default: UNREACHABLE(); } } - catch(std::bad_alloc&) +} + +void __stdcall glTexParameterf(GLenum target, GLenum pname, GLfloat param) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %f)", target, pname, param); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (!ValidateTexParamParameters(context, pname, static_cast<GLint>(param))) + { + return; + } + + gl::Texture *texture = context->getTargetTexture(target); + + if (!texture) + { + return gl::error(GL_INVALID_ENUM); + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: texture->getSamplerState().wrapS = gl::uiround<GLenum>(param); break; + case GL_TEXTURE_WRAP_T: texture->getSamplerState().wrapT = gl::uiround<GLenum>(param); break; + case GL_TEXTURE_WRAP_R: texture->getSamplerState().wrapR = gl::uiround<GLenum>(param); break; + case GL_TEXTURE_MIN_FILTER: texture->getSamplerState().minFilter = gl::uiround<GLenum>(param); break; + case GL_TEXTURE_MAG_FILTER: texture->getSamplerState().magFilter = gl::uiround<GLenum>(param); break; + case GL_TEXTURE_USAGE_ANGLE: texture->setUsage(gl::uiround<GLenum>(param)); break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->getSamplerState().maxAnisotropy = std::min(param, context->getExtensions().maxTextureAnisotropy); break; + case GL_TEXTURE_COMPARE_MODE: texture->getSamplerState().compareMode = gl::uiround<GLenum>(param); break; + case GL_TEXTURE_COMPARE_FUNC: texture->getSamplerState().compareFunc = gl::uiround<GLenum>(param); break; + case GL_TEXTURE_SWIZZLE_R: texture->getSamplerState().swizzleRed = gl::uiround<GLenum>(param); break; + case GL_TEXTURE_SWIZZLE_G: texture->getSamplerState().swizzleGreen = gl::uiround<GLenum>(param); break; + case GL_TEXTURE_SWIZZLE_B: texture->getSamplerState().swizzleBlue = gl::uiround<GLenum>(param); break; + case GL_TEXTURE_SWIZZLE_A: texture->getSamplerState().swizzleAlpha = gl::uiround<GLenum>(param); break; + case GL_TEXTURE_BASE_LEVEL: texture->getSamplerState().baseLevel = gl::iround<GLint>(param); break; + case GL_TEXTURE_MAX_LEVEL: texture->getSamplerState().maxLevel = gl::iround<GLint>(param); break; + case GL_TEXTURE_MIN_LOD: texture->getSamplerState().minLod = param; break; + case GL_TEXTURE_MAX_LOD: texture->getSamplerState().maxLod = param; break; + default: UNREACHABLE(); break; + } } } -void __stdcall glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +void __stdcall glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) { - glRenderbufferStorageMultisampleANGLE(target, 0, internalformat, width, height); + glTexParameterf(target, pname, (GLfloat)*params); } -void __stdcall glSampleCoverage(GLclampf value, GLboolean invert) +void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param) { - EVENT("(GLclampf value = %f, GLboolean invert = %d)", value, invert); + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - gl::Context* context = gl::getNonLostContext(); + if (!ValidateTexParamParameters(context, pname, param)) + { + return; + } - if (context) + gl::Texture *texture = context->getTargetTexture(target); + + if (!texture) { - context->setSampleCoverageParams(gl::clamp01(value), invert == GL_TRUE); + return gl::error(GL_INVALID_ENUM); + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: texture->getSamplerState().wrapS = (GLenum)param; break; + case GL_TEXTURE_WRAP_T: texture->getSamplerState().wrapT = (GLenum)param; break; + case GL_TEXTURE_WRAP_R: texture->getSamplerState().wrapR = (GLenum)param; break; + case GL_TEXTURE_MIN_FILTER: texture->getSamplerState().minFilter = (GLenum)param; break; + case GL_TEXTURE_MAG_FILTER: texture->getSamplerState().magFilter = (GLenum)param; break; + case GL_TEXTURE_USAGE_ANGLE: texture->setUsage((GLenum)param); break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->getSamplerState().maxAnisotropy = std::min((float)param, context->getExtensions().maxTextureAnisotropy); break; + case GL_TEXTURE_COMPARE_MODE: texture->getSamplerState().compareMode = (GLenum)param; break; + case GL_TEXTURE_COMPARE_FUNC: texture->getSamplerState().compareFunc = (GLenum)param; break; + case GL_TEXTURE_SWIZZLE_R: texture->getSamplerState().swizzleRed = (GLenum)param; break; + case GL_TEXTURE_SWIZZLE_G: texture->getSamplerState().swizzleGreen = (GLenum)param; break; + case GL_TEXTURE_SWIZZLE_B: texture->getSamplerState().swizzleBlue = (GLenum)param; break; + case GL_TEXTURE_SWIZZLE_A: texture->getSamplerState().swizzleAlpha = (GLenum)param; break; + case GL_TEXTURE_BASE_LEVEL: texture->getSamplerState().baseLevel = param; break; + case GL_TEXTURE_MAX_LEVEL: texture->getSamplerState().maxLevel = param; break; + case GL_TEXTURE_MIN_LOD: texture->getSamplerState().minLod = (GLfloat)param; break; + case GL_TEXTURE_MAX_LOD: texture->getSamplerState().maxLod = (GLfloat)param; break; + default: UNREACHABLE(); break; } } - catch(std::bad_alloc&) +} + +void __stdcall glTexParameteriv(GLenum target, GLenum pname, const GLint* params) +{ + glTexParameteri(target, pname, *params); +} + +void __stdcall glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + target, levels, internalformat, width, height); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (!context->getExtensions().textureStorage) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (context->getClientVersion() < 3 && + !ValidateES2TexStorageParameters(context, target, levels, internalformat, width, height)) + { + return; + } + + if (context->getClientVersion() >= 3 && + !ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, 1)) + { + return; + } + + switch (target) + { + case GL_TEXTURE_2D: + { + gl::Texture2D *texture2d = context->getTexture2D(); + texture2d->storage(levels, internalformat, width, height); + } + break; + + case GL_TEXTURE_CUBE_MAP: + { + gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); + textureCube->storage(levels, internalformat, width); + } + break; + + default: + return gl::error(GL_INVALID_ENUM); + } } } -void __stdcall glSetFenceNV(GLuint fence, GLenum condition) +void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLenum type, const GLvoid* pixels) { - EVENT("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition); + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, " + "const GLvoid* pixels = 0x%0.8p)", + target, level, xoffset, yoffset, width, height, format, type, pixels); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (condition != GL_ALL_COMPLETED_NV) + if (context->getClientVersion() < 3 && + !ValidateES2TexImageParameters(context, target, level, GL_NONE, false, true, + xoffset, yoffset, width, height, 0, format, type, pixels)) { - return gl::error(GL_INVALID_ENUM); + return; + } + + if (context->getClientVersion() >= 3 && + !ValidateES3TexImageParameters(context, target, level, GL_NONE, false, true, + xoffset, yoffset, 0, width, height, 1, 0, format, type, pixels)) + { + return; } - gl::Context *context = gl::getNonLostContext(); + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0) + { + return; + } - if (context) + switch (target) { - gl::Fence *fenceObject = context->getFence(fence); + case GL_TEXTURE_2D: + { + gl::Texture2D *texture = context->getTexture2D(); + texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getState().getUnpackState(), pixels); + } + break; - if (fenceObject == NULL) + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { - return gl::error(GL_INVALID_OPERATION); + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getState().getUnpackState(), pixels); } + break; - fenceObject->setFence(condition); + default: + UNREACHABLE(); } } - catch(std::bad_alloc&) +} + +void __stdcall glUniform1f(GLint location, GLfloat x) +{ + glUniform1fv(location, 1, &x); +} + +void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (!ValidateUniform(context, GL_FLOAT, location, count)) + { + return; + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform1fv(location, count, v); } } -void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height) +void __stdcall glUniform1i(GLint location, GLint x) { - EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); + glUniform1iv(location, 1, &x); +} - try +void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (width < 0 || height < 0) + if (!ValidateUniform(context, GL_INT, location, count)) { - return gl::error(GL_INVALID_VALUE); + return; } - gl::Context* context = gl::getNonLostContext(); + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform1iv(location, count, v); + } +} - if (context) +void __stdcall glUniform2f(GLint location, GLfloat x, GLfloat y) +{ + GLfloat xy[2] = {x, y}; + + glUniform2fv(location, 1, xy); +} + +void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!ValidateUniform(context, GL_FLOAT_VEC2, location, count)) { - context->setScissorParams(x, y, width, height); + return; } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform2fv(location, count, v); } - catch(std::bad_alloc&) +} + +void __stdcall glUniform2i(GLint location, GLint x, GLint y) +{ + GLint xy[2] = {x, y}; + + glUniform2iv(location, 1, xy); +} + +void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (!ValidateUniform(context, GL_INT_VEC2, location, count)) + { + return; + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform2iv(location, count, v); } } -void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +void __stdcall glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) { - EVENT("(GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, " - "const GLvoid* binary = 0x%0.8p, GLsizei length = %d)", - n, shaders, binaryformat, binary, length); + GLfloat xyz[3] = {x, y, z}; + + glUniform3fv(location, 1, xyz); +} + +void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - // No binary shader formats are supported. - return gl::error(GL_INVALID_ENUM); + if (!ValidateUniform(context, GL_FLOAT_VEC3, location, count)) + { + return; + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform3fv(location, count, v); } - catch(std::bad_alloc&) +} + +void __stdcall glUniform3i(GLint location, GLint x, GLint y, GLint z) +{ + GLint xyz[3] = {x, y, z}; + + glUniform3iv(location, 1, xyz); +} + +void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (!ValidateUniform(context, GL_INT_VEC3, location, count)) + { + return; + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform3iv(location, count, v); } } -void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) +void __stdcall glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { - EVENT("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)", - shader, count, string, length); + GLfloat xyzw[4] = {x, y, z, w}; + + glUniform4fv(location, 1, xyzw); +} - try +void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (count < 0) + if (!ValidateUniform(context, GL_FLOAT_VEC4, location, count)) { - return gl::error(GL_INVALID_VALUE); + return; } - gl::Context *context = gl::getNonLostContext(); + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform4fv(location, count, v); + } +} - if (context) +void __stdcall glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +{ + GLint xyzw[4] = {x, y, z, w}; + + glUniform4iv(location, 1, xyzw); +} + +void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!ValidateUniform(context, GL_INT_VEC4, location, count)) { - gl::Shader *shaderObject = context->getShader(shader); + return; + } - if (!shaderObject) - { - if (context->getProgram(shader)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } - } + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform4iv(location, count, v); + } +} - shaderObject->setSource(count, string, length); +void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2, location, count, transpose)) + { + return; } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniformMatrix2fv(location, count, transpose, value); } - catch(std::bad_alloc&) +} + +void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3, location, count, transpose)) + { + return; + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniformMatrix3fv(location, count, transpose, value); } } -void __stdcall glStencilFunc(GLenum func, GLint ref, GLuint mask) +void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask); + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4, location, count, transpose)) + { + return; + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniformMatrix4fv(location, count, transpose, value); + } } -void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +void __stdcall glUseProgram(GLuint program) { - EVENT("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask); + EVENT("(GLuint program = %d)", program); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - switch (face) + gl::Program *programObject = context->getProgram(program); + + if (!programObject && program != 0) { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - break; - default: - return gl::error(GL_INVALID_ENUM); + if (context->getShader(program)) + { + return gl::error(GL_INVALID_OPERATION); + } + else + { + return gl::error(GL_INVALID_VALUE); + } } - switch (func) + if (program != 0 && !programObject->isLinked()) { - case GL_NEVER: - case GL_ALWAYS: - case GL_LESS: - case GL_LEQUAL: - case GL_EQUAL: - case GL_GEQUAL: - case GL_GREATER: - case GL_NOTEQUAL: - break; - default: - return gl::error(GL_INVALID_ENUM); + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); + context->useProgram(program); + } +} + +void __stdcall glValidateProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) { - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + if (context->getShader(program)) { - context->setStencilParams(func, ref, mask); + return gl::error(GL_INVALID_OPERATION); } - - if (face == GL_BACK || face == GL_FRONT_AND_BACK) + else { - context->setStencilBackParams(func, ref, mask); + return gl::error(GL_INVALID_VALUE); } } + + programObject->validate(); + } +} + +void __stdcall glVertexAttrib1f(GLuint index, GLfloat x) +{ + EVENT("(GLuint index = %d, GLfloat x = %f)", index, x); + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); } - catch(std::bad_alloc&) + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + GLfloat vals[4] = { x, 0, 0, 1 }; + context->getState().setVertexAttribf(index, vals); } } -void __stdcall glStencilMask(GLuint mask) +void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values) { - glStencilMaskSeparate(GL_FRONT_AND_BACK, mask); + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { values[0], 0, 0, 1 }; + context->getState().setVertexAttribf(index, vals); + } } -void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask) +void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) { - EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask); + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y); - try + if (index >= gl::MAX_VERTEX_ATTRIBS) { - switch (face) + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { x, y, 0, 1 }; + context->getState().setVertexAttribf(index, vals); + } +} + +void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { values[0], values[1], 0, 1 }; + context->getState().setVertexAttribf(index, vals); + } +} + +void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z); + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { x, y, z, 1 }; + context->getState().setVertexAttribf(index, vals); + } +} + +void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { values[0], values[1], values[2], 1 }; + context->getState().setVertexAttribf(index, vals); + } +} + +void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w); + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { x, y, z, w }; + context->getState().setVertexAttribf(index, vals); + } +} + +void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->getState().setVertexAttribf(index, values); + } +} + +void __stdcall glVertexAttribDivisorANGLE(GLuint index, GLuint divisor) +{ + EVENT("(GLuint index = %d, GLuint divisor = %d)", index, divisor); + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setVertexAttribDivisor(index, divisor); + } +} + +void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) +{ + EVENT("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, " + "GLboolean normalized = %u, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)", + index, size, type, normalized, stride, ptr); + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); + } + + if (size < 1 || size > 4) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + switch (type) + { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_FIXED: + case GL_FLOAT: + break; + case GL_HALF_FLOAT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_2_10_10_10_REV: + if (context && context->getClientVersion() < 3) { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - break; - default: return gl::error(GL_INVALID_ENUM); } + else + { + break; + } + default: + return gl::error(GL_INVALID_ENUM); + } - gl::Context *context = gl::getNonLostContext(); + if (stride < 0) + { + return gl::error(GL_INVALID_VALUE); + } - if (context) - { - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) - { - context->setStencilWritemask(mask); - } + if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4) + { + return gl::error(GL_INVALID_OPERATION); + } - if (face == GL_BACK || face == GL_FRONT_AND_BACK) - { - context->setStencilBackWritemask(mask); - } + if (context) + { + // [OpenGL ES 3.0.2] Section 2.8 page 24: + // An INVALID_OPERATION error is generated when a non-zero vertex array object + // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, + // and the pointer argument is not NULL. + if (context->getState().getVertexArray()->id() != 0 && context->getState().getArrayBufferId() == 0 && ptr != NULL) + { + return gl::error(GL_INVALID_OPERATION); } + + context->getState().setVertexAttribState(index, context->getState().getTargetBuffer(GL_ARRAY_BUFFER), size, type, + normalized == GL_TRUE, false, stride, ptr); } - catch(std::bad_alloc&) +} + +void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); + + if (width < 0 || height < 0) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + context->getState().setViewportParams(x, y, width, height); } } -void __stdcall glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) +// OpenGL ES 3.0 functions + +void __stdcall glReadBuffer(GLenum mode) { - glStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass); + EVENT("(GLenum mode = 0x%X)", mode); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + // glReadBuffer + UNIMPLEMENTED(); + } } -void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +void __stdcall glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices) { - EVENT("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)", - face, fail, zfail, zpass); + EVENT("(GLenum mode = 0x%X, GLuint start = %u, GLuint end = %u, GLsizei count = %d, GLenum type = 0x%X, " + "const GLvoid* indices = 0x%0.8p)", mode, start, end, count, type, indices); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - switch (face) + if (context->getClientVersion() < 3) { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: + return gl::error(GL_INVALID_OPERATION); + } + + // glDrawRangeElements + UNIMPLEMENTED(); + } +} + +void __stdcall glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, " + "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLenum format = 0x%X, " + "GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)", + target, level, internalformat, width, height, depth, border, format, type, pixels); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + // validateES3TexImageFormat sets the error code if there is an error + if (!ValidateES3TexImageParameters(context, target, level, internalformat, false, false, + 0, 0, 0, width, height, depth, border, format, type, pixels)) + { + return; + } + + switch(target) + { + case GL_TEXTURE_3D: + { + gl::Texture3D *texture = context->getTexture3D(); + texture->setImage(level, width, height, depth, internalformat, format, type, context->getState().getUnpackState(), pixels); + } + break; + + case GL_TEXTURE_2D_ARRAY: + { + gl::Texture2DArray *texture = context->getTexture2DArray(); + texture->setImage(level, width, height, depth, internalformat, format, type, context->getState().getUnpackState(), pixels); + } break; + default: return gl::error(GL_INVALID_ENUM); } + } +} + +void __stdcall glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " + "GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)", + target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); - switch (fail) + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + // validateES3TexImageFormat sets the error code if there is an error + if (!ValidateES3TexImageParameters(context, target, level, GL_NONE, false, true, + xoffset, yoffset, zoffset, width, height, depth, 0, + format, type, pixels)) + { + return; + } + + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0 || depth == 0) { - case GL_ZERO: - case GL_KEEP: - case GL_REPLACE: - case GL_INCR: - case GL_DECR: - case GL_INVERT: - case GL_INCR_WRAP: - case GL_DECR_WRAP: + return; + } + + switch(target) + { + case GL_TEXTURE_3D: + { + gl::Texture3D *texture = context->getTexture3D(); + texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getState().getUnpackState(), pixels); + } + break; + + case GL_TEXTURE_2D_ARRAY: + { + gl::Texture2DArray *texture = context->getTexture2DArray(); + texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getState().getUnpackState(), pixels); + } break; + default: return gl::error(GL_INVALID_ENUM); } + } +} + +void __stdcall glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLint zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", + target, level, xoffset, yoffset, zoffset, x, y, width, height); - switch (zfail) + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) { - case GL_ZERO: - case GL_KEEP: - case GL_REPLACE: - case GL_INCR: - case GL_DECR: - case GL_INVERT: - case GL_INCR_WRAP: - case GL_DECR_WRAP: + return gl::error(GL_INVALID_OPERATION); + } + + if (!ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset, yoffset, zoffset, + x, y, width, height, 0)) + { + return; + } + + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + gl::Texture *texture = NULL; + switch (target) + { + case GL_TEXTURE_3D: + texture = context->getTexture3D(); break; + + case GL_TEXTURE_2D_ARRAY: + texture = context->getTexture2DArray(); + break; + default: return gl::error(GL_INVALID_ENUM); } - switch (zpass) + texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, framebuffer); + } +} + +void __stdcall glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " + "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, " + "const GLvoid* data = 0x%0.8p)", + target, level, internalformat, width, height, depth, border, imageSize, data); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) { - case GL_ZERO: - case GL_KEEP: - case GL_REPLACE: - case GL_INCR: - case GL_DECR: - case GL_INVERT: - case GL_INCR_WRAP: - case GL_DECR_WRAP: + return gl::error(GL_INVALID_OPERATION); + } + + if (imageSize < 0 || imageSize != (GLsizei)gl::GetBlockSize(internalformat, GL_UNSIGNED_BYTE, width, height)) + { + return gl::error(GL_INVALID_VALUE); + } + + // validateES3TexImageFormat sets the error code if there is an error + if (!ValidateES3TexImageParameters(context, target, level, internalformat, true, false, + 0, 0, 0, width, height, depth, border, GL_NONE, GL_NONE, data)) + { + return; + } + + switch(target) + { + case GL_TEXTURE_3D: + { + gl::Texture3D *texture = context->getTexture3D(); + texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data); + } + break; + + case GL_TEXTURE_2D_ARRAY: + { + gl::Texture2DArray *texture = context->getTexture2DArray(); + texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data); + } break; + default: return gl::error(GL_INVALID_ENUM); } + } +} + +void __stdcall glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " + "GLenum format = 0x%X, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", + target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (imageSize < 0 || imageSize != (GLsizei)gl::GetBlockSize(format, GL_UNSIGNED_BYTE, width, height)) + { + return gl::error(GL_INVALID_VALUE); + } - gl::Context *context = gl::getNonLostContext(); + if (!data) + { + return gl::error(GL_INVALID_VALUE); + } - if (context) + // validateES3TexImageFormat sets the error code if there is an error + if (!ValidateES3TexImageParameters(context, target, level, GL_NONE, true, true, + 0, 0, 0, width, height, depth, 0, GL_NONE, GL_NONE, data)) { - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + return; + } + + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0) + { + return; + } + + switch(target) + { + case GL_TEXTURE_3D: { - context->setStencilOperations(fail, zfail, zpass); + gl::Texture3D *texture = context->getTexture3D(); + texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, + format, imageSize, data); } + break; - if (face == GL_BACK || face == GL_FRONT_AND_BACK) + case GL_TEXTURE_2D_ARRAY: { - context->setStencilBackOperations(fail, zfail, zpass); + gl::Texture2DArray *texture = context->getTexture2DArray(); + texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, + format, imageSize, data); } + break; + + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) +} + +void __stdcall glGenQueries(GLsizei n, GLuint* ids) +{ + EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (n < 0) + { + return gl::error(GL_INVALID_VALUE); + } + + for (GLsizei i = 0; i < n; i++) + { + ids[i] = context->createQuery(); + } } } -GLboolean __stdcall glTestFenceNV(GLuint fence) +void __stdcall glDeleteQueries(GLsizei n, const GLuint* ids) { - EVENT("(GLuint fence = %d)", fence); + EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - gl::Context *context = gl::getNonLostContext(); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } - if (context) + if (n < 0) { - gl::Fence *fenceObject = context->getFence(fence); + return gl::error(GL_INVALID_VALUE); + } - if (fenceObject == NULL) - { - return gl::error(GL_INVALID_OPERATION, GL_TRUE); - } + for (GLsizei i = 0; i < n; i++) + { + context->deleteQuery(ids[i]); + } + } +} - return fenceObject->testFence(); +GLboolean __stdcall glIsQuery(GLuint id) +{ + EVENT("(GLuint id = %u)", id); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, GL_FALSE); } + + return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE; } - catch(std::bad_alloc&) + + return GL_FALSE; +} + +void __stdcall glBeginQuery(GLenum target, GLuint id) +{ + EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (!ValidateBeginQuery(context, target, id)) + { + return; + } + context->beginQuery(target, id); } - - return GL_TRUE; } -void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, - GLint border, GLenum format, GLenum type, const GLvoid* pixels) +void __stdcall glEndQuery(GLenum target) { - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, " - "GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)", - target, level, internalformat, width, height, border, format, type, pixels); + EVENT("(GLenum target = 0x%X)", target); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (!validImageSize(level, width, height)) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - if (internalformat != GLint(format)) + if (!ValidateEndQuery(context, target)) + { + return; + } + + context->endQuery(target); + } +} + +void __stdcall glGetQueryiv(GLenum target, GLenum pname, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) { return gl::error(GL_INVALID_OPERATION); } - // validate <type> by itself (used as secondary key below) - switch (type) + if (!ValidQueryType(context, target)) + { + return gl::error(GL_INVALID_ENUM); + } + + switch (pname) { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT: - case GL_UNSIGNED_INT: - case GL_UNSIGNED_INT_24_8_OES: - case GL_HALF_FLOAT_OES: - case GL_FLOAT: + case GL_CURRENT_QUERY: + params[0] = static_cast<GLint>(context->getState().getActiveQueryId(target)); break; + default: return gl::error(GL_INVALID_ENUM); } + } +} - // validate <format> + <type> combinations - // - invalid <format> -> sets INVALID_ENUM - // - invalid <format>+<type> combination -> sets INVALID_OPERATION - switch (format) +void __stdcall glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) +{ + EVENT("(GLuint id = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", id, pname, params); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) { - case GL_ALPHA: - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_FLOAT: - case GL_HALF_FLOAT_OES: - break; - default: - return gl::error(GL_INVALID_OPERATION); - } - break; - case GL_RGB: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_5_6_5: - case GL_FLOAT: - case GL_HALF_FLOAT_OES: - break; - default: - return gl::error(GL_INVALID_OPERATION); - } - break; - case GL_RGBA: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_FLOAT: - case GL_HALF_FLOAT_OES: - break; - default: - return gl::error(GL_INVALID_OPERATION); - } - break; - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - return gl::error(GL_INVALID_OPERATION); - } - break; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - break; - case GL_DEPTH_COMPONENT: - switch (type) - { - case GL_UNSIGNED_SHORT: - case GL_UNSIGNED_INT: - break; - default: - return gl::error(GL_INVALID_OPERATION); - } + return gl::error(GL_INVALID_OPERATION); + } + + gl::Query *queryObject = context->getQuery(id, false, GL_NONE); + + if (!queryObject) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (context->getState().getActiveQueryId(queryObject->getType()) == id) + { + return gl::error(GL_INVALID_OPERATION); + } + + switch(pname) + { + case GL_QUERY_RESULT: + params[0] = queryObject->getResult(); break; - case GL_DEPTH_STENCIL_OES: - switch (type) - { - case GL_UNSIGNED_INT_24_8_OES: - break; - default: - return gl::error(GL_INVALID_OPERATION); - } + case GL_QUERY_RESULT_AVAILABLE: + params[0] = queryObject->isResultAvailable(); break; default: return gl::error(GL_INVALID_ENUM); } + } +} + +GLboolean __stdcall glUnmapBuffer(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + gl::Context *context = gl::getNonLostContext(); - if (border != 0) + if (context) + { + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION, GL_FALSE); } - gl::Context *context = gl::getNonLostContext(); + return glUnmapBufferOES(target); + } + + return GL_FALSE; +} + +void __stdcall glGetBufferPointerv(GLenum target, GLenum pname, GLvoid** params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params); + + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (context->getClientVersion() < 3) { - if (level > context->getMaximumTextureLevel()) - { - return gl::error(GL_INVALID_VALUE); - } + return gl::error(GL_INVALID_OPERATION); + } - switch (target) - { - case GL_TEXTURE_2D: - if (width > (context->getMaximumTextureDimension() >> level) || - height > (context->getMaximumTextureDimension() >> level)) - { - return gl::error(GL_INVALID_VALUE); - } - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - if (width != height) - { - return gl::error(GL_INVALID_VALUE); - } + glGetBufferPointervOES(target, pname, params); + } +} - if (width > (context->getMaximumCubeTextureDimension() >> level) || - height > (context->getMaximumCubeTextureDimension() >> level)) - { - return gl::error(GL_INVALID_VALUE); - } - break; - default: - return gl::error(GL_INVALID_ENUM); - } +void __stdcall glDrawBuffers(GLsizei n, const GLenum* bufs) +{ + gl::Context *context = gl::getNonLostContext(); - switch (format) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (context->supportsDXT1Textures()) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (context->supportsDXT3Textures()) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (context->supportsDXT5Textures()) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_STENCIL_OES: - if (!context->supportsDepthTextures()) - { - return gl::error(GL_INVALID_VALUE); - } - if (target != GL_TEXTURE_2D) - { - return gl::error(GL_INVALID_OPERATION); - } - // OES_depth_texture supports loading depth data and multiple levels, - // but ANGLE_depth_texture does not - if (pixels != NULL || level != 0) - { - return gl::error(GL_INVALID_OPERATION); - } - break; - default: - break; - } + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } - if (type == GL_FLOAT) - { - if (!context->supportsFloat32Textures()) - { - return gl::error(GL_INVALID_ENUM); - } - } - else if (type == GL_HALF_FLOAT_OES) - { - if (!context->supportsFloat16Textures()) - { - return gl::error(GL_INVALID_ENUM); - } - } + glDrawBuffersEXT(n, bufs); + } +} - if (target == GL_TEXTURE_2D) - { - gl::Texture2D *texture = context->getTexture2D(); +void __stdcall glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); - if (!texture) - { - return gl::error(GL_INVALID_OPERATION); - } + gl::Context *context = gl::getNonLostContext(); - if (texture->isImmutable()) - { - return gl::error(GL_INVALID_OPERATION); - } + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2x3, location, count, transpose)) + { + return; + } - texture->setImage(level, width, height, format, type, context->getUnpackAlignment(), pixels); - } - else - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniformMatrix2x3fv(location, count, transpose, value); + } +} - if (!texture) - { - return gl::error(GL_INVALID_OPERATION); - } +void __stdcall glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); - if (texture->isImmutable()) - { - return gl::error(GL_INVALID_OPERATION); - } + gl::Context *context = gl::getNonLostContext(); - switch (target) - { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - texture->setImagePosX(level, width, height, format, type, context->getUnpackAlignment(), pixels); - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - texture->setImageNegX(level, width, height, format, type, context->getUnpackAlignment(), pixels); - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - texture->setImagePosY(level, width, height, format, type, context->getUnpackAlignment(), pixels); - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - texture->setImageNegY(level, width, height, format, type, context->getUnpackAlignment(), pixels); - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - texture->setImagePosZ(level, width, height, format, type, context->getUnpackAlignment(), pixels); - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - texture->setImageNegZ(level, width, height, format, type, context->getUnpackAlignment(), pixels); - break; - default: UNREACHABLE(); - } - } + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3x2, location, count, transpose)) + { + return; } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniformMatrix3x2fv(location, count, transpose, value); } - catch(std::bad_alloc&) +} + +void __stdcall glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2x4, location, count, transpose)) + { + return; + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniformMatrix2x4fv(location, count, transpose, value); } } -void __stdcall glTexParameterf(GLenum target, GLenum pname, GLfloat param) +void __stdcall glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %f)", target, pname, param); + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4x2, location, count, transpose)) { - gl::Texture *texture; + return; + } - switch (target) - { - case GL_TEXTURE_2D: - texture = context->getTexture2D(); - break; - case GL_TEXTURE_CUBE_MAP: - texture = context->getTextureCubeMap(); - break; - default: - return gl::error(GL_INVALID_ENUM); - } + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniformMatrix4x2fv(location, count, transpose, value); + } +} - switch (pname) - { - case GL_TEXTURE_WRAP_S: - if (!texture->setWrapS((GLenum)param)) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_TEXTURE_WRAP_T: - if (!texture->setWrapT((GLenum)param)) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_TEXTURE_MIN_FILTER: - if (!texture->setMinFilter((GLenum)param)) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_TEXTURE_MAG_FILTER: - if (!texture->setMagFilter((GLenum)param)) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_TEXTURE_USAGE_ANGLE: - if (!texture->setUsage((GLenum)param)) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (!context->supportsTextureFilterAnisotropy()) - { - return gl::error(GL_INVALID_ENUM); - } - if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy())) - { - return gl::error(GL_INVALID_VALUE); - } - break; - default: - return gl::error(GL_INVALID_ENUM); - } +void __stdcall glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3x4, location, count, transpose)) + { + return; } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniformMatrix3x4fv(location, count, transpose, value); } - catch(std::bad_alloc&) +} + +void __stdcall glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4x3, location, count, transpose)) + { + return; + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniformMatrix4x3fv(location, count, transpose, value); } } -void __stdcall glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) +void __stdcall glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { - glTexParameterf(target, pname, (GLfloat)*params); + EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, GLint dstX0 = %d, " + "GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, GLbitfield mask = 0x%X, GLenum filter = 0x%X)", + srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + + gl::Context *context = gl::getNonLostContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, mask, filter, + false)) + { + return; + } + + context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, + mask, filter); + } } -void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param) +void __stdcall glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param); + EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + target, samples, internalformat, width, height); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - gl::Context *context = gl::getNonLostContext(); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } - if (context) + if (!ValidateRenderbufferStorageParameters(context, target, samples, internalformat, + width, height, false)) { - gl::Texture *texture; + return; + } - switch (target) - { - case GL_TEXTURE_2D: - texture = context->getTexture2D(); - break; - case GL_TEXTURE_CUBE_MAP: - texture = context->getTextureCubeMap(); - break; - default: - return gl::error(GL_INVALID_ENUM); - } + context->setRenderbufferStorage(width, height, internalformat, samples); + } +} - switch (pname) +void __stdcall glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) +{ + EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, GLint layer = %d)", + target, attachment, texture, level, layer); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!ValidateFramebufferTextureLayer(context, target, attachment, texture, + level, layer)) + { + return; + } + + gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + gl::Texture *textureObject = context->getTexture(texture); + GLenum textarget = textureObject ? textureObject->getTarget() : GL_NONE; + + if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + { + const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + framebuffer->setColorbuffer(colorAttachment, textarget, texture, level, layer); + } + else + { + switch (attachment) { - case GL_TEXTURE_WRAP_S: - if (!texture->setWrapS((GLenum)param)) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_TEXTURE_WRAP_T: - if (!texture->setWrapT((GLenum)param)) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_TEXTURE_MIN_FILTER: - if (!texture->setMinFilter((GLenum)param)) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_TEXTURE_MAG_FILTER: - if (!texture->setMagFilter((GLenum)param)) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_TEXTURE_USAGE_ANGLE: - if (!texture->setUsage((GLenum)param)) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (!context->supportsTextureFilterAnisotropy()) - { - return gl::error(GL_INVALID_ENUM); - } - if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy())) - { - return gl::error(GL_INVALID_VALUE); - } - break; - default: - return gl::error(GL_INVALID_ENUM); + case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture, level, layer); break; + case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture, level, layer); break; + case GL_DEPTH_STENCIL_ATTACHMENT: framebuffer->setDepthStencilBuffer(textarget, texture, level, layer); break; } } } - catch(std::bad_alloc&) +} + +GLvoid* __stdcall glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +{ + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)", + target, offset, length, access); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, reinterpret_cast<GLvoid*>(NULL)); + } + + return glMapBufferRangeEXT(target, offset, length, access); } + + return NULL; } -void __stdcall glTexParameteriv(GLenum target, GLenum pname, const GLint* params) +void __stdcall glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) { - glTexParameteri(target, pname, *params); + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + glFlushMappedBufferRangeEXT(target, offset, length); + } } -void __stdcall glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +void __stdcall glBindVertexArray(GLuint array) { - EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", - target, levels, internalformat, width, height); + EVENT("(GLuint array = %u)", array); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_ENUM); + return gl::error(GL_INVALID_OPERATION); } - if (width < 1 || height < 1 || levels < 1) + gl::VertexArray *vao = context->getVertexArray(array); + + if (!vao) { - return gl::error(GL_INVALID_VALUE); + // The default VAO should always exist + ASSERT(array != 0); + return gl::error(GL_INVALID_OPERATION); } - if (target == GL_TEXTURE_CUBE_MAP && width != height) + context->bindVertexArray(array); + } +} + +void __stdcall glDeleteVertexArrays(GLsizei n, const GLuint* arrays) +{ + EVENT("(GLsizei n = %d, const GLuint* arrays = 0x%0.8p)", n, arrays); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (n < 0) { return gl::error(GL_INVALID_VALUE); } - if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) + for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) + { + if (arrays[arrayIndex] != 0) + { + context->deleteVertexArray(arrays[arrayIndex]); + } + } + } +} + +void __stdcall glGenVertexArrays(GLsizei n, GLuint* arrays) +{ + EVENT("(GLsizei n = %d, GLuint* arrays = 0x%0.8p)", n, arrays); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) { return gl::error(GL_INVALID_OPERATION); } - GLenum format = gl::ExtractFormat(internalformat); - GLenum type = gl::ExtractType(internalformat); + if (n < 0) + { + return gl::error(GL_INVALID_VALUE); + } - if (format == GL_NONE || type == GL_NONE) + for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) { - return gl::error(GL_INVALID_ENUM); + arrays[arrayIndex] = context->createVertexArray(); } + } +} + +GLboolean __stdcall glIsVertexArray(GLuint array) +{ + EVENT("(GLuint array = %u)", array); - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (context->getClientVersion() < 3) { - switch (target) - { - case GL_TEXTURE_2D: - if (width > context->getMaximumTextureDimension() || - height > context->getMaximumTextureDimension()) - { - return gl::error(GL_INVALID_VALUE); - } - break; - case GL_TEXTURE_CUBE_MAP: - if (width > context->getMaximumCubeTextureDimension() || - height > context->getMaximumCubeTextureDimension()) - { - return gl::error(GL_INVALID_VALUE); - } - break; - default: - return gl::error(GL_INVALID_ENUM); - } + return gl::error(GL_INVALID_OPERATION, GL_FALSE); + } - if (levels != 1 && !context->supportsNonPower2Texture()) - { - if (!gl::isPow2(width) || !gl::isPow2(height)) - { - return gl::error(GL_INVALID_OPERATION); - } - } + if (array == 0) + { + return GL_FALSE; + } - switch (internalformat) - { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (!context->supportsDXT1Textures()) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (!context->supportsDXT3Textures()) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (!context->supportsDXT5Textures()) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_RGBA32F_EXT: - case GL_RGB32F_EXT: - case GL_ALPHA32F_EXT: - case GL_LUMINANCE32F_EXT: - case GL_LUMINANCE_ALPHA32F_EXT: - if (!context->supportsFloat32Textures()) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_RGBA16F_EXT: - case GL_RGB16F_EXT: - case GL_ALPHA16F_EXT: - case GL_LUMINANCE16F_EXT: - case GL_LUMINANCE_ALPHA16F_EXT: - if (!context->supportsFloat16Textures()) - { - return gl::error(GL_INVALID_ENUM); - } - break; - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT32_OES: - case GL_DEPTH24_STENCIL8_OES: - if (!context->supportsDepthTextures()) - { - return gl::error(GL_INVALID_ENUM); - } - if (target != GL_TEXTURE_2D) - { - return gl::error(GL_INVALID_OPERATION); - } - // ANGLE_depth_texture only supports 1-level textures - if (levels != 1) - { - return gl::error(GL_INVALID_OPERATION); - } - break; - default: - break; - } + gl::VertexArray *vao = context->getVertexArray(array); - if (target == GL_TEXTURE_2D) - { - gl::Texture2D *texture = context->getTexture2D(); + return (vao != NULL ? GL_TRUE : GL_FALSE); + } - if (!texture || texture->id() == 0) - { - return gl::error(GL_INVALID_OPERATION); - } + return GL_FALSE; +} - if (texture->isImmutable()) - { - return gl::error(GL_INVALID_OPERATION); - } +void __stdcall glGetIntegeri_v(GLenum target, GLuint index, GLint* data) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint* data = 0x%0.8p)", + target, index, data); - texture->storage(levels, internalformat, width, height); - } - else if (target == GL_TEXTURE_CUBE_MAP) + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (index >= context->getMaxTransformFeedbackBufferBindings()) + return gl::error(GL_INVALID_VALUE); + break; + case GL_UNIFORM_BUFFER_START: + case GL_UNIFORM_BUFFER_SIZE: + case GL_UNIFORM_BUFFER_BINDING: + if (index >= context->getMaximumCombinedUniformBufferBindings()) + return gl::error(GL_INVALID_VALUE); + break; + default: + return gl::error(GL_INVALID_ENUM); + } + + if (!(context->getIndexedIntegerv(target, index, data))) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!context->getIndexedQueryParameterInfo(target, &nativeType, &numParams)) + return gl::error(GL_INVALID_ENUM); + + if (numParams == 0) + return; // it is known that pname is valid, but there are no parameters to return + + if (nativeType == GL_INT_64_ANGLEX) { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); + GLint64 minIntValue = static_cast<GLint64>(std::numeric_limits<int>::min()); + GLint64 maxIntValue = static_cast<GLint64>(std::numeric_limits<int>::max()); + GLint64 *int64Params = new GLint64[numParams]; - if (!texture || texture->id() == 0) - { - return gl::error(GL_INVALID_OPERATION); - } + context->getIndexedInteger64v(target, index, int64Params); - if (texture->isImmutable()) + for (unsigned int i = 0; i < numParams; ++i) { - return gl::error(GL_INVALID_OPERATION); + GLint64 clampedValue = std::max(std::min(int64Params[i], maxIntValue), minIntValue); + data[i] = static_cast<GLint>(clampedValue); } - texture->storage(levels, internalformat, width); + delete [] int64Params; + } + else + { + UNREACHABLE(); } - else UNREACHABLE(); } } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } } -void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLenum type, const GLvoid* pixels) +void __stdcall glBeginTransformFeedback(GLenum primitiveMode) { - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " - "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, " - "const GLvoid* pixels = 0x%0.8p)", - target, level, xoffset, yoffset, width, height, format, type, pixels); + EVENT("(GLenum primitiveMode = 0x%X)", primitiveMode); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (!gl::IsInternalTextureTarget(target)) + if (context->getClientVersion() < 3) { + return gl::error(GL_INVALID_OPERATION); + } + + switch (primitiveMode) + { + case GL_TRIANGLES: + case GL_LINES: + case GL_POINTS: + break; + default: return gl::error(GL_INVALID_ENUM); } - if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) + gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != NULL); + + if (transformFeedback->isStarted()) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height) + if (transformFeedback->isPaused()) { - return gl::error(GL_INVALID_VALUE); + transformFeedback->resume(); + } + else + { + transformFeedback->start(primitiveMode); + } + } +} + +void __stdcall glEndTransformFeedback(void) +{ + EVENT("(void)"); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); } - if (!checkTextureFormatType(format, type)) + gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != NULL); + + if (!transformFeedback->isStarted()) { - return; // error is set by helper function + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); + transformFeedback->stop(); + } +} + +void __stdcall glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u, GLintptr offset = %d, GLsizeiptr size = %d)", + target, index, buffer, offset, size); - if (context) + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) { - if (level > context->getMaximumTextureLevel()) + return gl::error(GL_INVALID_OPERATION); + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER: + if (index >= context->getMaxTransformFeedbackBufferBindings()) { return gl::error(GL_INVALID_VALUE); } + break; - if (format == GL_FLOAT) + case GL_UNIFORM_BUFFER: + if (index >= context->getMaximumCombinedUniformBufferBindings()) { - if (!context->supportsFloat32Textures()) - { - return gl::error(GL_INVALID_ENUM); - } - } - else if (format == GL_HALF_FLOAT_OES) - { - if (!context->supportsFloat16Textures()) - { - return gl::error(GL_INVALID_ENUM); - } - } - else if (gl::IsDepthTexture(format)) - { - if (!context->supportsDepthTextures()) - { - return gl::error(GL_INVALID_ENUM); - } - if (target != GL_TEXTURE_2D) - { - return gl::error(GL_INVALID_OPERATION); - } - // OES_depth_texture supports loading depth data, but ANGLE_depth_texture does not - return gl::error(GL_INVALID_OPERATION); + return gl::error(GL_INVALID_VALUE); } + break; - if (width == 0 || height == 0 || pixels == NULL) + default: + return gl::error(GL_INVALID_ENUM); + } + + if (buffer != 0 && size <= 0) + { + return gl::error(GL_INVALID_VALUE); + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER: + + // size and offset must be a multiple of 4 + if (buffer != 0 && ((offset % 4) != 0 || (size % 4) != 0)) { - return; + return gl::error(GL_INVALID_VALUE); } - if (target == GL_TEXTURE_2D) + context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size); + context->bindGenericTransformFeedbackBuffer(buffer); + break; + + case GL_UNIFORM_BUFFER: + + // it is an error to bind an offset not a multiple of the alignment + if (buffer != 0 && (offset % context->getUniformBufferOffsetAlignment()) != 0) { - gl::Texture2D *texture = context->getTexture2D(); - if (validateSubImageParams2D(false, width, height, xoffset, yoffset, level, format, type, texture)) - { - texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); - } + return gl::error(GL_INVALID_VALUE); } - else if (gl::IsCubemapTextureTarget(target)) + + context->bindIndexedUniformBuffer(buffer, index, offset, size); + context->bindGenericUniformBuffer(buffer); + break; + + default: + UNREACHABLE(); + } + } +} + +void __stdcall glBindBufferBase(GLenum target, GLuint index, GLuint buffer) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u)", + target, index, buffer); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER: + if (index >= context->getMaxTransformFeedbackBufferBindings()) { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - if (validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, format, type, texture)) - { - texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); - } + return gl::error(GL_INVALID_VALUE); } - else + break; + + case GL_UNIFORM_BUFFER: + if (index >= context->getMaximumCombinedUniformBufferBindings()) { - UNREACHABLE(); + return gl::error(GL_INVALID_VALUE); } + break; + + default: + return gl::error(GL_INVALID_ENUM); + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER: + context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0); + context->bindGenericTransformFeedbackBuffer(buffer); + break; + + case GL_UNIFORM_BUFFER: + context->bindIndexedUniformBuffer(buffer, index, 0, 0); + context->bindGenericUniformBuffer(buffer); + break; + + default: + UNREACHABLE(); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); } } -void __stdcall glUniform1f(GLint location, GLfloat x) +void __stdcall glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode) { - glUniform1fv(location, 1, &x); -} + EVENT("(GLuint program = %u, GLsizei count = %d, const GLchar* const* varyings = 0x%0.8p, GLenum bufferMode = 0x%X)", + program, count, varyings, bufferMode); -void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (count < 0) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - if (location == -1) + if (count < 0) { - return; + return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); - - if (context) + switch (bufferMode) { - gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); - if (!programBinary) + case GL_INTERLEAVED_ATTRIBS: + break; + case GL_SEPARATE_ATTRIBS: + if (static_cast<GLuint>(count) > context->getMaxTransformFeedbackBufferBindings()) { - return gl::error(GL_INVALID_OPERATION); + return gl::error(GL_INVALID_VALUE); } + break; + default: + return gl::error(GL_INVALID_ENUM); + } - if (!programBinary->setUniform1fv(location, count, v)) - { - return gl::error(GL_INVALID_OPERATION); - } + if (!gl::ValidProgram(context, program)) + { + return; } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + gl::Program *programObject = context->getProgram(program); + ASSERT(programObject); + + programObject->setTransformFeedbackVaryings(count, varyings, bufferMode); } } -void __stdcall glUniform1i(GLint location, GLint x) +void __stdcall glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name) { - glUniform1iv(location, 1, &x); -} + EVENT("(GLuint program = %u, GLuint index = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, " + "GLsizei* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)", + program, index, bufSize, length, size, type, name); -void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (count < 0) + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (bufSize < 0) { return gl::error(GL_INVALID_VALUE); } - if (location == -1) + if (!gl::ValidProgram(context, program)) { return; } - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); + ASSERT(programObject); - if (context) + if (index >= static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount())) { - gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); - if (!programBinary) - { - return gl::error(GL_INVALID_OPERATION); - } + return gl::error(GL_INVALID_VALUE); + } - if (!programBinary->setUniform1iv(location, count, v)) - { - return gl::error(GL_INVALID_OPERATION); - } + programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name); + } +} + +void __stdcall glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) +{ + EVENT("(GLuint index = %u, GLint size = %d, GLenum type = 0x%X, GLsizei stride = %d, const GLvoid* pointer = 0x%0.8p)", + index, size, type, stride, pointer); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); } } - catch(std::bad_alloc&) + + if (index >= gl::MAX_VERTEX_ATTRIBS) { - return gl::error(GL_OUT_OF_MEMORY); + return gl::error(GL_INVALID_VALUE); } -} -void __stdcall glUniform2f(GLint location, GLfloat x, GLfloat y) -{ - GLfloat xy[2] = {x, y}; + if (size < 1 || size > 4) + { + return gl::error(GL_INVALID_VALUE); + } + + switch (type) + { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_2_10_10_10_REV: + break; + default: + return gl::error(GL_INVALID_ENUM); + } + + if (stride < 0) + { + return gl::error(GL_INVALID_VALUE); + } + + if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (context) + { + // [OpenGL ES 3.0.2] Section 2.8 page 24: + // An INVALID_OPERATION error is generated when a non-zero vertex array object + // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, + // and the pointer argument is not NULL. + if (context->getState().getVertexArray()->id() != 0 && context->getState().getArrayBufferId() == 0 && pointer != NULL) + { + return gl::error(GL_INVALID_OPERATION); + } - glUniform2fv(location, 1, (GLfloat*)&xy); + context->getState().setVertexAttribState(index, context->getState().getTargetBuffer(GL_ARRAY_BUFFER), size, type, false, true, + stride, pointer); + } } -void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v) +void __stdcall glGetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", + index, pname, params); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (count < 0) + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (index >= gl::MAX_VERTEX_ATTRIBS) { return gl::error(GL_INVALID_VALUE); } - - if (location == -1) + + const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index); + + if (!gl::ValidateGetVertexAttribParameters(pname, context->getClientVersion())) { return; } - gl::Context *context = gl::getNonLostContext(); - - if (context) + if (pname == GL_CURRENT_VERTEX_ATTRIB) { - gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); - if (!programBinary) + const gl::VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); + for (int i = 0; i < 4; ++i) { - return gl::error(GL_INVALID_OPERATION); + params[i] = currentValueData.IntValues[i]; } + } + else + { + *params = gl::QuerySingleVertexAttributeParameter<GLint>(attribState, pname); + } + } +} + +void __stdcall glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) +{ + EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLuint* params = 0x%0.8p)", + index, pname, params); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); + } + + const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index); + + if (!gl::ValidateGetVertexAttribParameters(pname, context->getClientVersion())) + { + return; + } - if (!programBinary->setUniform2fv(location, count, v)) + if (pname == GL_CURRENT_VERTEX_ATTRIB) + { + const gl::VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); + for (int i = 0; i < 4; ++i) { - return gl::error(GL_INVALID_OPERATION); + params[i] = currentValueData.UnsignedIntValues[i]; } } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + else + { + *params = gl::QuerySingleVertexAttributeParameter<GLuint>(attribState, pname); + } } } -void __stdcall glUniform2i(GLint location, GLint x, GLint y) +void __stdcall glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) { - GLint xy[4] = {x, y}; + EVENT("(GLuint index = %u, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)", + index, x, y, z, w); + + gl::Context *context = gl::getNonLostContext(); - glUniform2iv(location, 1, (GLint*)&xy); + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); + } + + GLint vals[4] = { x, y, z, w }; + context->getState().setVertexAttribi(index, vals); + } } -void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v) +void __stdcall glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + EVENT("(GLuint index = %u, GLuint x = %u, GLuint y = %u, GLuint z = %u, GLuint w = %u)", + index, x, y, z, w); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (count < 0) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - if (location == -1) + if (index >= gl::MAX_VERTEX_ATTRIBS) { - return; + return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); + GLuint vals[4] = { x, y, z, w }; + context->getState().setVertexAttribu(index, vals); + } +} - if (context) +void __stdcall glVertexAttribI4iv(GLuint index, const GLint* v) +{ + EVENT("(GLuint index = %u, const GLint* v = 0x%0.8p)", index, v); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) { - gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); - if (!programBinary) - { - return gl::error(GL_INVALID_OPERATION); - } + return gl::error(GL_INVALID_OPERATION); + } - if (!programBinary->setUniform2iv(location, count, v)) - { - return gl::error(GL_INVALID_OPERATION); - } + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); } + + context->getState().setVertexAttribi(index, v); } - catch(std::bad_alloc&) +} + +void __stdcall glVertexAttribI4uiv(GLuint index, const GLuint* v) +{ + EVENT("(GLuint index = %u, const GLuint* v = 0x%0.8p)", index, v); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return gl::error(GL_INVALID_VALUE); + } + + context->getState().setVertexAttribu(index, v); } } -void __stdcall glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +void __stdcall glGetUniformuiv(GLuint program, GLint location, GLuint* params) { - GLfloat xyz[3] = {x, y, z}; + EVENT("(GLuint program = %u, GLint location = %d, GLuint* params = 0x%0.8p)", + program, location, params); + + gl::Context *context = gl::getNonLostContext(); - glUniform3fv(location, 1, (GLfloat*)&xyz); + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (program == 0) + { + return gl::error(GL_INVALID_VALUE); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return gl::error(GL_INVALID_OPERATION); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (!programBinary->getUniformuiv(location, NULL, params)) + { + return gl::error(GL_INVALID_OPERATION); + } + } } -void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v) +GLint __stdcall glGetFragDataLocation(GLuint program, const GLchar *name) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + EVENT("(GLuint program = %u, const GLchar *name = 0x%0.8p)", + program, name); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (count < 0) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION, -1); } - if (location == -1) + if (program == 0) { - return; + return gl::error(GL_INVALID_VALUE, -1); } - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); - if (context) + if (!programObject || !programObject->isLinked()) { - gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); - if (!programBinary) - { - return gl::error(GL_INVALID_OPERATION); - } + return gl::error(GL_INVALID_OPERATION, -1); + } - if (!programBinary->setUniform3fv(location, count, v)) - { - return gl::error(GL_INVALID_OPERATION); - } + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return gl::error(GL_INVALID_OPERATION, -1); } + + return programBinary->getFragDataLocation(name); } - catch(std::bad_alloc&) + + return 0; +} + +void __stdcall glUniform1ui(GLint location, GLuint v0) +{ + glUniform1uiv(location, 1, &v0); +} + +void __stdcall glUniform2ui(GLint location, GLuint v0, GLuint v1) +{ + const GLuint xy[] = { v0, v1 }; + glUniform2uiv(location, 1, xy); +} + +void __stdcall glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + const GLuint xyz[] = { v0, v1, v2 }; + glUniform3uiv(location, 1, xyz); +} + +void __stdcall glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +{ + const GLuint xyzw[] = { v0, v1, v2, v3 }; + glUniform4uiv(location, 1, xyzw); +} + +void __stdcall glUniform1uiv(GLint location, GLsizei count, const GLuint* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", + location, count, value); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (!ValidateUniform(context, GL_UNSIGNED_INT, location, count)) + { + return; + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform1uiv(location, count, value); } } -void __stdcall glUniform3i(GLint location, GLint x, GLint y, GLint z) +void __stdcall glUniform2uiv(GLint location, GLsizei count, const GLuint* value) { - GLint xyz[3] = {x, y, z}; + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", + location, count, value); + + gl::Context *context = gl::getNonLostContext(); - glUniform3iv(location, 1, (GLint*)&xyz); + if (context) + { + if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC2, location, count)) + { + return; + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform2uiv(location, count, value); + } } -void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v) +void __stdcall glUniform3uiv(GLint location, GLsizei count, const GLuint* value) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value)", + location, count, value); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (count < 0) + if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC3, location, count)) { - return gl::error(GL_INVALID_VALUE); + return; } - if (location == -1) + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform3uiv(location, count, value); + } +} + +void __stdcall glUniform4uiv(GLint location, GLsizei count, const GLuint* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", + location, count, value); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC4, location, count)) { return; } - gl::Context *context = gl::getNonLostContext(); + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + programBinary->setUniform4uiv(location, count, value); + } +} - if (context) +void __stdcall glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) +{ + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint* value = 0x%0.8p)", + buffer, drawbuffer, value); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!ValidateClearBuffer(context)) { - gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); - if (!programBinary) + return; + } + + switch (buffer) + { + case GL_COLOR: + if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers) { - return gl::error(GL_INVALID_OPERATION); + return gl::error(GL_INVALID_VALUE); } - - if (!programBinary->setUniform3iv(location, count, v)) + break; + case GL_STENCIL: + if (drawbuffer != 0) { - return gl::error(GL_INVALID_OPERATION); + return gl::error(GL_INVALID_VALUE); } + break; + default: + return gl::error(GL_INVALID_ENUM); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + context->clearBufferiv(buffer, drawbuffer, value); } } -void __stdcall glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +void __stdcall glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { - GLfloat xyzw[4] = {x, y, z, w}; + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint* value = 0x%0.8p)", + buffer, drawbuffer, value); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!ValidateClearBuffer(context)) + { + return; + } + + switch (buffer) + { + case GL_COLOR: + if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers) + { + return gl::error(GL_INVALID_VALUE); + } + break; + default: + return gl::error(GL_INVALID_ENUM); + } - glUniform4fv(location, 1, (GLfloat*)&xyzw); + context->clearBufferuiv(buffer, drawbuffer, value); + } } -void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v) +void __stdcall glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat* value = 0x%0.8p)", + buffer, drawbuffer, value); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (count < 0) + if (!ValidateClearBuffer(context)) { - return gl::error(GL_INVALID_VALUE); + return; } - if (location == -1) + switch (buffer) { - return; + case GL_COLOR: + if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers) + { + return gl::error(GL_INVALID_VALUE); + } + break; + case GL_DEPTH: + if (drawbuffer != 0) + { + return gl::error(GL_INVALID_VALUE); + } + break; + default: + return gl::error(GL_INVALID_ENUM); } - gl::Context *context = gl::getNonLostContext(); + context->clearBufferfv(buffer, drawbuffer, value); + } +} + +void __stdcall glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) +{ + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth, GLint stencil = %d)", + buffer, drawbuffer, depth, stencil); + + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (!ValidateClearBuffer(context)) { - gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); - if (!programBinary) - { - return gl::error(GL_INVALID_OPERATION); - } + return; + } - if (!programBinary->setUniform4fv(location, count, v)) + switch (buffer) + { + case GL_DEPTH_STENCIL: + if (drawbuffer != 0) { - return gl::error(GL_INVALID_OPERATION); + return gl::error(GL_INVALID_VALUE); } + break; + default: + return gl::error(GL_INVALID_ENUM); } + + context->clearBufferfi(buffer, drawbuffer, depth, stencil); } - catch(std::bad_alloc&) +} + +const GLubyte* __stdcall glGetStringi(GLenum name, GLuint index) +{ + EVENT("(GLenum name = 0x%X, GLuint index = %u)", name, index); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, reinterpret_cast<GLubyte*>(NULL)); + } + + if (name != GL_EXTENSIONS) + { + return gl::error(GL_INVALID_ENUM, reinterpret_cast<GLubyte*>(NULL)); + } + + if (index >= context->getExtensionStringCount()) + { + return gl::error(GL_INVALID_VALUE, reinterpret_cast<GLubyte*>(NULL)); + } + + return reinterpret_cast<const GLubyte*>(context->getExtensionString(index).c_str()); } + + return NULL; } -void __stdcall glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +void __stdcall glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { - GLint xyzw[4] = {x, y, z, w}; + EVENT("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)", + readTarget, writeTarget, readOffset, writeOffset, size); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (!gl::ValidBufferTarget(context, readTarget) || !gl::ValidBufferTarget(context, readTarget)) + { + return gl::error(GL_INVALID_ENUM); + } + + gl::Buffer *readBuffer = context->getState().getTargetBuffer(readTarget); + gl::Buffer *writeBuffer = context->getState().getTargetBuffer(writeTarget); + + if (!readBuffer || !writeBuffer) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (readBuffer->isMapped() || writeBuffer->isMapped()) + { + return gl::error(GL_INVALID_OPERATION); + } - glUniform4iv(location, 1, (GLint*)&xyzw); + if (readOffset < 0 || writeOffset < 0 || size < 0 || + static_cast<unsigned int>(readOffset + size) > readBuffer->getSize() || + static_cast<unsigned int>(writeOffset + size) > writeBuffer->getSize()) + { + return gl::error(GL_INVALID_VALUE); + } + + if (readBuffer == writeBuffer && abs(readOffset - writeOffset) < size) + { + return gl::error(GL_INVALID_VALUE); + } + + // TODO: Verify that readBuffer and writeBuffer are not currently mapped (GL_INVALID_OPERATION) + + // if size is zero, the copy is a successful no-op + if (size > 0) + { + writeBuffer->copyBufferSubData(readBuffer, readOffset, writeOffset, size); + } + } } -void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v) +void __stdcall glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLchar* const* uniformNames = 0x%0.8p, GLuint* uniformIndices = 0x%0.8p)", + program, uniformCount, uniformNames, uniformIndices); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (count < 0) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - if (location == -1) + if (uniformCount < 0) { - return; + return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); - if (context) + if (!programObject) { - gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); - if (!programBinary) + if (context->getShader(program)) { return gl::error(GL_INVALID_OPERATION); } + else + { + return gl::error(GL_INVALID_VALUE); + } + } - if (!programBinary->setUniform4iv(location, count, v)) + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programObject->isLinked() || !programBinary) + { + for (int uniformId = 0; uniformId < uniformCount; uniformId++) { - return gl::error(GL_INVALID_OPERATION); + uniformIndices[uniformId] = GL_INVALID_INDEX; + } + } + else + { + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + uniformIndices[uniformId] = programBinary->getUniformIndex(uniformNames[uniformId]); } } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); } } -void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void __stdcall glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); + EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLuint* uniformIndices = 0x%0.8p, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", + program, uniformCount, uniformIndices, pname, params); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (count < 0 || transpose != GL_FALSE) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - if (location == -1) + if (uniformCount < 0) { - return; + return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); - if (context) + if (!programObject) { - gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); - if (!programBinary) + if (context->getShader(program)) { return gl::error(GL_INVALID_OPERATION); } + else + { + return gl::error(GL_INVALID_VALUE); + } + } - if (!programBinary->setUniformMatrix2fv(location, count, value)) + switch (pname) + { + case GL_UNIFORM_TYPE: + case GL_UNIFORM_SIZE: + case GL_UNIFORM_NAME_LENGTH: + case GL_UNIFORM_BLOCK_INDEX: + case GL_UNIFORM_OFFSET: + case GL_UNIFORM_ARRAY_STRIDE: + case GL_UNIFORM_MATRIX_STRIDE: + case GL_UNIFORM_IS_ROW_MAJOR: + break; + default: + return gl::error(GL_INVALID_ENUM); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + + if (!programBinary && uniformCount > 0) + { + return gl::error(GL_INVALID_VALUE); + } + + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + const GLuint index = uniformIndices[uniformId]; + + if (index >= (GLuint)programBinary->getActiveUniformCount()) { - return gl::error(GL_INVALID_OPERATION); + return gl::error(GL_INVALID_VALUE); } } + + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + const GLuint index = uniformIndices[uniformId]; + params[uniformId] = programBinary->getActiveUniformi(index, pname); + } } - catch(std::bad_alloc&) +} + +GLuint __stdcall glGetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) +{ + EVENT("(GLuint program = %u, const GLchar* uniformBlockName = 0x%0.8p)", program, uniformBlockName); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, GL_INVALID_INDEX); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return gl::error(GL_INVALID_OPERATION, GL_INVALID_INDEX); + } + else + { + return gl::error(GL_INVALID_VALUE, GL_INVALID_INDEX); + } + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return GL_INVALID_INDEX; + } + + return programBinary->getUniformBlockIndex(uniformBlockName); } + + return 0; } -void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void __stdcall glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); + EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", + program, uniformBlockIndex, pname, params); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (count < 0 || transpose != GL_FALSE) + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return gl::error(GL_INVALID_OPERATION); + } + else + { + return gl::error(GL_INVALID_VALUE); + } + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + + if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount()) { return gl::error(GL_INVALID_VALUE); } - if (location == -1) + switch (pname) { - return; + case GL_UNIFORM_BLOCK_BINDING: + *params = static_cast<GLint>(programObject->getUniformBlockBinding(uniformBlockIndex)); + break; + + case GL_UNIFORM_BLOCK_DATA_SIZE: + case GL_UNIFORM_BLOCK_NAME_LENGTH: + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: + programBinary->getActiveUniformBlockiv(uniformBlockIndex, pname, params); + break; + + default: + return gl::error(GL_INVALID_ENUM); + } + } +} + +void __stdcall glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName) +{ + EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLchar* uniformBlockName = 0x%0.8p)", + program, uniformBlockIndex, bufSize, length, uniformBlockName); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); - if (context) + if (!programObject) { - gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); - if (!programBinary) + if (context->getShader(program)) { return gl::error(GL_INVALID_OPERATION); } - - if (!programBinary->setUniformMatrix3fv(location, count, value)) + else { - return gl::error(GL_INVALID_OPERATION); + return gl::error(GL_INVALID_VALUE); } } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + + if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount()) + { + return gl::error(GL_INVALID_VALUE); + } + + programBinary->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName); } } -void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void __stdcall glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); + EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLuint uniformBlockBinding = %u)", + program, uniformBlockIndex, uniformBlockBinding); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (count < 0 || transpose != GL_FALSE) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - if (location == -1) + if (uniformBlockBinding >= context->getMaximumCombinedUniformBufferBindings()) { - return; + return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); - if (context) + if (!programObject) { - gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); - if (!programBinary) + if (context->getShader(program)) { return gl::error(GL_INVALID_OPERATION); } - - if (!programBinary->setUniformMatrix4fv(location, count, value)) + else { - return gl::error(GL_INVALID_OPERATION); + return gl::error(GL_INVALID_VALUE); } } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + + // if never linked, there won't be any uniform blocks + if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount()) + { + return gl::error(GL_INVALID_VALUE); + } + + programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding); } - catch(std::bad_alloc&) +} + +void __stdcall glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) +{ + EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)", + mode, first, count, instanceCount); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + // glDrawArraysInstanced + UNIMPLEMENTED(); } } -void __stdcall glUseProgram(GLuint program) +void __stdcall glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount) { - EVENT("(GLuint program = %d)", program); + EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei instanceCount = %d)", + mode, count, type, indices, instanceCount); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + // glDrawElementsInstanced + UNIMPLEMENTED(); + } +} + +GLsync __stdcall glFenceSync(GLenum condition, GLbitfield flags) +{ + EVENT("(GLenum condition = 0x%X, GLbitfield flags = 0x%X)", condition, flags); + + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (context->getClientVersion() < 3) { - gl::Program *programObject = context->getProgram(program); + return gl::error(GL_INVALID_OPERATION, reinterpret_cast<GLsync>(0)); + } - if (!programObject && program != 0) - { - if (context->getShader(program)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } - } + if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) + { + return gl::error(GL_INVALID_ENUM, reinterpret_cast<GLsync>(0)); + } - if (program != 0 && !programObject->isLinked()) - { - return gl::error(GL_INVALID_OPERATION); - } + if (flags != 0) + { + return gl::error(GL_INVALID_VALUE, reinterpret_cast<GLsync>(0)); + } - context->useProgram(program); + return context->createFenceSync(condition); + } + + return NULL; +} + +GLboolean __stdcall glIsSync(GLsync sync) +{ + EVENT("(GLsync sync = 0x%0.8p)", sync); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, GL_FALSE); } + + return (context->getFenceSync(sync) != NULL); } - catch(std::bad_alloc&) + + return GL_FALSE; +} + +void __stdcall glDeleteSync(GLsync sync) +{ + EVENT("(GLsync sync = 0x%0.8p)", sync); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (sync != static_cast<GLsync>(0) && !context->getFenceSync(sync)) + { + return gl::error(GL_INVALID_VALUE); + } + + context->deleteFenceSync(sync); } } -void __stdcall glValidateProgram(GLuint program) +GLenum __stdcall glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { - EVENT("(GLuint program = %d)", program); + EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", + sync, flags, timeout); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - gl::Context *context = gl::getNonLostContext(); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, GL_WAIT_FAILED); + } - if (context) + if ((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0) { - gl::Program *programObject = context->getProgram(program); + return gl::error(GL_INVALID_VALUE, GL_WAIT_FAILED); + } - if (!programObject) - { - if (context->getShader(program)) - { - return gl::error(GL_INVALID_OPERATION); - } - else - { - return gl::error(GL_INVALID_VALUE); - } - } + gl::FenceSync *fenceSync = context->getFenceSync(sync); - programObject->validate(); + if (!fenceSync) + { + return gl::error(GL_INVALID_VALUE, GL_WAIT_FAILED); } + + return fenceSync->clientWait(flags, timeout); } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } + + return GL_FALSE; } -void __stdcall glVertexAttrib1f(GLuint index, GLfloat x) +void __stdcall glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { - EVENT("(GLuint index = %d, GLfloat x = %f)", index, x); + EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", + sync, flags, timeout); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (index >= gl::MAX_VERTEX_ATTRIBS) + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (flags != 0) { return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); + if (timeout != GL_TIMEOUT_IGNORED) + { + return gl::error(GL_INVALID_VALUE); + } - if (context) + gl::FenceSync *fenceSync = context->getFenceSync(sync); + + if (!fenceSync) { - GLfloat vals[4] = { x, 0, 0, 1 }; - context->setVertexAttrib(index, vals); + return gl::error(GL_INVALID_VALUE); } + + fenceSync->serverWait(); } - catch(std::bad_alloc&) +} + +void __stdcall glGetInteger64v(GLenum pname, GLint64* params) +{ + EVENT("(GLenum pname = 0x%X, GLint64* params = 0x%0.8p)", + pname, params); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + GLenum nativeType; + unsigned int numParams = 0; + if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) + { + return; + } + + if (nativeType == GL_INT_64_ANGLEX) + { + context->getInteger64v(pname, params); + } + else + { + CastStateValues(context, nativeType, pname, numParams, params); + } } } -void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values) +void __stdcall glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) { - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + EVENT("(GLsync sync = 0x%0.8p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLint* values = 0x%0.8p)", + sync, pname, bufSize, length, values); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (index >= gl::MAX_VERTEX_ATTRIBS) + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (bufSize < 0) { return gl::error(GL_INVALID_VALUE); } - gl::Context *context = gl::getNonLostContext(); + gl::FenceSync *fenceSync = context->getFenceSync(sync); - if (context) + if (!fenceSync) { - GLfloat vals[4] = { values[0], 0, 0, 1 }; - context->setVertexAttrib(index, vals); + return gl::error(GL_INVALID_VALUE); + } + + switch (pname) + { + case GL_OBJECT_TYPE: values[0] = static_cast<GLint>(GL_SYNC_FENCE); break; + case GL_SYNC_STATUS: values[0] = static_cast<GLint>(fenceSync->getStatus()); break; + case GL_SYNC_CONDITION: values[0] = static_cast<GLint>(fenceSync->getCondition()); break; + case GL_SYNC_FLAGS: values[0] = 0; break; + + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) +} + +void __stdcall glGetInteger64i_v(GLenum target, GLuint index, GLint64* data) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint64* data = 0x%0.8p)", + target, index, data); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (index >= context->getMaxTransformFeedbackBufferBindings()) + return gl::error(GL_INVALID_VALUE); + break; + case GL_UNIFORM_BUFFER_START: + case GL_UNIFORM_BUFFER_SIZE: + case GL_UNIFORM_BUFFER_BINDING: + if (index >= context->getMaximumCombinedUniformBufferBindings()) + return gl::error(GL_INVALID_VALUE); + break; + default: + return gl::error(GL_INVALID_ENUM); + } + + if (!(context->getIndexedInteger64v(target, index, data))) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!context->getIndexedQueryParameterInfo(target, &nativeType, &numParams)) + return gl::error(GL_INVALID_ENUM); + + if (numParams == 0) + return; // it is known that pname is valid, but there are no parameters to return + + if (nativeType == GL_INT) + { + GLint *intParams = new GLint[numParams]; + + context->getIndexedIntegerv(target, index, intParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + data[i] = static_cast<GLint64>(intParams[i]); + } + + delete [] intParams; + } + else + { + UNREACHABLE(); + } + } } } -void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) +void __stdcall glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params) { - EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y); + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64* params = 0x%0.8p)", + target, pname, params); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (index >= gl::MAX_VERTEX_ATTRIBS) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); + if (!gl::ValidBufferTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM); + } - if (context) + if (!gl::ValidBufferParameter(context, pname)) { - GLfloat vals[4] = { x, y, 0, 1 }; - context->setVertexAttrib(index, vals); + return gl::error(GL_INVALID_ENUM); + } + + gl::Buffer *buffer = context->getState().getTargetBuffer(target); + + if (!buffer) + { + // A null buffer means that "0" is bound to the requested buffer target + return gl::error(GL_INVALID_OPERATION); + } + + switch (pname) + { + case GL_BUFFER_USAGE: + *params = static_cast<GLint64>(buffer->getUsage()); + break; + case GL_BUFFER_SIZE: + *params = buffer->getSize(); + break; + case GL_BUFFER_ACCESS_FLAGS: + *params = static_cast<GLint64>(buffer->getAccessFlags()); + break; + case GL_BUFFER_MAPPED: + *params = static_cast<GLint64>(buffer->isMapped()); + break; + case GL_BUFFER_MAP_OFFSET: + *params = buffer->getMapOffset(); + break; + case GL_BUFFER_MAP_LENGTH: + *params = buffer->getMapLength(); + break; + default: UNREACHABLE(); break; } } - catch(std::bad_alloc&) +} + +void __stdcall glGenSamplers(GLsizei count, GLuint* samplers) +{ + EVENT("(GLsizei count = %d, GLuint* samplers = 0x%0.8p)", count, samplers); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (count < 0) + { + return gl::error(GL_INVALID_VALUE); + } + + for (int i = 0; i < count; i++) + { + samplers[i] = context->createSampler(); + } } } -void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values) +void __stdcall glDeleteSamplers(GLsizei count, const GLuint* samplers) { - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + EVENT("(GLsizei count = %d, const GLuint* samplers = 0x%0.8p)", count, samplers); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (index >= gl::MAX_VERTEX_ATTRIBS) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); + if (count < 0) + { + return gl::error(GL_INVALID_VALUE); + } - if (context) + for (int i = 0; i < count; i++) { - GLfloat vals[4] = { values[0], values[1], 0, 1 }; - context->setVertexAttrib(index, vals); + context->deleteSampler(samplers[i]); } } - catch(std::bad_alloc&) +} + +GLboolean __stdcall glIsSampler(GLuint sampler) +{ + EVENT("(GLuint sampler = %u)", sampler); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, GL_FALSE); + } + + return context->isSampler(sampler); } + + return GL_FALSE; } -void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) +void __stdcall glBindSampler(GLuint unit, GLuint sampler) { - EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z); + EVENT("(GLuint unit = %u, GLuint sampler = %u)", unit, sampler); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (index >= gl::MAX_VERTEX_ATTRIBS) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); + if (sampler != 0 && !context->isSampler(sampler)) + { + return gl::error(GL_INVALID_OPERATION); + } - if (context) + if (unit >= context->getMaximumCombinedTextureImageUnits()) { - GLfloat vals[4] = { x, y, z, 1 }; - context->setVertexAttrib(index, vals); + return gl::error(GL_INVALID_VALUE); } + + context->bindSampler(unit, sampler); } - catch(std::bad_alloc&) +} + +void __stdcall glSamplerParameteri(GLuint sampler, GLenum pname, GLint param) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint param = %d)", sampler, pname, param); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (!gl::ValidateSamplerObjectParameter(pname)) + { + return; + } + + if (!gl::ValidateTexParamParameters(context, pname, param)) + { + return; + } + + if (!context->isSampler(sampler)) + { + return gl::error(GL_INVALID_OPERATION); + } + + context->samplerParameteri(sampler, pname, param); } } -void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values) +void __stdcall glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) { - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + glSamplerParameteri(sampler, pname, *param); +} + +void __stdcall glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLfloat param = %g)", sampler, pname, param); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (index >= gl::MAX_VERTEX_ATTRIBS) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); + if (!gl::ValidateSamplerObjectParameter(pname)) + { + return; + } - if (context) + if (!gl::ValidateTexParamParameters(context, pname, static_cast<GLint>(param))) { - GLfloat vals[4] = { values[0], values[1], values[2], 1 }; - context->setVertexAttrib(index, vals); + return; } + + if (!context->isSampler(sampler)) + { + return gl::error(GL_INVALID_OPERATION); + } + + context->samplerParameterf(sampler, pname, param); } - catch(std::bad_alloc&) +} + +void __stdcall glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) +{ + glSamplerParameterf(sampler, pname, *param); +} + +void __stdcall glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", sampler, pname, params); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (!gl::ValidateSamplerObjectParameter(pname)) + { + return; + } + + if (!context->isSampler(sampler)) + { + return gl::error(GL_INVALID_OPERATION); + } + + *params = context->getSamplerParameteri(sampler, pname); } } -void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +void __stdcall glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) { - EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w); + EVENT("(GLuint sample = %ur, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", sampler, pname, params); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (index >= gl::MAX_VERTEX_ATTRIBS) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); + if (!gl::ValidateSamplerObjectParameter(pname)) + { + return; + } - if (context) + if (!context->isSampler(sampler)) { - GLfloat vals[4] = { x, y, z, w }; - context->setVertexAttrib(index, vals); + return gl::error(GL_INVALID_OPERATION); } + + *params = context->getSamplerParameterf(sampler, pname); } - catch(std::bad_alloc&) +} + +void __stdcall glVertexAttribDivisor(GLuint index, GLuint divisor) +{ + EVENT("(GLuint index = %u, GLuint divisor = %u)", index, divisor); + + if (index >= gl::MAX_VERTEX_ATTRIBS) { - return gl::error(GL_OUT_OF_MEMORY); + return gl::error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + context->setVertexAttribDivisor(index, divisor); } } -void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values) +void __stdcall glBindTransformFeedback(GLenum target, GLuint id) { - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - if (index >= gl::MAX_VERTEX_ATTRIBS) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); - - if (context) + switch (target) { - context->setVertexAttrib(index, values); + case GL_TRANSFORM_FEEDBACK: + { + // Cannot bind a transform feedback object if the current one is started and not paused (3.0.2 pg 85 section 2.14.1) + gl::TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) + { + return gl::error(GL_INVALID_OPERATION); + } + + // Cannot bind a transform feedback object that does not exist (3.0.2 pg 85 section 2.14.1) + if (context->getTransformFeedback(id) == NULL) + { + return gl::error(GL_INVALID_OPERATION); + } + + context->bindTransformFeedback(id); + } + break; + + default: + return gl::error(GL_INVALID_ENUM); } } - catch(std::bad_alloc&) +} + +void __stdcall glDeleteTransformFeedbacks(GLsizei n, const GLuint* ids) +{ + EVENT("(GLsizei n = %d, const GLuint* ids = 0x%0.8p)", n, ids); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + for (int i = 0; i < n; i++) + { + context->deleteTransformFeedback(ids[i]); + } } } -void __stdcall glVertexAttribDivisorANGLE(GLuint index, GLuint divisor) +void __stdcall glGenTransformFeedbacks(GLsizei n, GLuint* ids) { - EVENT("(GLuint index = %d, GLuint divisor = %d)", index, divisor); + EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (index >= gl::MAX_VERTEX_ATTRIBS) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); - - if (context) + for (int i = 0; i < n; i++) { - context->setVertexAttribDivisor(index, divisor); + ids[i] = context->createTransformFeedback(); } } - catch(std::bad_alloc&) +} + +GLboolean __stdcall glIsTransformFeedback(GLuint id) +{ + EVENT("(GLuint id = %u)", id); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, GL_FALSE); + } + + return ((context->getTransformFeedback(id) != NULL) ? GL_TRUE : GL_FALSE); } + + return GL_FALSE; } -void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) +void __stdcall glPauseTransformFeedback(void) { - EVENT("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, " - "GLboolean normalized = %d, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)", - index, size, type, normalized, stride, ptr); + EVENT("(void)"); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (index >= gl::MAX_VERTEX_ATTRIBS) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - if (size < 1 || size > 4) + gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != NULL); + + // Current transform feedback must be started and not paused in order to pause (3.0.2 pg 86) + if (!transformFeedback->isStarted() || transformFeedback->isPaused()) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - switch (type) + transformFeedback->pause(); + } +} + +void __stdcall glResumeTransformFeedback(void) +{ + EVENT("(void)"); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getClientVersion() < 3) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_FIXED: - case GL_FLOAT: - break; - default: - return gl::error(GL_INVALID_ENUM); + return gl::error(GL_INVALID_OPERATION); } - if (stride < 0) + gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != NULL); + + // Current transform feedback must be started and paused in order to resume (3.0.2 pg 86) + if (!transformFeedback->isStarted() || !transformFeedback->isPaused()) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); + transformFeedback->resume(); + } +} + +void __stdcall glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary) +{ + EVENT("(GLuint program = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLenum* binaryFormat = 0x%0.8p, GLvoid* binary = 0x%0.8p)", + program, bufSize, length, binaryFormat, binary); + + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (context->getClientVersion() < 3) { - context->setVertexAttribState(index, context->getArrayBuffer(), size, type, (normalized == GL_TRUE), stride, ptr); + return gl::error(GL_INVALID_OPERATION); } + + // glGetProgramBinary + UNIMPLEMENTED(); } - catch(std::bad_alloc&) +} + +void __stdcall glProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length) +{ + EVENT("(GLuint program = %u, GLenum binaryFormat = 0x%X, const GLvoid* binary = 0x%0.8p, GLsizei length = %d)", + program, binaryFormat, binary, length); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + // glProgramBinary + UNIMPLEMENTED(); } } -void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +void __stdcall glProgramParameteri(GLuint program, GLenum pname, GLint value) { - EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); + EVENT("(GLuint program = %u, GLenum pname = 0x%X, GLint value = %d)", + program, pname, value); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - if (width < 0 || height < 0) + if (context->getClientVersion() < 3) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); + // glProgramParameteri + UNIMPLEMENTED(); + } +} + +void __stdcall glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) +{ + EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p)", + target, numAttachments, attachments); + + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (context->getClientVersion() < 3) { - context->setViewportParams(x, y, width, height); + return gl::error(GL_INVALID_OPERATION); } + + if (!ValidateInvalidateFramebufferParameters(context, target, numAttachments, attachments)) + { + return; + } + + GLuint maxDimension = context->getCaps().maxRenderbufferSize; + context->invalidateFrameBuffer(target, numAttachments, attachments, 0, 0, maxDimension, maxDimension); } - catch(std::bad_alloc&) +} + +void __stdcall glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p, GLint x = %d, " + "GLint y = %d, GLsizei width = %d, GLsizei height = %d)", + target, numAttachments, attachments, x, y, width, height); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (!ValidateInvalidateFramebufferParameters(context, target, numAttachments, attachments)) + { + return; + } + + context->invalidateFrameBuffer(target, numAttachments, attachments, x, y, width, height); } } -void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) +void __stdcall glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { - EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, " - "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, " - "GLbitfield mask = 0x%X, GLenum filter = 0x%X)", - srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter); + EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + target, levels, internalformat, width, height); + + gl::Context *context = gl::getNonLostContext(); - try + if (context) { - switch (filter) + if (context->getClientVersion() < 3) { - case GL_NEAREST: + return gl::error(GL_INVALID_OPERATION); + } + + if (!ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, 1)) + { + return; + } + + switch (target) + { + case GL_TEXTURE_2D: + { + gl::Texture2D *texture2d = context->getTexture2D(); + texture2d->storage(levels, internalformat, width, height); + } break; + + case GL_TEXTURE_CUBE_MAP: + { + gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); + textureCube->storage(levels, internalformat, width); + } + break; + default: return gl::error(GL_INVALID_ENUM); } + } +} - if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) - { - return gl::error(GL_INVALID_VALUE); - } +void __stdcall glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +{ + EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " + "GLsizei height = %d, GLsizei depth = %d)", + target, levels, internalformat, width, height, depth); + + gl::Context *context = gl::getNonLostContext(); - if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0) + if (context) + { + if (context->getClientVersion() < 3) { - ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation"); return gl::error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getNonLostContext(); + if (!ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, depth)) + { + return; + } - if (context) + switch (target) { - if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle()) + case GL_TEXTURE_3D: { - ERR("Blits with the same source and destination framebuffer are not supported by this implementation."); - return gl::error(GL_INVALID_OPERATION); + gl::Texture3D *texture3d = context->getTexture3D(); + texture3d->storage(levels, internalformat, width, height, depth); + } + break; + + case GL_TEXTURE_2D_ARRAY: + { + gl::Texture2DArray *texture2darray = context->getTexture2DArray(); + texture2darray->storage(levels, internalformat, width, height, depth); } + break; - context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask); + default: + UNREACHABLE(); } } - catch(std::bad_alloc&) +} + +void __stdcall glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, " + "GLint* params = 0x%0.8p)", + target, internalformat, pname, bufSize, params); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION); + } + + const gl::TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (!formatCaps.renderable) + { + return gl::error(GL_INVALID_ENUM); + } + + if (target != GL_RENDERBUFFER) + { + return gl::error(GL_INVALID_ENUM); + } + + if (bufSize < 0) + { + return gl::error(GL_INVALID_VALUE); + } + + switch (pname) + { + case GL_NUM_SAMPLE_COUNTS: + if (bufSize != 0) + *params = context->getNumSampleCounts(internalformat); + break; + case GL_SAMPLES: + context->getSampleCounts(internalformat, bufSize, params); + break; + default: + return gl::error(GL_INVALID_ENUM); + } + } +} + +// Extension functions + +void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, " + "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, " + "GLbitfield mask = 0x%X, GLenum filter = 0x%X)", + srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, mask, filter, + true)) + { + return; + } + + context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, + mask, filter); } } @@ -6878,53 +7949,39 @@ void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* pixels = 0x%0.8p)", target, level, internalformat, width, height, depth, border, format, type, pixels); - try - { - UNIMPLEMENTED(); // FIXME - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); - } + UNIMPLEMENTED(); // FIXME } -void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, +void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) { EVENT("(GLenum program = 0x%X, bufSize = %d, length = 0x%0.8p, binaryFormat = 0x%0.8p, binary = 0x%0.8p)", program, bufSize, length, binaryFormat, binary); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::Program *programObject = context->getProgram(program); - if (context) + if (!programObject || !programObject->isLinked()) { - gl::Program *programObject = context->getProgram(program); - - if (!programObject || !programObject->isLinked()) - { - return gl::error(GL_INVALID_OPERATION); - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + return gl::error(GL_INVALID_OPERATION); + } - if (!programBinary) - { - return gl::error(GL_INVALID_OPERATION); - } + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programBinary->save(binary, bufSize, length)) - { - return gl::error(GL_INVALID_OPERATION); - } + if (!programBinary) + { + return gl::error(GL_INVALID_OPERATION); + } - *binaryFormat = GL_PROGRAM_BINARY_ANGLE; + if (!programBinary->save(binary, bufSize, length)) + { + return gl::error(GL_INVALID_OPERATION); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + *binaryFormat = GL_PROGRAM_BINARY_ANGLE; } } @@ -6934,30 +7991,23 @@ void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat, EVENT("(GLenum program = 0x%X, binaryFormat = 0x%x, binary = 0x%0.8p, length = %d)", program, binaryFormat, binary, length); - try - { - gl::Context *context = gl::getNonLostContext(); + gl::Context *context = gl::getNonLostContext(); - if (context) + if (context) + { + if (binaryFormat != GL_PROGRAM_BINARY_ANGLE) { - if (binaryFormat != GL_PROGRAM_BINARY_ANGLE) - { - return gl::error(GL_INVALID_ENUM); - } + return gl::error(GL_INVALID_ENUM); + } - gl::Program *programObject = context->getProgram(program); + gl::Program *programObject = context->getProgram(program); - if (!programObject) - { - return gl::error(GL_INVALID_OPERATION); - } - - context->setProgramBinary(program, binary, length); + if (!programObject) + { + return gl::error(GL_INVALID_OPERATION); } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY); + + context->setProgramBinary(program, binary, length); } } @@ -6965,57 +8015,271 @@ void __stdcall glDrawBuffersEXT(GLsizei n, const GLenum *bufs) { EVENT("(GLenum n = %d, bufs = 0x%0.8p)", n, bufs); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers) + { + return gl::error(GL_INVALID_VALUE); + } - if (context) + if (context->getState().getDrawFramebuffer()->id() == 0) { - if (n < 0 || (unsigned int)n > context->getMaximumRenderTargets()) + if (n != 1) { - return gl::error(GL_INVALID_VALUE); + return gl::error(GL_INVALID_OPERATION); } - if (context->getDrawFramebufferHandle() == 0) + if (bufs[0] != GL_NONE && bufs[0] != GL_BACK) { - if (n != 1) - { - return gl::error(GL_INVALID_OPERATION); - } - - if (bufs[0] != GL_NONE && bufs[0] != GL_BACK) - { - return gl::error(GL_INVALID_OPERATION); - } + return gl::error(GL_INVALID_OPERATION); } - else + } + else + { + for (int colorAttachment = 0; colorAttachment < n; colorAttachment++) { - for (int colorAttachment = 0; colorAttachment < n; colorAttachment++) + const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment; + if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment) { - const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment; - if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment) - { - return gl::error(GL_INVALID_OPERATION); - } + return gl::error(GL_INVALID_OPERATION); } } + } - gl::Framebuffer *framebuffer = context->getDrawFramebuffer(); + gl::Framebuffer *framebuffer = context->getState().getDrawFramebuffer(); - for (int colorAttachment = 0; colorAttachment < n; colorAttachment++) - { - framebuffer->setDrawBufferState(colorAttachment, bufs[colorAttachment]); - } + for (unsigned int colorAttachment = 0; colorAttachment < static_cast<unsigned int>(n); colorAttachment++) + { + framebuffer->setDrawBufferState(colorAttachment, bufs[colorAttachment]); + } - for (int colorAttachment = n; colorAttachment < (int)context->getMaximumRenderTargets(); colorAttachment++) - { - framebuffer->setDrawBufferState(colorAttachment, GL_NONE); - } + for (unsigned int colorAttachment = n; colorAttachment < context->getCaps().maxDrawBuffers; colorAttachment++) + { + framebuffer->setDrawBufferState(colorAttachment, GL_NONE); } } - catch (std::bad_alloc&) +} + +void __stdcall glGetBufferPointervOES(GLenum target, GLenum pname, void** params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params); + + gl::Context *context = gl::getNonLostContext(); + + if (context) { - return gl::error(GL_OUT_OF_MEMORY); + if (!gl::ValidBufferTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM); + } + + if (pname != GL_BUFFER_MAP_POINTER) + { + return gl::error(GL_INVALID_ENUM); + } + + gl::Buffer *buffer = context->getState().getTargetBuffer(target); + + if (!buffer || !buffer->isMapped()) + { + *params = NULL; + } + else + { + *params = buffer->getMapPointer(); + } + } +} + +void * __stdcall glMapBufferOES(GLenum target, GLenum access) +{ + EVENT("(GLenum target = 0x%X, GLbitfield access = 0x%X)", target, access); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!gl::ValidBufferTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM, reinterpret_cast<GLvoid*>(NULL)); + } + + gl::Buffer *buffer = context->getState().getTargetBuffer(target); + + if (buffer == NULL) + { + return gl::error(GL_INVALID_OPERATION, reinterpret_cast<GLvoid*>(NULL)); + } + + if (access != GL_WRITE_ONLY_OES) + { + return gl::error(GL_INVALID_ENUM, reinterpret_cast<GLvoid*>(NULL)); + } + + if (buffer->isMapped()) + { + return gl::error(GL_INVALID_OPERATION, reinterpret_cast<GLvoid*>(NULL)); + } + + return buffer->mapRange(0, buffer->getSize(), GL_MAP_WRITE_BIT); + } + + return NULL; +} + +GLboolean __stdcall glUnmapBufferOES(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!gl::ValidBufferTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM, GL_FALSE); + } + + gl::Buffer *buffer = context->getState().getTargetBuffer(target); + + if (buffer == NULL || !buffer->isMapped()) + { + return gl::error(GL_INVALID_OPERATION, GL_FALSE); + } + + // TODO: detect if we had corruption. if so, throw an error and return false. + + buffer->unmap(); + + return GL_TRUE; + } + + return GL_FALSE; +} + +void* __stdcall glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +{ + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)", + target, offset, length, access); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!gl::ValidBufferTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM, reinterpret_cast<GLvoid*>(NULL)); + } + + if (offset < 0 || length < 0) + { + return gl::error(GL_INVALID_VALUE, reinterpret_cast<GLvoid*>(NULL)); + } + + gl::Buffer *buffer = context->getState().getTargetBuffer(target); + + if (buffer == NULL) + { + return gl::error(GL_INVALID_OPERATION, reinterpret_cast<GLvoid*>(NULL)); + } + + // Check for buffer overflow + size_t offsetSize = static_cast<size_t>(offset); + size_t lengthSize = static_cast<size_t>(length); + + if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) || + offsetSize + lengthSize > static_cast<size_t>(buffer->getSize())) + { + return gl::error(GL_INVALID_VALUE, reinterpret_cast<GLvoid*>(NULL)); + } + + // Check for invalid bits in the mask + GLbitfield allAccessBits = GL_MAP_READ_BIT | + GL_MAP_WRITE_BIT | + GL_MAP_INVALIDATE_RANGE_BIT | + GL_MAP_INVALIDATE_BUFFER_BIT | + GL_MAP_FLUSH_EXPLICIT_BIT | + GL_MAP_UNSYNCHRONIZED_BIT; + + if (access & ~(allAccessBits)) + { + return gl::error(GL_INVALID_VALUE, reinterpret_cast<GLvoid*>(NULL)); + } + + if (length == 0 || buffer->isMapped()) + { + return gl::error(GL_INVALID_OPERATION, reinterpret_cast<GLvoid*>(NULL)); + } + + // Check for invalid bit combinations + if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) + { + return gl::error(GL_INVALID_OPERATION, reinterpret_cast<GLvoid*>(NULL)); + } + + GLbitfield writeOnlyBits = GL_MAP_INVALIDATE_RANGE_BIT | + GL_MAP_INVALIDATE_BUFFER_BIT | + GL_MAP_UNSYNCHRONIZED_BIT; + + if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0) + { + return gl::error(GL_INVALID_OPERATION, reinterpret_cast<GLvoid*>(NULL)); + } + + if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0) + { + return gl::error(GL_INVALID_OPERATION, reinterpret_cast<GLvoid*>(NULL)); + } + + return buffer->mapRange(offset, length, access); + } + + return NULL; +} + +void __stdcall glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length) +{ + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length); + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (offset < 0 || length < 0) + { + return gl::error(GL_INVALID_VALUE); + } + + if (!gl::ValidBufferTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM); + } + + gl::Buffer *buffer = context->getState().getTargetBuffer(target); + + if (buffer == NULL) + { + return gl::error(GL_INVALID_OPERATION); + } + + if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) + { + return gl::error(GL_INVALID_OPERATION); + } + + // Check for buffer overflow + size_t offsetSize = static_cast<size_t>(offset); + size_t lengthSize = static_cast<size_t>(length); + + if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) || + offsetSize + lengthSize > static_cast<size_t>(buffer->getMapLength())) + { + return gl::error(GL_INVALID_VALUE); + } + + // We do not currently support a non-trivial implementation of FlushMappedBufferRange } } @@ -7057,7 +8321,12 @@ __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char * {"glDrawArraysInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawArraysInstancedANGLE}, {"glDrawElementsInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawElementsInstancedANGLE}, {"glGetProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glGetProgramBinaryOES}, - {"glProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glProgramBinaryOES}, }; + {"glProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glProgramBinaryOES}, + {"glGetBufferPointervOES", (__eglMustCastToProperFunctionPointerType)glGetBufferPointervOES}, + {"glMapBufferOES", (__eglMustCastToProperFunctionPointerType)glMapBufferOES}, + {"glUnmapBufferOES", (__eglMustCastToProperFunctionPointerType)glUnmapBufferOES}, + {"glMapBufferRangeEXT", (__eglMustCastToProperFunctionPointerType)glMapBufferRangeEXT}, + {"glFlushMappedBufferRangeEXT", (__eglMustCastToProperFunctionPointerType)glFlushMappedBufferRangeEXT}, }; for (unsigned int ext = 0; ext < ArraySize(glExtensions); ext++) { @@ -7077,28 +8346,19 @@ bool __stdcall glBindTexImage(egl::Surface *surface) EVENT("(egl::Surface* surface = 0x%0.8p)", surface); - try + gl::Context *context = gl::getNonLostContext(); + + if (context) { - gl::Context *context = gl::getNonLostContext(); + gl::Texture2D *textureObject = context->getTexture2D(); + ASSERT(textureObject != NULL); - if (context) + if (textureObject->isImmutable()) { - gl::Texture2D *textureObject = context->getTexture2D(); - - if (textureObject->isImmutable()) - { - return false; - } - - if (textureObject) - { - textureObject->bindTexImage(surface); - } + return false; } - } - catch(std::bad_alloc&) - { - return gl::error(GL_OUT_OF_MEMORY, false); + + textureObject->bindTexImage(surface); } return true; diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def index b8320c8f25..88dceb3556 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def @@ -173,6 +173,117 @@ EXPORTS glProgramBinaryOES @175 glGetProgramBinaryOES @176 glDrawBuffersEXT @179 + glMapBufferOES @285 + glUnmapBufferOES @286 + glGetBufferPointervOES @287 + glMapBufferRangeEXT @288 + glFlushMappedBufferRangeEXT @289 + + ; GLES 3.0 Functions + glReadBuffer @180 + glDrawRangeElements @181 + glTexImage3D @182 + glTexSubImage3D @183 + glCopyTexSubImage3D @184 + glCompressedTexImage3D @185 + glCompressedTexSubImage3D @186 + glGenQueries @187 + glDeleteQueries @188 + glIsQuery @189 + glBeginQuery @190 + glEndQuery @191 + glGetQueryiv @192 + glGetQueryObjectuiv @193 + glUnmapBuffer @194 + glGetBufferPointerv @195 + glDrawBuffers @196 + glUniformMatrix2x3fv @197 + glUniformMatrix3x2fv @198 + glUniformMatrix2x4fv @199 + glUniformMatrix4x2fv @200 + glUniformMatrix3x4fv @201 + glUniformMatrix4x3fv @202 + glBlitFramebuffer @203 + glRenderbufferStorageMultisample @204 + glFramebufferTextureLayer @205 + glMapBufferRange @206 + glFlushMappedBufferRange @207 + glBindVertexArray @208 + glDeleteVertexArrays @209 + glGenVertexArrays @210 + glIsVertexArray @211 + glGetIntegeri_v @212 + glBeginTransformFeedback @213 + glEndTransformFeedback @214 + glBindBufferRange @215 + glBindBufferBase @216 + glTransformFeedbackVaryings @217 + glGetTransformFeedbackVarying @218 + glVertexAttribIPointer @219 + glGetVertexAttribIiv @220 + glGetVertexAttribIuiv @221 + glVertexAttribI4i @222 + glVertexAttribI4ui @223 + glVertexAttribI4iv @224 + glVertexAttribI4uiv @225 + glGetUniformuiv @226 + glGetFragDataLocation @227 + glUniform1ui @228 + glUniform2ui @229 + glUniform3ui @230 + glUniform4ui @231 + glUniform1uiv @232 + glUniform2uiv @233 + glUniform3uiv @234 + glUniform4uiv @235 + glClearBufferiv @236 + glClearBufferuiv @237 + glClearBufferfv @238 + glClearBufferfi @239 + glGetStringi @240 + glCopyBufferSubData @241 + glGetUniformIndices @242 + glGetActiveUniformsiv @243 + glGetUniformBlockIndex @244 + glGetActiveUniformBlockiv @245 + glGetActiveUniformBlockName @246 + glUniformBlockBinding @247 + glDrawArraysInstanced @248 + glDrawElementsInstanced @249 + glFenceSync @250 + glIsSync @251 + glDeleteSync @252 + glClientWaitSync @253 + glWaitSync @254 + glGetInteger64v @255 + glGetSynciv @256 + glGetInteger64i_v @257 + glGetBufferParameteri64v @258 + glGenSamplers @259 + glDeleteSamplers @260 + glIsSampler @261 + glBindSampler @262 + glSamplerParameteri @263 + glSamplerParameteriv @264 + glSamplerParameterf @265 + glSamplerParameterfv @266 + glGetSamplerParameteriv @267 + glGetSamplerParameterfv @268 + glVertexAttribDivisor @269 + glBindTransformFeedback @270 + glDeleteTransformFeedbacks @271 + glGenTransformFeedbacks @272 + glIsTransformFeedback @273 + glPauseTransformFeedback @274 + glResumeTransformFeedback @275 + glGetProgramBinary @276 + glProgramBinary @277 + glProgramParameteri @278 + glInvalidateFramebuffer @279 + glInvalidateSubFramebuffer @280 + glTexStorage2D @281 + glTexStorage3D @282 + glGetInternalformativ @283 ; EGL dependencies glCreateContext @144 NONAME @@ -185,4 +296,4 @@ EXPORTS glDestroyRenderer @178 NONAME ; Setting up TRACE macro callbacks - SetTraceFunctionPointers @180 + SetTraceFunctionPointers @284 diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def index ef44917d71..d6272c4df9 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def @@ -1,188 +1,299 @@ LIBRARY libGLESv2 EXPORTS - glActiveTexture@4 @1 - glAttachShader@8 @2 - glBindAttribLocation@12 @3 - glBindBuffer@8 @4 - glBindFramebuffer@8 @5 - glBindRenderbuffer@8 @6 - glBindTexture@8 @7 - glBlendColor@16 @8 - glBlendEquation@4 @9 - glBlendEquationSeparate@8 @10 - glBlendFunc@8 @11 - glBlendFuncSeparate@16 @12 - glBufferData@16 @13 - glBufferSubData@16 @14 - glCheckFramebufferStatus@4 @15 - glClear@4 @16 - glClearColor@16 @17 - glClearDepthf@4 @18 - glClearStencil@4 @19 - glColorMask@16 @20 - glCompileShader@4 @21 - glCompressedTexImage2D@32 @22 - glCompressedTexSubImage2D@36 @23 - glCopyTexImage2D@32 @24 - glCopyTexSubImage2D@32 @25 - glCreateProgram@0 @26 - glCreateShader@4 @27 - glCullFace@4 @28 - glDeleteBuffers@8 @29 - glDeleteFramebuffers@8 @30 - glDeleteProgram@4 @32 - glDeleteRenderbuffers@8 @33 - glDeleteShader@4 @34 - glDeleteTextures@8 @31 - glDepthFunc@4 @36 - glDepthMask@4 @37 - glDepthRangef@8 @38 - glDetachShader@8 @35 - glDisable@4 @39 - glDisableVertexAttribArray@4 @40 - glDrawArrays@12 @41 - glDrawElements@16 @42 - glEnable@4 @43 - glEnableVertexAttribArray@4 @44 - glFinish@0 @45 - glFlush@0 @46 - glFramebufferRenderbuffer@16 @47 - glFramebufferTexture2D@20 @48 - glFrontFace@4 @49 - glGenBuffers@8 @50 - glGenFramebuffers@8 @52 - glGenRenderbuffers@8 @53 - glGenTextures@8 @54 - glGenerateMipmap@4 @51 - glGetActiveAttrib@28 @55 - glGetActiveUniform@28 @56 - glGetAttachedShaders@16 @57 - glGetAttribLocation@8 @58 - glGetBooleanv@8 @59 - glGetBufferParameteriv@12 @60 - glGetError@0 @61 - glGetFloatv@8 @62 - glGetFramebufferAttachmentParameteriv@16 @63 - glGetIntegerv@8 @64 - glGetProgramInfoLog@16 @66 - glGetProgramiv@12 @65 - glGetRenderbufferParameteriv@12 @67 - glGetShaderInfoLog@16 @69 - glGetShaderPrecisionFormat@16 @70 - glGetShaderSource@16 @71 - glGetShaderiv@12 @68 - glGetString@4 @72 - glGetTexParameterfv@12 @73 - glGetTexParameteriv@12 @74 - glGetUniformLocation@8 @77 - glGetUniformfv@12 @75 - glGetUniformiv@12 @76 - glGetVertexAttribPointerv@12 @80 - glGetVertexAttribfv@12 @78 - glGetVertexAttribiv@12 @79 - glHint@8 @81 - glIsBuffer@4 @82 - glIsEnabled@4 @83 - glIsFramebuffer@4 @84 - glIsProgram@4 @85 - glIsRenderbuffer@4 @86 - glIsShader@4 @87 - glIsTexture@4 @88 - glLineWidth@4 @89 - glLinkProgram@4 @90 - glPixelStorei@8 @91 - glPolygonOffset@8 @92 - glReadPixels@28 @93 - glReleaseShaderCompiler@0 @94 - glRenderbufferStorage@16 @95 - glSampleCoverage@8 @96 - glScissor@16 @97 - glShaderBinary@20 @98 - glShaderSource@16 @99 - glStencilFunc@12 @100 - glStencilFuncSeparate@16 @101 - glStencilMask@4 @102 - glStencilMaskSeparate@8 @103 - glStencilOp@12 @104 - glStencilOpSeparate@16 @105 - glTexImage2D@36 @106 - glTexParameterf@12 @107 - glTexParameterfv@12 @108 - glTexParameteri@12 @109 - glTexParameteriv@12 @110 - glTexSubImage2D@36 @111 - glUniform1f@8 @112 - glUniform1fv@12 @113 - glUniform1i@8 @114 - glUniform1iv@12 @115 - glUniform2f@12 @116 - glUniform2fv@12 @117 - glUniform2i@12 @118 - glUniform2iv@12 @119 - glUniform3f@16 @120 - glUniform3fv@12 @121 - glUniform3i@16 @122 - glUniform3iv@12 @123 - glUniform4f@20 @124 - glUniform4fv@12 @125 - glUniform4i@20 @126 - glUniform4iv@12 @127 - glUniformMatrix2fv@16 @128 - glUniformMatrix3fv@16 @129 - glUniformMatrix4fv@16 @130 - glUseProgram@4 @131 - glValidateProgram@4 @132 - glVertexAttrib1f@8 @133 - glVertexAttrib1fv@8 @134 - glVertexAttrib2f@12 @135 - glVertexAttrib2fv@8 @136 - glVertexAttrib3f@16 @137 - glVertexAttrib3fv@8 @138 - glVertexAttrib4f@20 @139 - glVertexAttrib4fv@8 @140 - glVertexAttribPointer@24 @141 - glViewport@16 @142 + glActiveTexture@4 @1 + glAttachShader@8 @2 + glBindAttribLocation@12 @3 + glBindBuffer@8 @4 + glBindFramebuffer@8 @5 + glBindRenderbuffer@8 @6 + glBindTexture@8 @7 + glBlendColor@16 @8 + glBlendEquation@4 @9 + glBlendEquationSeparate@8 @10 + glBlendFunc@8 @11 + glBlendFuncSeparate@16 @12 + glBufferData@16 @13 + glBufferSubData@16 @14 + glCheckFramebufferStatus@4 @15 + glClear@4 @16 + glClearColor@16 @17 + glClearDepthf@4 @18 + glClearStencil@4 @19 + glColorMask@16 @20 + glCompileShader@4 @21 + glCompressedTexImage2D@32 @22 + glCompressedTexSubImage2D@36 @23 + glCopyTexImage2D@32 @24 + glCopyTexSubImage2D@32 @25 + glCreateProgram@0 @26 + glCreateShader@4 @27 + glCullFace@4 @28 + glDeleteBuffers@8 @29 + glDeleteFramebuffers@8 @30 + glDeleteProgram@4 @32 + glDeleteRenderbuffers@8 @33 + glDeleteShader@4 @34 + glDeleteTextures@8 @31 + glDepthFunc@4 @36 + glDepthMask@4 @37 + glDepthRangef@8 @38 + glDetachShader@8 @35 + glDisable@4 @39 + glDisableVertexAttribArray@4 @40 + glDrawArrays@12 @41 + glDrawElements@16 @42 + glEnable@4 @43 + glEnableVertexAttribArray@4 @44 + glFinish@0 @45 + glFlush@0 @46 + glFramebufferRenderbuffer@16 @47 + glFramebufferTexture2D@20 @48 + glFrontFace@4 @49 + glGenBuffers@8 @50 + glGenFramebuffers@8 @52 + glGenRenderbuffers@8 @53 + glGenTextures@8 @54 + glGenerateMipmap@4 @51 + glGetActiveAttrib@28 @55 + glGetActiveUniform@28 @56 + glGetAttachedShaders@16 @57 + glGetAttribLocation@8 @58 + glGetBooleanv@8 @59 + glGetBufferParameteriv@12 @60 + glGetError@0 @61 + glGetFloatv@8 @62 + glGetFramebufferAttachmentParameteriv@16 @63 + glGetIntegerv@8 @64 + glGetProgramInfoLog@16 @66 + glGetProgramiv@12 @65 + glGetRenderbufferParameteriv@12 @67 + glGetShaderInfoLog@16 @69 + glGetShaderPrecisionFormat@16 @70 + glGetShaderSource@16 @71 + glGetShaderiv@12 @68 + glGetString@4 @72 + glGetTexParameterfv@12 @73 + glGetTexParameteriv@12 @74 + glGetUniformLocation@8 @77 + glGetUniformfv@12 @75 + glGetUniformiv@12 @76 + glGetVertexAttribPointerv@12 @80 + glGetVertexAttribfv@12 @78 + glGetVertexAttribiv@12 @79 + glHint@8 @81 + glIsBuffer@4 @82 + glIsEnabled@4 @83 + glIsFramebuffer@4 @84 + glIsProgram@4 @85 + glIsRenderbuffer@4 @86 + glIsShader@4 @87 + glIsTexture@4 @88 + glLineWidth@4 @89 + glLinkProgram@4 @90 + glPixelStorei@8 @91 + glPolygonOffset@8 @92 + glReadPixels@28 @93 + glReleaseShaderCompiler@0 @94 + glRenderbufferStorage@16 @95 + glSampleCoverage@8 @96 + glScissor@16 @97 + glShaderBinary@20 @98 + glShaderSource@16 @99 + glStencilFunc@12 @100 + glStencilFuncSeparate@16 @101 + glStencilMask@4 @102 + glStencilMaskSeparate@8 @103 + glStencilOp@12 @104 + glStencilOpSeparate@16 @105 + glTexImage2D@36 @106 + glTexParameterf@12 @107 + glTexParameterfv@12 @108 + glTexParameteri@12 @109 + glTexParameteriv@12 @110 + glTexSubImage2D@36 @111 + glUniform1f@8 @112 + glUniform1fv@12 @113 + glUniform1i@8 @114 + glUniform1iv@12 @115 + glUniform2f@12 @116 + glUniform2fv@12 @117 + glUniform2i@12 @118 + glUniform2iv@12 @119 + glUniform3f@16 @120 + glUniform3fv@12 @121 + glUniform3i@16 @122 + glUniform3iv@12 @123 + glUniform4f@20 @124 + glUniform4fv@12 @125 + glUniform4i@20 @126 + glUniform4iv@12 @127 + glUniformMatrix2fv@16 @128 + glUniformMatrix3fv@16 @129 + glUniformMatrix4fv@16 @130 + glUseProgram@4 @131 + glValidateProgram@4 @132 + glVertexAttrib1f@8 @133 + glVertexAttrib1fv@8 @134 + glVertexAttrib2f@12 @135 + glVertexAttrib2fv@8 @136 + glVertexAttrib3f@16 @137 + glVertexAttrib3fv@8 @138 + glVertexAttrib4f@20 @139 + glVertexAttrib4fv@8 @140 + glVertexAttribPointer@24 @141 + glViewport@16 @142 - ; Extensions - glTexImage3DOES@40 @143 - glBlitFramebufferANGLE@40 @149 - glRenderbufferStorageMultisampleANGLE@20 @150 - glDeleteFencesNV@8 @151 - glFinishFenceNV@4 @152 - glGenFencesNV@8 @153 - glGetFenceivNV@12 @154 - glIsFenceNV@4 @155 - glSetFenceNV@8 @156 - glTestFenceNV@4 @157 - glGetTranslatedShaderSourceANGLE@16 @159 - glTexStorage2DEXT@20 @160 - glGetGraphicsResetStatusEXT@0 @161 - glReadnPixelsEXT@32 @162 - glGetnUniformfvEXT@16 @163 - glGetnUniformivEXT@16 @164 - glGenQueriesEXT@8 @165 - glDeleteQueriesEXT@8 @166 - glIsQueryEXT@4 @167 - glBeginQueryEXT@8 @168 - glEndQueryEXT@4 @169 - glGetQueryivEXT@12 @170 - glGetQueryObjectuivEXT@12 @171 - glVertexAttribDivisorANGLE@8 @172 - glDrawArraysInstancedANGLE@16 @173 - glDrawElementsInstancedANGLE@20 @174 - glProgramBinaryOES@16 @175 - glGetProgramBinaryOES@20 @176 - glDrawBuffersEXT@8 @179 + ; Extensions + glTexImage3DOES@40 @143 + glBlitFramebufferANGLE@40 @149 + glRenderbufferStorageMultisampleANGLE@20 @150 + glDeleteFencesNV@8 @151 + glFinishFenceNV@4 @152 + glGenFencesNV@8 @153 + glGetFenceivNV@12 @154 + glIsFenceNV@4 @155 + glSetFenceNV@8 @156 + glTestFenceNV@4 @157 + glGetTranslatedShaderSourceANGLE@16 @159 + glTexStorage2DEXT@20 @160 + glGetGraphicsResetStatusEXT@0 @161 + glReadnPixelsEXT@32 @162 + glGetnUniformfvEXT@16 @163 + glGetnUniformivEXT@16 @164 + glGenQueriesEXT@8 @165 + glDeleteQueriesEXT@8 @166 + glIsQueryEXT@4 @167 + glBeginQueryEXT@8 @168 + glEndQueryEXT@4 @169 + glGetQueryivEXT@12 @170 + glGetQueryObjectuivEXT@12 @171 + glVertexAttribDivisorANGLE@8 @172 + glDrawArraysInstancedANGLE@16 @173 + glDrawElementsInstancedANGLE@20 @174 + glProgramBinaryOES@16 @175 + glGetProgramBinaryOES@20 @176 + glDrawBuffersEXT@8 @179 + glMapBufferOES@8 @285 + glUnmapBufferOES@4 @286 + glGetBufferPointervOES@12 @287 + glMapBufferRangeEXT@16 @288 + glFlushMappedBufferRangeEXT@12 @289 - ; EGL dependencies - glCreateContext @144 NONAME - glDestroyContext @145 NONAME - glMakeCurrent @146 NONAME - glGetCurrentContext @147 NONAME - glGetProcAddress@4 @148 NONAME - glBindTexImage@4 @158 NONAME - glCreateRenderer @177 NONAME - glDestroyRenderer @178 NONAME + ; GLES 3.0 Functions + glReadBuffer@4 @180 + glDrawRangeElements@24 @181 + glTexImage3D@40 @182 + glTexSubImage3D@44 @183 + glCopyTexSubImage3D@36 @184 + glCompressedTexImage3D@36 @185 + glCompressedTexSubImage3D@44 @186 + glGenQueries@8 @187 + glDeleteQueries@8 @188 + glIsQuery@4 @189 + glBeginQuery@8 @190 + glEndQuery@4 @191 + glGetQueryiv@12 @192 + glGetQueryObjectuiv@12 @193 + glUnmapBuffer@4 @194 + glGetBufferPointerv@12 @195 + glDrawBuffers@8 @196 + glUniformMatrix2x3fv@16 @197 + glUniformMatrix3x2fv@16 @198 + glUniformMatrix2x4fv@16 @199 + glUniformMatrix4x2fv@16 @200 + glUniformMatrix3x4fv@16 @201 + glUniformMatrix4x3fv@16 @202 + glBlitFramebuffer@40 @203 + glRenderbufferStorageMultisample@20 @204 + glFramebufferTextureLayer@20 @205 + glMapBufferRange@16 @206 + glFlushMappedBufferRange@12 @207 + glBindVertexArray@4 @208 + glDeleteVertexArrays@8 @209 + glGenVertexArrays@8 @210 + glIsVertexArray@4 @211 + glGetIntegeri_v@12 @212 + glBeginTransformFeedback@4 @213 + glEndTransformFeedback@0 @214 + glBindBufferRange@20 @215 + glBindBufferBase@12 @216 + glTransformFeedbackVaryings@16 @217 + glGetTransformFeedbackVarying@28 @218 + glVertexAttribIPointer@20 @219 + glGetVertexAttribIiv@12 @220 + glGetVertexAttribIuiv@12 @221 + glVertexAttribI4i@20 @222 + glVertexAttribI4ui@20 @223 + glVertexAttribI4iv@8 @224 + glVertexAttribI4uiv@8 @225 + glGetUniformuiv@12 @226 + glGetFragDataLocation@8 @227 + glUniform1ui@8 @228 + glUniform2ui@12 @229 + glUniform3ui@16 @230 + glUniform4ui@20 @231 + glUniform1uiv@12 @232 + glUniform2uiv@12 @233 + glUniform3uiv@12 @234 + glUniform4uiv@12 @235 + glClearBufferiv@12 @236 + glClearBufferuiv@12 @237 + glClearBufferfv@12 @238 + glClearBufferfi@16 @239 + glGetStringi@8 @240 + glCopyBufferSubData@20 @241 + glGetUniformIndices@16 @242 + glGetActiveUniformsiv@20 @243 + glGetUniformBlockIndex@8 @244 + glGetActiveUniformBlockiv@16 @245 + glGetActiveUniformBlockName@20 @246 + glUniformBlockBinding@12 @247 + glDrawArraysInstanced@16 @248 + glDrawElementsInstanced@20 @249 + glFenceSync@8 @250 + glIsSync@4 @251 + glDeleteSync@4 @252 + glClientWaitSync@16 @253 + glWaitSync@16 @254 + glGetInteger64v@8 @255 + glGetSynciv@20 @256 + glGetInteger64i_v@12 @257 + glGetBufferParameteri64v@12 @258 + glGenSamplers@8 @259 + glDeleteSamplers@8 @260 + glIsSampler@4 @261 + glBindSampler@8 @262 + glSamplerParameteri@12 @263 + glSamplerParameteriv@12 @264 + glSamplerParameterf@12 @265 + glSamplerParameterfv@12 @266 + glGetSamplerParameteriv@12 @267 + glGetSamplerParameterfv@12 @268 + glVertexAttribDivisor@8 @269 + glBindTransformFeedback@8 @270 + glDeleteTransformFeedbacks@8 @271 + glGenTransformFeedbacks@8 @272 + glIsTransformFeedback@4 @273 + glPauseTransformFeedback@0 @274 + glResumeTransformFeedback@0 @275 + glGetProgramBinary@20 @276 + glProgramBinary@16 @277 + glProgramParameteri@12 @278 + glInvalidateFramebuffer@12 @279 + glInvalidateSubFramebuffer@28 @280 + glTexStorage2D@20 @281 + glTexStorage3D@24 @282 + glGetInternalformativ@20 @283 - ; Setting up TRACE macro callbacks - SetTraceFunctionPointers@8 @180 + ; EGL dependencies + glCreateContext @144 NONAME + glDestroyContext @145 NONAME + glMakeCurrent @146 NONAME + glGetCurrentContext @147 NONAME + glGetProcAddress@4 @148 NONAME + glBindTexImage@4 @158 NONAME + glCreateRenderer @177 NONAME + glDestroyRenderer @178 NONAME + + ; Setting up TRACE macro callbacks + SetTraceFunctionPointers@8 @284 diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def index 3dd5683b5f..d301aa0905 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def @@ -173,6 +173,117 @@ EXPORTS glProgramBinaryOES @175 glGetProgramBinaryOES @176 glDrawBuffersEXT @179 + glMapBufferOES @285 + glUnmapBufferOES @286 + glGetBufferPointervOES @287 + glMapBufferRangeEXT @288 + glFlushMappedBufferRangeEXT @289 + + ; GLES 3.0 Functions + glReadBuffer @180 + glDrawRangeElements @181 + glTexImage3D @182 + glTexSubImage3D @183 + glCopyTexSubImage3D @184 + glCompressedTexImage3D @185 + glCompressedTexSubImage3D @186 + glGenQueries @187 + glDeleteQueries @188 + glIsQuery @189 + glBeginQuery @190 + glEndQuery @191 + glGetQueryiv @192 + glGetQueryObjectuiv @193 + glUnmapBuffer @194 + glGetBufferPointerv @195 + glDrawBuffers @196 + glUniformMatrix2x3fv @197 + glUniformMatrix3x2fv @198 + glUniformMatrix2x4fv @199 + glUniformMatrix4x2fv @200 + glUniformMatrix3x4fv @201 + glUniformMatrix4x3fv @202 + glBlitFramebuffer @203 + glRenderbufferStorageMultisample @204 + glFramebufferTextureLayer @205 + glMapBufferRange @206 + glFlushMappedBufferRange @207 + glBindVertexArray @208 + glDeleteVertexArrays @209 + glGenVertexArrays @210 + glIsVertexArray @211 + glGetIntegeri_v @212 + glBeginTransformFeedback @213 + glEndTransformFeedback @214 + glBindBufferRange @215 + glBindBufferBase @216 + glTransformFeedbackVaryings @217 + glGetTransformFeedbackVarying @218 + glVertexAttribIPointer @219 + glGetVertexAttribIiv @220 + glGetVertexAttribIuiv @221 + glVertexAttribI4i @222 + glVertexAttribI4ui @223 + glVertexAttribI4iv @224 + glVertexAttribI4uiv @225 + glGetUniformuiv @226 + glGetFragDataLocation @227 + glUniform1ui @228 + glUniform2ui @229 + glUniform3ui @230 + glUniform4ui @231 + glUniform1uiv @232 + glUniform2uiv @233 + glUniform3uiv @234 + glUniform4uiv @235 + glClearBufferiv @236 + glClearBufferuiv @237 + glClearBufferfv @238 + glClearBufferfi @239 + glGetStringi @240 + glCopyBufferSubData @241 + glGetUniformIndices @242 + glGetActiveUniformsiv @243 + glGetUniformBlockIndex @244 + glGetActiveUniformBlockiv @245 + glGetActiveUniformBlockName @246 + glUniformBlockBinding @247 + glDrawArraysInstanced @248 + glDrawElementsInstanced @249 + glFenceSync @250 + glIsSync @251 + glDeleteSync @252 + glClientWaitSync @253 + glWaitSync @254 + glGetInteger64v @255 + glGetSynciv @256 + glGetInteger64i_v @257 + glGetBufferParameteri64v @258 + glGenSamplers @259 + glDeleteSamplers @260 + glIsSampler @261 + glBindSampler @262 + glSamplerParameteri @263 + glSamplerParameteriv @264 + glSamplerParameterf @265 + glSamplerParameterfv @266 + glGetSamplerParameteriv @267 + glGetSamplerParameterfv @268 + glVertexAttribDivisor @269 + glBindTransformFeedback @270 + glDeleteTransformFeedbacks @271 + glGenTransformFeedbacks @272 + glIsTransformFeedback @273 + glPauseTransformFeedback @274 + glResumeTransformFeedback @275 + glGetProgramBinary @276 + glProgramBinary @277 + glProgramParameteri @278 + glInvalidateFramebuffer @279 + glInvalidateSubFramebuffer @280 + glTexStorage2D @281 + glTexStorage3D @282 + glGetInternalformativ @283 ; EGL dependencies glCreateContext @144 NONAME @@ -185,4 +296,4 @@ EXPORTS glDestroyRenderer @178 NONAME ; Setting up TRACE macro callbacks - SetTraceFunctionPointers @180 + SetTraceFunctionPointers @284 diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def index 6c8d3ed630..a82d629ae4 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def @@ -1,188 +1,299 @@ LIBRARY libGLESv2d EXPORTS - glActiveTexture@4 @1 - glAttachShader@8 @2 - glBindAttribLocation@12 @3 - glBindBuffer@8 @4 - glBindFramebuffer@8 @5 - glBindRenderbuffer@8 @6 - glBindTexture@8 @7 - glBlendColor@16 @8 - glBlendEquation@4 @9 - glBlendEquationSeparate@8 @10 - glBlendFunc@8 @11 - glBlendFuncSeparate@16 @12 - glBufferData@16 @13 - glBufferSubData@16 @14 - glCheckFramebufferStatus@4 @15 - glClear@4 @16 - glClearColor@16 @17 - glClearDepthf@4 @18 - glClearStencil@4 @19 - glColorMask@16 @20 - glCompileShader@4 @21 - glCompressedTexImage2D@32 @22 - glCompressedTexSubImage2D@36 @23 - glCopyTexImage2D@32 @24 - glCopyTexSubImage2D@32 @25 - glCreateProgram@0 @26 - glCreateShader@4 @27 - glCullFace@4 @28 - glDeleteBuffers@8 @29 - glDeleteFramebuffers@8 @30 - glDeleteProgram@4 @32 - glDeleteRenderbuffers@8 @33 - glDeleteShader@4 @34 - glDeleteTextures@8 @31 - glDepthFunc@4 @36 - glDepthMask@4 @37 - glDepthRangef@8 @38 - glDetachShader@8 @35 - glDisable@4 @39 - glDisableVertexAttribArray@4 @40 - glDrawArrays@12 @41 - glDrawElements@16 @42 - glEnable@4 @43 - glEnableVertexAttribArray@4 @44 - glFinish@0 @45 - glFlush@0 @46 - glFramebufferRenderbuffer@16 @47 - glFramebufferTexture2D@20 @48 - glFrontFace@4 @49 - glGenBuffers@8 @50 - glGenFramebuffers@8 @52 - glGenRenderbuffers@8 @53 - glGenTextures@8 @54 - glGenerateMipmap@4 @51 - glGetActiveAttrib@28 @55 - glGetActiveUniform@28 @56 - glGetAttachedShaders@16 @57 - glGetAttribLocation@8 @58 - glGetBooleanv@8 @59 - glGetBufferParameteriv@12 @60 - glGetError@0 @61 - glGetFloatv@8 @62 - glGetFramebufferAttachmentParameteriv@16 @63 - glGetIntegerv@8 @64 - glGetProgramInfoLog@16 @66 - glGetProgramiv@12 @65 - glGetRenderbufferParameteriv@12 @67 - glGetShaderInfoLog@16 @69 - glGetShaderPrecisionFormat@16 @70 - glGetShaderSource@16 @71 - glGetShaderiv@12 @68 - glGetString@4 @72 - glGetTexParameterfv@12 @73 - glGetTexParameteriv@12 @74 - glGetUniformLocation@8 @77 - glGetUniformfv@12 @75 - glGetUniformiv@12 @76 - glGetVertexAttribPointerv@12 @80 - glGetVertexAttribfv@12 @78 - glGetVertexAttribiv@12 @79 - glHint@8 @81 - glIsBuffer@4 @82 - glIsEnabled@4 @83 - glIsFramebuffer@4 @84 - glIsProgram@4 @85 - glIsRenderbuffer@4 @86 - glIsShader@4 @87 - glIsTexture@4 @88 - glLineWidth@4 @89 - glLinkProgram@4 @90 - glPixelStorei@8 @91 - glPolygonOffset@8 @92 - glReadPixels@28 @93 - glReleaseShaderCompiler@0 @94 - glRenderbufferStorage@16 @95 - glSampleCoverage@8 @96 - glScissor@16 @97 - glShaderBinary@20 @98 - glShaderSource@16 @99 - glStencilFunc@12 @100 - glStencilFuncSeparate@16 @101 - glStencilMask@4 @102 - glStencilMaskSeparate@8 @103 - glStencilOp@12 @104 - glStencilOpSeparate@16 @105 - glTexImage2D@36 @106 - glTexParameterf@12 @107 - glTexParameterfv@12 @108 - glTexParameteri@12 @109 - glTexParameteriv@12 @110 - glTexSubImage2D@36 @111 - glUniform1f@8 @112 - glUniform1fv@12 @113 - glUniform1i@8 @114 - glUniform1iv@12 @115 - glUniform2f@12 @116 - glUniform2fv@12 @117 - glUniform2i@12 @118 - glUniform2iv@12 @119 - glUniform3f@16 @120 - glUniform3fv@12 @121 - glUniform3i@16 @122 - glUniform3iv@12 @123 - glUniform4f@20 @124 - glUniform4fv@12 @125 - glUniform4i@20 @126 - glUniform4iv@12 @127 - glUniformMatrix2fv@16 @128 - glUniformMatrix3fv@16 @129 - glUniformMatrix4fv@16 @130 - glUseProgram@4 @131 - glValidateProgram@4 @132 - glVertexAttrib1f@8 @133 - glVertexAttrib1fv@8 @134 - glVertexAttrib2f@12 @135 - glVertexAttrib2fv@8 @136 - glVertexAttrib3f@16 @137 - glVertexAttrib3fv@8 @138 - glVertexAttrib4f@20 @139 - glVertexAttrib4fv@8 @140 - glVertexAttribPointer@24 @141 - glViewport@16 @142 + glActiveTexture@4 @1 + glAttachShader@8 @2 + glBindAttribLocation@12 @3 + glBindBuffer@8 @4 + glBindFramebuffer@8 @5 + glBindRenderbuffer@8 @6 + glBindTexture@8 @7 + glBlendColor@16 @8 + glBlendEquation@4 @9 + glBlendEquationSeparate@8 @10 + glBlendFunc@8 @11 + glBlendFuncSeparate@16 @12 + glBufferData@16 @13 + glBufferSubData@16 @14 + glCheckFramebufferStatus@4 @15 + glClear@4 @16 + glClearColor@16 @17 + glClearDepthf@4 @18 + glClearStencil@4 @19 + glColorMask@16 @20 + glCompileShader@4 @21 + glCompressedTexImage2D@32 @22 + glCompressedTexSubImage2D@36 @23 + glCopyTexImage2D@32 @24 + glCopyTexSubImage2D@32 @25 + glCreateProgram@0 @26 + glCreateShader@4 @27 + glCullFace@4 @28 + glDeleteBuffers@8 @29 + glDeleteFramebuffers@8 @30 + glDeleteProgram@4 @32 + glDeleteRenderbuffers@8 @33 + glDeleteShader@4 @34 + glDeleteTextures@8 @31 + glDepthFunc@4 @36 + glDepthMask@4 @37 + glDepthRangef@8 @38 + glDetachShader@8 @35 + glDisable@4 @39 + glDisableVertexAttribArray@4 @40 + glDrawArrays@12 @41 + glDrawElements@16 @42 + glEnable@4 @43 + glEnableVertexAttribArray@4 @44 + glFinish@0 @45 + glFlush@0 @46 + glFramebufferRenderbuffer@16 @47 + glFramebufferTexture2D@20 @48 + glFrontFace@4 @49 + glGenBuffers@8 @50 + glGenFramebuffers@8 @52 + glGenRenderbuffers@8 @53 + glGenTextures@8 @54 + glGenerateMipmap@4 @51 + glGetActiveAttrib@28 @55 + glGetActiveUniform@28 @56 + glGetAttachedShaders@16 @57 + glGetAttribLocation@8 @58 + glGetBooleanv@8 @59 + glGetBufferParameteriv@12 @60 + glGetError@0 @61 + glGetFloatv@8 @62 + glGetFramebufferAttachmentParameteriv@16 @63 + glGetIntegerv@8 @64 + glGetProgramInfoLog@16 @66 + glGetProgramiv@12 @65 + glGetRenderbufferParameteriv@12 @67 + glGetShaderInfoLog@16 @69 + glGetShaderPrecisionFormat@16 @70 + glGetShaderSource@16 @71 + glGetShaderiv@12 @68 + glGetString@4 @72 + glGetTexParameterfv@12 @73 + glGetTexParameteriv@12 @74 + glGetUniformLocation@8 @77 + glGetUniformfv@12 @75 + glGetUniformiv@12 @76 + glGetVertexAttribPointerv@12 @80 + glGetVertexAttribfv@12 @78 + glGetVertexAttribiv@12 @79 + glHint@8 @81 + glIsBuffer@4 @82 + glIsEnabled@4 @83 + glIsFramebuffer@4 @84 + glIsProgram@4 @85 + glIsRenderbuffer@4 @86 + glIsShader@4 @87 + glIsTexture@4 @88 + glLineWidth@4 @89 + glLinkProgram@4 @90 + glPixelStorei@8 @91 + glPolygonOffset@8 @92 + glReadPixels@28 @93 + glReleaseShaderCompiler@0 @94 + glRenderbufferStorage@16 @95 + glSampleCoverage@8 @96 + glScissor@16 @97 + glShaderBinary@20 @98 + glShaderSource@16 @99 + glStencilFunc@12 @100 + glStencilFuncSeparate@16 @101 + glStencilMask@4 @102 + glStencilMaskSeparate@8 @103 + glStencilOp@12 @104 + glStencilOpSeparate@16 @105 + glTexImage2D@36 @106 + glTexParameterf@12 @107 + glTexParameterfv@12 @108 + glTexParameteri@12 @109 + glTexParameteriv@12 @110 + glTexSubImage2D@36 @111 + glUniform1f@8 @112 + glUniform1fv@12 @113 + glUniform1i@8 @114 + glUniform1iv@12 @115 + glUniform2f@12 @116 + glUniform2fv@12 @117 + glUniform2i@12 @118 + glUniform2iv@12 @119 + glUniform3f@16 @120 + glUniform3fv@12 @121 + glUniform3i@16 @122 + glUniform3iv@12 @123 + glUniform4f@20 @124 + glUniform4fv@12 @125 + glUniform4i@20 @126 + glUniform4iv@12 @127 + glUniformMatrix2fv@16 @128 + glUniformMatrix3fv@16 @129 + glUniformMatrix4fv@16 @130 + glUseProgram@4 @131 + glValidateProgram@4 @132 + glVertexAttrib1f@8 @133 + glVertexAttrib1fv@8 @134 + glVertexAttrib2f@12 @135 + glVertexAttrib2fv@8 @136 + glVertexAttrib3f@16 @137 + glVertexAttrib3fv@8 @138 + glVertexAttrib4f@20 @139 + glVertexAttrib4fv@8 @140 + glVertexAttribPointer@24 @141 + glViewport@16 @142 - ; Extensions - glTexImage3DOES@40 @143 - glBlitFramebufferANGLE@40 @149 - glRenderbufferStorageMultisampleANGLE@20 @150 - glDeleteFencesNV@8 @151 - glFinishFenceNV@4 @152 - glGenFencesNV@8 @153 - glGetFenceivNV@12 @154 - glIsFenceNV@4 @155 - glSetFenceNV@8 @156 - glTestFenceNV@4 @157 - glGetTranslatedShaderSourceANGLE@16 @159 - glTexStorage2DEXT@20 @160 - glGetGraphicsResetStatusEXT@0 @161 - glReadnPixelsEXT@32 @162 - glGetnUniformfvEXT@16 @163 - glGetnUniformivEXT@16 @164 - glGenQueriesEXT@8 @165 - glDeleteQueriesEXT@8 @166 - glIsQueryEXT@4 @167 - glBeginQueryEXT@8 @168 - glEndQueryEXT@4 @169 - glGetQueryivEXT@12 @170 - glGetQueryObjectuivEXT@12 @171 - glVertexAttribDivisorANGLE@8 @172 - glDrawArraysInstancedANGLE@16 @173 - glDrawElementsInstancedANGLE@20 @174 - glProgramBinaryOES@16 @175 - glGetProgramBinaryOES@20 @176 - glDrawBuffersEXT@8 @179 + ; Extensions + glTexImage3DOES@40 @143 + glBlitFramebufferANGLE@40 @149 + glRenderbufferStorageMultisampleANGLE@20 @150 + glDeleteFencesNV@8 @151 + glFinishFenceNV@4 @152 + glGenFencesNV@8 @153 + glGetFenceivNV@12 @154 + glIsFenceNV@4 @155 + glSetFenceNV@8 @156 + glTestFenceNV@4 @157 + glGetTranslatedShaderSourceANGLE@16 @159 + glTexStorage2DEXT@20 @160 + glGetGraphicsResetStatusEXT@0 @161 + glReadnPixelsEXT@32 @162 + glGetnUniformfvEXT@16 @163 + glGetnUniformivEXT@16 @164 + glGenQueriesEXT@8 @165 + glDeleteQueriesEXT@8 @166 + glIsQueryEXT@4 @167 + glBeginQueryEXT@8 @168 + glEndQueryEXT@4 @169 + glGetQueryivEXT@12 @170 + glGetQueryObjectuivEXT@12 @171 + glVertexAttribDivisorANGLE@8 @172 + glDrawArraysInstancedANGLE@16 @173 + glDrawElementsInstancedANGLE@20 @174 + glProgramBinaryOES@16 @175 + glGetProgramBinaryOES@20 @176 + glDrawBuffersEXT@8 @179 + glMapBufferOES@8 @285 + glUnmapBufferOES@4 @286 + glGetBufferPointervOES@12 @287 + glMapBufferRangeEXT@16 @288 + glFlushMappedBufferRangeEXT@12 @289 - ; EGL dependencies - glCreateContext @144 NONAME - glDestroyContext @145 NONAME - glMakeCurrent @146 NONAME - glGetCurrentContext @147 NONAME - glGetProcAddress@4 @148 NONAME - glBindTexImage@4 @158 NONAME - glCreateRenderer @177 NONAME - glDestroyRenderer @178 NONAME + ; GLES 3.0 Functions + glReadBuffer@4 @180 + glDrawRangeElements@24 @181 + glTexImage3D@40 @182 + glTexSubImage3D@44 @183 + glCopyTexSubImage3D@36 @184 + glCompressedTexImage3D@36 @185 + glCompressedTexSubImage3D@44 @186 + glGenQueries@8 @187 + glDeleteQueries@8 @188 + glIsQuery@4 @189 + glBeginQuery@8 @190 + glEndQuery@4 @191 + glGetQueryiv@12 @192 + glGetQueryObjectuiv@12 @193 + glUnmapBuffer@4 @194 + glGetBufferPointerv@12 @195 + glDrawBuffers@8 @196 + glUniformMatrix2x3fv@16 @197 + glUniformMatrix3x2fv@16 @198 + glUniformMatrix2x4fv@16 @199 + glUniformMatrix4x2fv@16 @200 + glUniformMatrix3x4fv@16 @201 + glUniformMatrix4x3fv@16 @202 + glBlitFramebuffer@40 @203 + glRenderbufferStorageMultisample@20 @204 + glFramebufferTextureLayer@20 @205 + glMapBufferRange@16 @206 + glFlushMappedBufferRange@12 @207 + glBindVertexArray@4 @208 + glDeleteVertexArrays@8 @209 + glGenVertexArrays@8 @210 + glIsVertexArray@4 @211 + glGetIntegeri_v@12 @212 + glBeginTransformFeedback@4 @213 + glEndTransformFeedback@0 @214 + glBindBufferRange@20 @215 + glBindBufferBase@12 @216 + glTransformFeedbackVaryings@16 @217 + glGetTransformFeedbackVarying@28 @218 + glVertexAttribIPointer@20 @219 + glGetVertexAttribIiv@12 @220 + glGetVertexAttribIuiv@12 @221 + glVertexAttribI4i@20 @222 + glVertexAttribI4ui@20 @223 + glVertexAttribI4iv@8 @224 + glVertexAttribI4uiv@8 @225 + glGetUniformuiv@12 @226 + glGetFragDataLocation@8 @227 + glUniform1ui@8 @228 + glUniform2ui@12 @229 + glUniform3ui@16 @230 + glUniform4ui@20 @231 + glUniform1uiv@12 @232 + glUniform2uiv@12 @233 + glUniform3uiv@12 @234 + glUniform4uiv@12 @235 + glClearBufferiv@12 @236 + glClearBufferuiv@12 @237 + glClearBufferfv@12 @238 + glClearBufferfi@16 @239 + glGetStringi@8 @240 + glCopyBufferSubData@20 @241 + glGetUniformIndices@16 @242 + glGetActiveUniformsiv@20 @243 + glGetUniformBlockIndex@8 @244 + glGetActiveUniformBlockiv@16 @245 + glGetActiveUniformBlockName@20 @246 + glUniformBlockBinding@12 @247 + glDrawArraysInstanced@16 @248 + glDrawElementsInstanced@20 @249 + glFenceSync@8 @250 + glIsSync@4 @251 + glDeleteSync@4 @252 + glClientWaitSync@16 @253 + glWaitSync@16 @254 + glGetInteger64v@8 @255 + glGetSynciv@20 @256 + glGetInteger64i_v@12 @257 + glGetBufferParameteri64v@12 @258 + glGenSamplers@8 @259 + glDeleteSamplers@8 @260 + glIsSampler@4 @261 + glBindSampler@8 @262 + glSamplerParameteri@12 @263 + glSamplerParameteriv@12 @264 + glSamplerParameterf@12 @265 + glSamplerParameterfv@12 @266 + glGetSamplerParameteriv@12 @267 + glGetSamplerParameterfv@12 @268 + glVertexAttribDivisor@8 @269 + glBindTransformFeedback@8 @270 + glDeleteTransformFeedbacks@8 @271 + glGenTransformFeedbacks@8 @272 + glIsTransformFeedback@4 @273 + glPauseTransformFeedback@0 @274 + glResumeTransformFeedback@0 @275 + glGetProgramBinary@20 @276 + glProgramBinary@16 @277 + glProgramParameteri@12 @278 + glInvalidateFramebuffer@12 @279 + glInvalidateSubFramebuffer@28 @280 + glTexStorage2D@20 @281 + glTexStorage3D@24 @282 + glGetInternalformativ@20 @283 - ; Setting up TRACE macro callbacks - SetTraceFunctionPointers@8 @180 + ; EGL dependencies + glCreateContext @144 NONAME + glDestroyContext @145 NONAME + glMakeCurrent @146 NONAME + glGetCurrentContext @147 NONAME + glGetProcAddress@4 @148 NONAME + glBindTexImage@4 @158 NONAME + glCreateRenderer @177 NONAME + glDestroyRenderer @178 NONAME + + ; Setting up TRACE macro callbacks + SetTraceFunctionPointers@8 @284 diff --git a/src/3rdparty/angle/src/libGLESv2/main.cpp b/src/3rdparty/angle/src/libGLESv2/main.cpp index e52799438d..8820700c76 100644 --- a/src/3rdparty/angle/src/libGLESv2/main.cpp +++ b/src/3rdparty/angle/src/libGLESv2/main.cpp @@ -8,60 +8,56 @@ // main.cpp: DLL entry point and management of thread-local data. #include "libGLESv2/main.h" - #include "libGLESv2/Context.h" -#if !defined(ANGLE_OS_WINRT) -static DWORD currentTLS = TLS_OUT_OF_INDEXES; -#else -static __declspec(thread) void *currentTLS = 0; +#include "common/tls.h" + +#if defined(ANGLE_PLATFORM_WINRT) +__declspec(thread) #endif +static TLSIndex currentTLS = TLS_OUT_OF_INDEXES; namespace gl { Current *AllocateCurrent() { -#if !defined(ANGLE_OS_WINRT) - Current *current = (Current*)LocalAlloc(LPTR, sizeof(Current)); -#else - currentTLS = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Current)); - Current *current = (Current*)currentTLS; +#if defined(ANGLE_PLATFORM_WINRT) + if (currentTLS == TLS_OUT_OF_INDEXES) + { + currentTLS = CreateTLSIndex(); + } #endif - - if (!current) + ASSERT(currentTLS != TLS_OUT_OF_INDEXES); + if (currentTLS == TLS_OUT_OF_INDEXES) { - ERR("Could not allocate thread local storage."); return NULL; } -#if !defined(ANGLE_OS_WINRT) - ASSERT(currentTLS != TLS_OUT_OF_INDEXES); - TlsSetValue(currentTLS, current); -#endif - + Current *current = new Current(); current->context = NULL; current->display = NULL; + if (!SetTLSValue(currentTLS, current)) + { + ERR("Could not set thread local storage."); + return NULL; + } + return current; } void DeallocateCurrent() { -#if !defined(ANGLE_OS_WINRT) - void *current = TlsGetValue(currentTLS); - - if (current) +#if defined(ANGLE_PLATFORM_WINRT) + if (currentTLS == TLS_OUT_OF_INDEXES) { - LocalFree((HLOCAL)current); - } -#else - if (currentTLS) - { - HeapFree(GetProcessHeap(), 0, currentTLS); - currentTLS = 0; + return; } #endif + Current *current = reinterpret_cast<Current*>(GetTLSValue(currentTLS)); + SafeDelete(current); + SetTLSValue(currentTLS, NULL); } } @@ -74,16 +70,16 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved { case DLL_PROCESS_ATTACH: { -#if !defined(ANGLE_OS_WINRT) - currentTLS = TlsAlloc(); - +#if defined(ANGLE_PLATFORM_WINRT) // On WinRT, don't handle TLS from DllMain + return DisableThreadLibraryCalls(instance); +#endif + currentTLS = CreateTLSIndex(); if (currentTLS == TLS_OUT_OF_INDEXES) { return FALSE; } -#endif } - // Fall throught to initialize index + // Fall through to initialize index case DLL_THREAD_ATTACH: { gl::AllocateCurrent(); @@ -96,9 +92,9 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved break; case DLL_PROCESS_DETACH: { +#if !defined(ANGLE_PLATFORM_WINRT) gl::DeallocateCurrent(); -#if !defined(ANGLE_OS_WINRT) - TlsFree(currentTLS); + DestroyTLSIndex(currentTLS); #endif } break; @@ -117,20 +113,16 @@ namespace gl Current *GetCurrentData() { #ifndef QT_OPENGL_ES_2_ANGLE_STATIC -#if !defined(ANGLE_OS_WINRT) - Current *current = (Current*)TlsGetValue(currentTLS); -#else - Current *current = (Current*)currentTLS; -#endif -#else - // No precautions for thread safety taken as ANGLE is used single-threaded in Qt. - static Current s_current = { 0, 0 }; - Current *current = &s_current; -#endif + Current *current = reinterpret_cast<Current*>(GetTLSValue(currentTLS)); // ANGLE issue 488: when the dll is loaded after thread initialization, // thread local storage (current) might not exist yet. return (current ? current : AllocateCurrent()); +#else + // No precautions for thread safety taken as ANGLE is used single-threaded in Qt. + static Current current = { 0, 0 }; + return ¤t; +#endif } void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface) @@ -156,7 +148,7 @@ Context *getContext() Context *getNonLostContext() { Context *context = getContext(); - + if (context) { if (context->isContextLost()) diff --git a/src/3rdparty/angle/src/libGLESv2/main.h b/src/3rdparty/angle/src/libGLESv2/main.h index 69465c9bbf..df28ea400d 100644 --- a/src/3rdparty/angle/src/libGLESv2/main.h +++ b/src/3rdparty/angle/src/libGLESv2/main.h @@ -10,6 +10,13 @@ #define LIBGLESV2_MAIN_H_ #include "common/debug.h" +#undef EGLAPI +#define EGLAPI +#include <EGL/egl.h> + +#ifndef Sleep +#define Sleep(ms) WaitForSingleObjectEx(GetCurrentThread(), ms, FALSE) +#endif namespace egl { @@ -53,11 +60,11 @@ class Renderer; extern "C" { // Exported functions for use by EGL -gl::Context *glCreateContext(const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess); +gl::Context *glCreateContext(int clientVersion, const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess); void glDestroyContext(gl::Context *context); void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface); gl::Context *glGetCurrentContext(); -rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType displayId); +rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, EGLint requestedDisplayType); void glDestroyRenderer(rx::Renderer *renderer); __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname); diff --git a/src/3rdparty/angle/src/libGLESv2/mathutil.h b/src/3rdparty/angle/src/libGLESv2/mathutil.h deleted file mode 100644 index 6474b66745..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/mathutil.h +++ /dev/null @@ -1,162 +0,0 @@ -// -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// mathutil.h: Math and bit manipulation functions. - -#ifndef LIBGLESV2_MATHUTIL_H_ -#define LIBGLESV2_MATHUTIL_H_ - -#include <intrin.h> - -#include "common/debug.h" - -namespace gl -{ -struct Vector4 -{ - Vector4() {} - Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} - - float x; - float y; - float z; - float w; -}; - -inline bool isPow2(int x) -{ - return (x & (x - 1)) == 0 && (x != 0); -} - -inline int log2(int x) -{ - int r = 0; - while ((x >> r) > 1) r++; - return r; -} - -inline unsigned int ceilPow2(unsigned int x) -{ - if (x != 0) x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - x++; - - return x; -} - -template<typename T, typename MIN, typename MAX> -inline T clamp(T x, MIN min, MAX max) -{ - // Since NaNs fail all comparison tests, a NaN value will default to min - return x > min ? (x > max ? max : x) : min; -} - -inline float clamp01(float x) -{ - return clamp(x, 0.0f, 1.0f); -} - -template<const int n> -inline unsigned int unorm(float x) -{ - const unsigned int max = 0xFFFFFFFF >> (32 - n); - - if (x > 1) - { - return max; - } - else if (x < 0) - { - return 0; - } - else - { - return (unsigned int)(max * x + 0.5f); - } -} - -inline bool supportsSSE2() -{ - static bool checked = false; - static bool supports = false; - - if (checked) - { - return supports; - } - -#if defined(_M_IX86) || defined(_M_AMD64) // ARM doesn't provide __cpuid() - int info[4]; - __cpuid(info, 0); - - if (info[0] >= 1) - { - __cpuid(info, 1); - - supports = (info[3] >> 26) & 1; - } -#endif - - checked = true; - - return supports; -} - -inline unsigned short float32ToFloat16(float fp32) -{ - unsigned int fp32i = (unsigned int&)fp32; - unsigned int sign = (fp32i & 0x80000000) >> 16; - unsigned int abs = fp32i & 0x7FFFFFFF; - - if(abs > 0x47FFEFFF) // Infinity - { - return sign | 0x7FFF; - } - else if(abs < 0x38800000) // Denormal - { - unsigned int mantissa = (abs & 0x007FFFFF) | 0x00800000; - int e = 113 - (abs >> 23); - - if(e < 24) - { - abs = mantissa >> e; - } - else - { - abs = 0; - } - - return sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13; - } - else - { - return sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13; - } -} - -float float16ToFloat32(unsigned short h); - -} - -namespace rx -{ - -struct Range -{ - Range() {} - Range(int lo, int hi) : start(lo), end(hi) { ASSERT(lo <= hi); } - - int start; - int end; -}; - -} - -#endif // LIBGLESV2_MATHUTIL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/precompiled.h b/src/3rdparty/angle/src/libGLESv2/precompiled.h index 2ff09f531e..0404eabf8a 100644 --- a/src/3rdparty/angle/src/libGLESv2/precompiled.h +++ b/src/3rdparty/angle/src/libGLESv2/precompiled.h @@ -6,16 +6,14 @@ // precompiled.h: Precompiled header file for libGLESv2. -#define GL_APICALL -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - -#define EGLAPI +#include "angle_gl.h" #include <EGL/egl.h> +#include <EGL/eglext.h> #include <assert.h> #include <cstddef> #include <float.h> +#include <stdint.h> #include <intrin.h> #include <math.h> #include <stdarg.h> @@ -31,57 +29,4 @@ #include <string> #include <unordered_map> #include <vector> - -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) -# define ANGLE_OS_WINRT -# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP -# define ANGLE_OS_WINPHONE -# endif -#endif - -#if defined(ANGLE_ENABLE_D3D9) -# include <d3d9.h> -#endif -#if defined(ANGLE_ENABLE_D3D11) -# if !defined(ANGLE_OS_WINRT) -# include <d3d11.h> -# else -# include <d3d11_1.h> -# define Sleep(x) WaitForSingleObjectEx(GetCurrentThread(), x, FALSE) -# define GetVersion() WINVER -# define LoadLibrary(x) LoadPackagedLibrary(x, NULL) -# endif -# include <dxgi.h> -#endif -#if !defined(ANGLE_OS_WINPHONE) -# include <d3dcompiler.h> -#endif - -#ifndef D3DCOMPILE_OPTIMIZATION_LEVEL0 -#define D3DCOMPILE_OPTIMIZATION_LEVEL0 (1 << 14) -#endif -#ifndef D3DCOMPILE_OPTIMIZATION_LEVEL1 -#define D3DCOMPILE_OPTIMIZATION_LEVEL1 0 -#endif -#ifndef D3DCOMPILE_OPTIMIZATION_LEVEL2 -#define D3DCOMPILE_OPTIMIZATION_LEVEL2 ((1 << 14) | (1 << 15)) -#endif -#ifndef D3DCOMPILE_OPTIMIZATION_LEVEL3 -#define D3DCOMPILE_OPTIMIZATION_LEVEL3 (1 << 15) -#endif -#ifndef D3DCOMPILE_DEBUG -#define D3DCOMPILE_DEBUG (1 << 0) -#endif -#ifndef D3DCOMPILE_SKIP_OPTIMIZATION -#define D3DCOMPILE_SKIP_OPTIMIZATION (1 << 2) -#endif -#ifndef D3DCOMPILE_AVOID_FLOW_CONTROL -#define D3DCOMPILE_AVOID_FLOW_CONTROL (1 << 9) -#endif -#ifndef D3DCOMPILE_PREFER_FLOW_CONTROL -#define D3DCOMPILE_PREFER_FLOW_CONTROL (1 << 10) -#endif - -#ifdef _MSC_VER -#include <hash_map> -#endif +#include <iterator> diff --git a/src/3rdparty/angle/src/libGLESv2/queryconversions.cpp b/src/3rdparty/angle/src/libGLESv2/queryconversions.cpp new file mode 100644 index 0000000000..67578efe3a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/queryconversions.cpp @@ -0,0 +1,148 @@ +#include "precompiled.h" +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// queryconversions.cpp: Implementation of state query cast conversions + +#include "libGLESv2/Context.h" +#include "common/utilities.h" + +namespace gl +{ + +// Helper class for converting a GL type to a GLenum: +// We can't use CastStateValueEnum generally, because of GLboolean + GLubyte overlap. +// We restrict our use to CastStateValue, where it eliminates duplicate parameters. + +template <typename GLType> +struct CastStateValueEnum { static GLenum mEnumForType; }; + +template <> GLenum CastStateValueEnum<GLint>::mEnumForType = GL_INT; +template <> GLenum CastStateValueEnum<GLuint>::mEnumForType = GL_UNSIGNED_INT; +template <> GLenum CastStateValueEnum<GLboolean>::mEnumForType = GL_BOOL; +template <> GLenum CastStateValueEnum<GLint64>::mEnumForType = GL_INT_64_ANGLEX; +template <> GLenum CastStateValueEnum<GLfloat>::mEnumForType = GL_FLOAT; + +template <typename QueryT, typename NativeT> +QueryT CastStateValueToInt(GLenum pname, NativeT value) +{ + GLenum queryType = CastStateValueEnum<QueryT>::mEnumForType; + GLenum nativeType = CastStateValueEnum<NativeT>::mEnumForType; + + if (nativeType == GL_FLOAT) + { + // RGBA color values and DepthRangeF values are converted to integer using Equation 2.4 from Table 4.5 + if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR) + { + return static_cast<QueryT>((static_cast<GLfloat>(0xFFFFFFFF) * value - 1.0f) / 2.0f); + } + else + { + return gl::iround<QueryT>(value); + } + } + + // Clamp 64-bit int values when casting to int + if (nativeType == GL_INT_64_ANGLEX && queryType == GL_INT) + { + GLint64 minIntValue = static_cast<GLint64>(std::numeric_limits<GLint>::min()); + GLint64 maxIntValue = static_cast<GLint64>(std::numeric_limits<GLint>::max()); + GLint64 clampedValue = std::max(std::min(static_cast<GLint64>(value), maxIntValue), minIntValue); + return static_cast<QueryT>(clampedValue); + } + + return static_cast<QueryT>(value); +} + +template <typename QueryT, typename NativeT> +QueryT CastStateValue(GLenum pname, NativeT value) +{ + GLenum queryType = CastStateValueEnum<QueryT>::mEnumForType; + + switch (queryType) + { + case GL_INT: return CastStateValueToInt<QueryT, NativeT>(pname, value); + case GL_INT_64_ANGLEX: return CastStateValueToInt<QueryT, NativeT>(pname, value); + case GL_FLOAT: return static_cast<QueryT>(value); + case GL_BOOL: return (value == static_cast<NativeT>(0) ? GL_FALSE : GL_TRUE); + default: UNREACHABLE(); return 0; + } +} + +template <typename QueryT> +void CastStateValues(Context *context, GLenum nativeType, GLenum pname, + unsigned int numParams, QueryT *outParams) +{ + if (nativeType == GL_INT) + { + GLint *intParams = NULL; + intParams = new GLint[numParams]; + + context->getIntegerv(pname, intParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastStateValue<QueryT>(pname, intParams[i]); + } + + delete [] intParams; + } + else if (nativeType == GL_BOOL) + { + GLboolean *boolParams = NULL; + boolParams = new GLboolean[numParams]; + + context->getBooleanv(pname, boolParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = (boolParams[i] == GL_FALSE ? static_cast<QueryT>(0) : static_cast<QueryT>(1)); + } + + delete [] boolParams; + } + else if (nativeType == GL_FLOAT) + { + GLfloat *floatParams = NULL; + floatParams = new GLfloat[numParams]; + + context->getFloatv(pname, floatParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastStateValue<QueryT>(pname, floatParams[i]); + } + + delete [] floatParams; + } + else if (nativeType == GL_INT_64_ANGLEX) + { + GLint64 *int64Params = NULL; + int64Params = new GLint64[numParams]; + + context->getInteger64v(pname, int64Params); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastStateValue<QueryT>(pname, int64Params[i]); + } + + delete [] int64Params; + } + else UNREACHABLE(); +} + +// Explicit template instantiation (how we export template functions in different files) +// The calls below will make CastStateValues successfully link with the GL state query types +// The GL state query API types are: bool, int, uint, float, int64 + +template void CastStateValues<GLboolean>(Context *, GLenum, GLenum, unsigned int, GLboolean *); +template void CastStateValues<GLint>(Context *, GLenum, GLenum, unsigned int, GLint *); +template void CastStateValues<GLuint>(Context *, GLenum, GLenum, unsigned int, GLuint *); +template void CastStateValues<GLfloat>(Context *, GLenum, GLenum, unsigned int, GLfloat *); +template void CastStateValues<GLint64>(Context *, GLenum, GLenum, unsigned int, GLint64 *); + +} diff --git a/src/3rdparty/angle/src/libGLESv2/queryconversions.h b/src/3rdparty/angle/src/libGLESv2/queryconversions.h new file mode 100644 index 0000000000..da7047f730 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/queryconversions.h @@ -0,0 +1,17 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// queryconversions.h: Declaration of state query cast conversions + +namespace gl +{ + +// The GL state query API types are: bool, int, uint, float, int64 +template <typename QueryT> +void CastStateValues(Context *context, GLenum nativeType, GLenum pname, + unsigned int numParams, QueryT *outParams); + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/BufferImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/BufferImpl.h new file mode 100644 index 0000000000..bea689b956 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/BufferImpl.h @@ -0,0 +1,34 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BufferImpl.h: Defines the abstract rx::BufferImpl class. + +#ifndef LIBGLESV2_RENDERER_BUFFERIMPL_H_ +#define LIBGLESV2_RENDERER_BUFFERIMPL_H_ + +#include "common/angleutils.h" +#include "libGLESv2/Buffer.h" + +namespace rx +{ + +class BufferImpl +{ + public: + virtual ~BufferImpl() { } + + virtual void setData(const void* data, size_t size, GLenum usage) = 0; + virtual void *getData() = 0; + virtual void setSubData(const void* data, size_t size, size_t offset) = 0; + virtual void copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) = 0; + virtual GLvoid* map(size_t offset, size_t length, GLbitfield access) = 0; + virtual void unmap() = 0; + virtual void markTransformFeedbackUsage() = 0; +}; + +} + +#endif // LIBGLESV2_RENDERER_BUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/BufferStorage.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/BufferStorage.cpp deleted file mode 100644 index a49b7bab84..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/BufferStorage.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// BufferStorage.cpp Defines the abstract BufferStorage class. - -#include "libGLESv2/renderer/BufferStorage.h" - -namespace rx -{ - -unsigned int BufferStorage::mNextSerial = 1; - -BufferStorage::BufferStorage() -{ - updateSerial(); -} - -BufferStorage::~BufferStorage() -{ -} - -unsigned int BufferStorage::getSerial() const -{ - return mSerial; -} - -void BufferStorage::updateSerial() -{ - mSerial = mNextSerial++; -} - -void BufferStorage::markBufferUsage() -{ -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/BufferStorage.h b/src/3rdparty/angle/src/libGLESv2/renderer/BufferStorage.h deleted file mode 100644 index ace1a11bae..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/BufferStorage.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// BufferStorage.h Defines the abstract BufferStorage class. - -#ifndef LIBGLESV2_RENDERER_BUFFERSTORAGE_H_ -#define LIBGLESV2_RENDERER_BUFFERSTORAGE_H_ - -#include "common/angleutils.h" - -namespace rx -{ - -class BufferStorage -{ - public: - BufferStorage(); - virtual ~BufferStorage(); - - // The data returned is only guaranteed valid until next non-const method. - virtual void *getData() = 0; - virtual void setData(const void* data, unsigned int size, unsigned int offset) = 0; - virtual void clear() = 0; - virtual unsigned int getSize() const = 0; - virtual bool supportsDirectBinding() const = 0; - virtual void markBufferUsage(); - unsigned int getSerial() const; - - protected: - void updateSerial(); - - private: - DISALLOW_COPY_AND_ASSIGN(BufferStorage); - - unsigned int mSerial; - static unsigned int mNextSerial; -}; - -} - -#endif // LIBGLESV2_RENDERER_BUFFERSTORAGE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h index d7f2102a2e..d54e6becd3 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h @@ -17,27 +17,16 @@ namespace rx class FenceImpl { public: - FenceImpl() : mStatus(GL_FALSE), mCondition(GL_NONE) { }; + FenceImpl() { }; virtual ~FenceImpl() { }; - virtual GLboolean isFence() = 0; - virtual void setFence(GLenum condition) = 0; - virtual GLboolean testFence() = 0; - virtual void finishFence() = 0; - virtual void getFenceiv(GLenum pname, GLint *params) = 0; - - protected: - void setStatus(GLboolean status) { mStatus = status; } - GLboolean getStatus() const { return mStatus; } - - void setCondition(GLuint condition) { mCondition = condition; } - GLuint getCondition() const { return mCondition; } + virtual bool isSet() const = 0; + virtual void set() = 0; + virtual bool test(bool flushCommandBuffer) = 0; + virtual bool hasError() const = 0; private: DISALLOW_COPY_AND_ASSIGN(FenceImpl); - - GLboolean mStatus; - GLenum mCondition; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp index 57239ef74f..5963534e03 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp @@ -18,531 +18,12 @@ Image::Image() { mWidth = 0; mHeight = 0; + mDepth = 0; mInternalFormat = GL_NONE; mActualFormat = GL_NONE; -} - -void Image::loadAlphaDataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned char *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = static_cast<const unsigned char*>(input) + y * inputPitch; - dest = static_cast<unsigned char*>(output) + y * outputPitch; - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = 0; - dest[4 * x + 1] = 0; - dest[4 * x + 2] = 0; - dest[4 * x + 3] = source[x]; - } - } -} - -void Image::loadAlphaDataToNative(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned char *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = static_cast<const unsigned char*>(input) + y * inputPitch; - dest = static_cast<unsigned char*>(output) + y * outputPitch; - memcpy(dest, source, width); - } -} - -void Image::loadAlphaFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const float *source = NULL; - float *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = 0; - dest[4 * x + 1] = 0; - dest[4 * x + 2] = 0; - dest[4 * x + 3] = source[x]; - } - } -} - -void Image::loadAlphaHalfFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned short *source = NULL; - unsigned short *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch); - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = 0; - dest[4 * x + 1] = 0; - dest[4 * x + 2] = 0; - dest[4 * x + 3] = source[x]; - } - } -} - -void Image::loadLuminanceDataToNativeOrBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native) -{ - const unsigned char *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = static_cast<const unsigned char*>(input) + y * inputPitch; - dest = static_cast<unsigned char*>(output) + y * outputPitch; - - if (!native) // BGRA8 destination format - { - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = source[x]; - dest[4 * x + 1] = source[x]; - dest[4 * x + 2] = source[x]; - dest[4 * x + 3] = 0xFF; - } - } - else // L8 destination format - { - memcpy(dest, source, width); - } - } -} - -void Image::loadLuminanceFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const float *source = NULL; - float *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = source[x]; - dest[4 * x + 1] = source[x]; - dest[4 * x + 2] = source[x]; - dest[4 * x + 3] = 1.0f; - } - } -} - -void Image::loadLuminanceFloatDataToRGB(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const float *source = NULL; - float *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); - for (int x = 0; x < width; x++) - { - dest[3 * x + 0] = source[x]; - dest[3 * x + 1] = source[x]; - dest[3 * x + 2] = source[x]; - } - } -} - -void Image::loadLuminanceHalfFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned short *source = NULL; - unsigned short *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch); - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = source[x]; - dest[4 * x + 1] = source[x]; - dest[4 * x + 2] = source[x]; - dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1 - } - } -} - -void Image::loadLuminanceAlphaDataToNativeOrBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native) -{ - const unsigned char *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = static_cast<const unsigned char*>(input) + y * inputPitch; - dest = static_cast<unsigned char*>(output) + y * outputPitch; - - if (!native) // BGRA8 destination format - { - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = source[2*x+0]; - dest[4 * x + 1] = source[2*x+0]; - dest[4 * x + 2] = source[2*x+0]; - dest[4 * x + 3] = source[2*x+1]; - } - } - else - { - memcpy(dest, source, width * 2); - } - } -} - -void Image::loadLuminanceAlphaFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const float *source = NULL; - float *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = source[2*x+0]; - dest[4 * x + 1] = source[2*x+0]; - dest[4 * x + 2] = source[2*x+0]; - dest[4 * x + 3] = source[2*x+1]; - } - } -} - -void Image::loadLuminanceAlphaHalfFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned short *source = NULL; - unsigned short *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch); - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = source[2*x+0]; - dest[4 * x + 1] = source[2*x+0]; - dest[4 * x + 2] = source[2*x+0]; - dest[4 * x + 3] = source[2*x+1]; - } - } -} - -void Image::loadRGBUByteDataToBGRX(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned char *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = static_cast<const unsigned char*>(input) + y * inputPitch; - dest = static_cast<unsigned char*>(output) + y * outputPitch; - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = source[x * 3 + 2]; - dest[4 * x + 1] = source[x * 3 + 1]; - dest[4 * x + 2] = source[x * 3 + 0]; - dest[4 * x + 3] = 0xFF; - } - } -} - -void Image::loadRGBUByteDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned char *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = static_cast<const unsigned char*>(input) + y * inputPitch; - dest = static_cast<unsigned char*>(output) + y * outputPitch; - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = source[x * 3 + 0]; - dest[4 * x + 1] = source[x * 3 + 1]; - dest[4 * x + 2] = source[x * 3 + 2]; - dest[4 * x + 3] = 0xFF; - } - } -} - -void Image::loadRGB565DataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned short *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = static_cast<unsigned char*>(output) + y * outputPitch; - for (int x = 0; x < width; x++) - { - unsigned short rgba = source[x]; - dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2); - dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9); - dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); - dest[4 * x + 3] = 0xFF; - } - } -} - -void Image::loadRGB565DataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned short *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = static_cast<unsigned char*>(output) + y * outputPitch; - for (int x = 0; x < width; x++) - { - unsigned short rgba = source[x]; - dest[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); - dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9); - dest[4 * x + 2] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2); - dest[4 * x + 3] = 0xFF; - } - } -} - -void Image::loadRGBFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const float *source = NULL; - float *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = source[x * 3 + 0]; - dest[4 * x + 1] = source[x * 3 + 1]; - dest[4 * x + 2] = source[x * 3 + 2]; - dest[4 * x + 3] = 1.0f; - } - } -} - -void Image::loadRGBFloatDataToNative(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const float *source = NULL; - float *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); - memcpy(dest, source, width * 12); - } -} - -void Image::loadRGBHalfFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned short *source = NULL; - unsigned short *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch); - for (int x = 0; x < width; x++) - { - dest[4 * x + 0] = source[x * 3 + 0]; - dest[4 * x + 1] = source[x * 3 + 1]; - dest[4 * x + 2] = source[x * 3 + 2]; - dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1 - } - } -} - -void Image::loadRGBAUByteDataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned int *source = NULL; - unsigned int *dest = NULL; - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch); - - for (int x = 0; x < width; x++) - { - unsigned int rgba = source[x]; - dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); - } - } -} - -void Image::loadRGBAUByteDataToNative(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned int *source = NULL; - unsigned int *dest = NULL; - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch); - - memcpy(dest, source, width * 4); - } -} - -void Image::loadRGBA4444DataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned short *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = static_cast<unsigned char*>(output) + y * outputPitch; - for (int x = 0; x < width; x++) - { - unsigned short rgba = source[x]; - dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); - dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); - dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); - dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); - } - } -} - -void Image::loadRGBA4444DataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned short *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = static_cast<unsigned char*>(output) + y * outputPitch; - for (int x = 0; x < width; x++) - { - unsigned short rgba = source[x]; - dest[4 * x + 0] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); - dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); - dest[4 * x + 2] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); - dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); - } - } -} - -void Image::loadRGBA5551DataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned short *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = static_cast<unsigned char*>(output) + y * outputPitch; - for (int x = 0; x < width; x++) - { - unsigned short rgba = source[x]; - dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); - dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); - dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); - dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; - } - } -} - -void Image::loadRGBA5551DataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned short *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = static_cast<unsigned char*>(output) + y * outputPitch; - for (int x = 0; x < width; x++) - { - unsigned short rgba = source[x]; - dest[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); - dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); - dest[4 * x + 2] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); - dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; - } - } -} - -void Image::loadRGBAFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const float *source = NULL; - float *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch); - memcpy(dest, source, width * 16); - } -} - -void Image::loadRGBAHalfFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned char *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = static_cast<const unsigned char*>(input) + y * inputPitch; - dest = static_cast<unsigned char*>(output) + y * outputPitch; - memcpy(dest, source, width * 8); - } -} - -void Image::loadBGRADataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned char *source = NULL; - unsigned char *dest = NULL; - - for (int y = 0; y < height; y++) - { - source = static_cast<const unsigned char*>(input) + y * inputPitch; - dest = static_cast<unsigned char*>(output) + y * outputPitch; - memcpy(dest, source, width*4); - } + mTarget = GL_NONE; + mRenderable = false; + mDirty = false; } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Image.h b/src/3rdparty/angle/src/libGLESv2/renderer/Image.h index 454e83e21e..8fcffa4309 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Image.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/Image.h @@ -20,9 +20,8 @@ class Framebuffer; namespace rx { + class Renderer; -class TextureStorageInterface2D; -class TextureStorageInterfaceCube; class Image { @@ -32,93 +31,33 @@ class Image GLsizei getWidth() const { return mWidth; } GLsizei getHeight() const { return mHeight; } + GLsizei getDepth() const { return mDepth; } GLenum getInternalFormat() const { return mInternalFormat; } GLenum getActualFormat() const { return mActualFormat; } + GLenum getTarget() const { return mTarget; } + bool isRenderableFormat() const { return mRenderable; } void markDirty() {mDirty = true;} void markClean() {mDirty = false;} virtual bool isDirty() const = 0; - virtual void setManagedSurface(TextureStorageInterface2D *storage, int level) {}; - virtual void setManagedSurface(TextureStorageInterfaceCube *storage, int face, int level) {}; - virtual bool updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0; - virtual bool updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0; - - virtual bool redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease) = 0; + virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) = 0; - virtual bool isRenderableFormat() const = 0; - - virtual void loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLint unpackAlignment, const void *input) = 0; - virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + virtual void loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input) = 0; + virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, const void *input) = 0; - virtual void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; - - static void loadAlphaDataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadAlphaDataToNative(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadAlphaDataToBGRASSE2(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadAlphaFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadAlphaHalfFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadLuminanceDataToNativeOrBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native); - static void loadLuminanceFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadLuminanceFloatDataToRGB(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadLuminanceHalfFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadLuminanceAlphaDataToNativeOrBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native); - static void loadLuminanceAlphaFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadLuminanceAlphaHalfFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBUByteDataToBGRX(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBUByteDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGB565DataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGB565DataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBFloatDataToNative(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBHalfFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBAUByteDataToBGRASSE2(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBAUByteDataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBAUByteDataToNative(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBA4444DataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBA4444DataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBA5551DataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBA5551DataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBAFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadRGBAHalfFloatDataToRGBA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); - static void loadBGRADataToBGRA(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output); + virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; protected: GLsizei mWidth; GLsizei mHeight; - GLint mInternalFormat; + GLsizei mDepth; + GLenum mInternalFormat; GLenum mActualFormat; + bool mRenderable; + GLenum mTarget; bool mDirty; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/ImageSSE2.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/ImageSSE2.cpp deleted file mode 100644 index b2a90ca961..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/ImageSSE2.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// ImageSSE2.cpp: Implements SSE2-based functions of rx::Image class. It's -// in a separated file for GCC, which can enable SSE usage only per-file, -// not for code blocks that use SSE2 explicitly. - -#include "libGLESv2/Texture.h" -#include "libGLESv2/renderer/Image.h" - -namespace rx -{ - -void Image::loadRGBAUByteDataToBGRASSE2(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned int *source = NULL; - unsigned int *dest = NULL; - __m128i brMask = _mm_set1_epi32(0x00ff00ff); - - for (int y = 0; y < height; y++) - { - source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); - dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch); - int x = 0; - - // Make output writes aligned - for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++) - { - unsigned int rgba = source[x]; - dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); - } - - for (; x + 3 < width; x += 4) - { - __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x])); - // Mask out g and a, which don't change - __m128i gaComponents = _mm_andnot_si128(brMask, sourceData); - // Mask out b and r - __m128i brComponents = _mm_and_si128(sourceData, brMask); - // Swap b and r - __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1)); - __m128i result = _mm_or_si128(gaComponents, brSwapped); - _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result); - } - - // Perform leftover writes - for (; x < width; x++) - { - unsigned int rgba = source[x]; - dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); - } - } -} - -void Image::loadAlphaDataToBGRASSE2(GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) -{ - const unsigned char *source = NULL; - unsigned int *dest = NULL; - __m128i zeroWide = _mm_setzero_si128(); - - for (int y = 0; y < height; y++) - { - source = static_cast<const unsigned char*>(input) + y * inputPitch; - dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch); - - int x; - // Make output writes aligned - for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 0xF) != 0 && x < width); x++) - { - dest[x] = static_cast<unsigned int>(source[x]) << 24; - } - - for (; x + 7 < width; x += 8) - { - __m128i sourceData = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&source[x])); - // Interleave each byte to 16bit, make the lower byte to zero - sourceData = _mm_unpacklo_epi8(zeroWide, sourceData); - // Interleave each 16bit to 32bit, make the lower 16bit to zero - __m128i lo = _mm_unpacklo_epi16(zeroWide, sourceData); - __m128i hi = _mm_unpackhi_epi16(zeroWide, sourceData); - - _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), lo); - _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x + 4]), hi); - } - - // Handle the remainder - for (; x < width; x++) - { - dest[x] = static_cast<unsigned int>(source[x]) << 24; - } - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp index 51d7f0b653..e957d96270 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp @@ -9,8 +9,8 @@ // ranges of indices. #include "libGLESv2/renderer/IndexRangeCache.h" +#include "libGLESv2/formatutils.h" #include "common/debug.h" -#include "libGLESv2/utilities.h" #include <tuple> namespace rx @@ -31,7 +31,7 @@ void IndexRangeCache::invalidateRange(unsigned int offset, unsigned int size) while (i != mIndexRangeCache.end()) { unsigned int rangeStart = i->second.streamOffset; - unsigned int rangeEnd = i->second.streamOffset + (gl::ComputeTypeSize(i->first.type) * i->first.count); + unsigned int rangeEnd = i->second.streamOffset + (gl::GetTypeBytes(i->first.type) * i->first.count); if (invalidateEnd < rangeStart || invalidateStart > rangeEnd) { diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.h index 56834306f2..837a44acd3 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.h @@ -11,6 +11,7 @@ #define LIBGLESV2_RENDERER_INDEXRANGECACHE_H_ #include "common/angleutils.h" +#include <map> namespace rx { @@ -55,4 +56,4 @@ class IndexRangeCache } -#endif LIBGLESV2_RENDERER_INDEXRANGECACHE_H +#endif // LIBGLESV2_RENDERER_INDEXRANGECACHE_H diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/QueryImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/QueryImpl.h index a874047b0c..a6750a204b 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/QueryImpl.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/QueryImpl.h @@ -24,6 +24,7 @@ class QueryImpl virtual void end() = 0; virtual GLuint getResult() = 0; virtual GLboolean isResultAvailable() = 0; + virtual bool isStarted() const = 0; GLenum getType() const { return mType; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h b/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h index 80de39f4f7..44637ec7de 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h @@ -11,6 +11,7 @@ #define LIBGLESV2_RENDERER_RENDERTARGET_H_ #include "common/angleutils.h" +#include "libGLESv2/angletypes.h" namespace rx { @@ -21,6 +22,7 @@ class RenderTarget { mWidth = 0; mHeight = 0; + mDepth = 0; mInternalFormat = GL_NONE; mActualFormat = GL_NONE; mSamples = 0; @@ -28,21 +30,27 @@ class RenderTarget virtual ~RenderTarget() {}; - GLsizei getWidth() { return mWidth; } - GLsizei getHeight() { return mHeight; } - GLenum getInternalFormat() { return mInternalFormat; } - GLenum getActualFormat() { return mActualFormat; } - GLsizei getSamples() { return mSamples; } - + GLsizei getWidth() const { return mWidth; } + GLsizei getHeight() const { return mHeight; } + GLsizei getDepth() const { return mDepth; } + GLenum getInternalFormat() const { return mInternalFormat; } + GLenum getActualFormat() const { return mActualFormat; } + GLsizei getSamples() const { return mSamples; } + gl::Extents getExtents() const { return gl::Extents(mWidth, mHeight, mDepth); } + + virtual void invalidate(GLint x, GLint y, GLsizei width, GLsizei height) = 0; + struct Desc { GLsizei width; GLsizei height; + GLsizei depth; GLenum format; }; protected: GLsizei mWidth; GLsizei mHeight; + GLsizei mDepth; GLenum mInternalFormat; GLenum mActualFormat; GLsizei mSamples; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp index 5278113811..590004ac9b 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -11,212 +11,77 @@ #include "libGLESv2/main.h" #include "libGLESv2/Program.h" #include "libGLESv2/renderer/Renderer.h" -#if defined(ANGLE_ENABLE_D3D9) -# include "libGLESv2/renderer/d3d9/Renderer9.h" -#endif -#if defined(ANGLE_ENABLE_D3D11) -# include "libGLESv2/renderer/d3d11/Renderer11.h" -#endif -#include "libGLESv2/utilities.h" +#include "common/utilities.h" #include "third_party/trace_event/trace_event.h" +#include "libGLESv2/Shader.h" -#ifndef D3DERR_OUTOFVIDEOMEMORY -#define D3DERR_OUTOFVIDEOMEMORY MAKE_HRESULT(1, 0x876, 380) -#endif - -#if defined(__MINGW32__) || defined(ANGLE_OS_WINPHONE) - -#ifndef D3DCOMPILER_DLL - -// Add define + typedefs for older MinGW-w64 headers (pre 5783) - -#define D3DCOMPILER_DLL L"d3dcompiler_43.dll" - -HRESULT WINAPI D3DCompile(const void *data, SIZE_T data_size, const char *filename, - const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, - const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages); -typedef HRESULT (WINAPI *pD3DCompile)(const void *data, SIZE_T data_size, const char *filename, - const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, - const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages); - -#endif // D3DCOMPILER_DLL +#if defined (ANGLE_ENABLE_D3D9) +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#endif // ANGLE_ENABLE_D3D9 -#endif // __MINGW32__ || ANGLE_OS_WINPHONE +#if defined (ANGLE_ENABLE_D3D11) +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#endif // ANGLE_ENABLE_D3D11 -#ifndef QT_D3DCOMPILER_DLL -#define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL +#if !defined(ANGLE_DEFAULT_D3D11) +// Enables use of the Direct3D 11 API for a default display, when available +#define ANGLE_DEFAULT_D3D11 0 #endif namespace rx { -Renderer::Renderer(egl::Display *display) : mDisplay(display) +Renderer::Renderer(egl::Display *display) + : mDisplay(display), + mCapsInitialized(false), + mCurrentClientVersion(2) { - mD3dCompilerModule = NULL; - mD3DCompileFunc = NULL; } Renderer::~Renderer() { - if (mD3dCompilerModule) - { - FreeLibrary(mD3dCompilerModule); - mD3dCompilerModule = NULL; - } + gl::Shader::releaseCompiler(); } -bool Renderer::initializeCompiler() +const gl::Caps &Renderer::getRendererCaps() const { - TRACE_EVENT0("gpu", "initializeCompiler"); -#if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES) - // Find a D3DCompiler module that had already been loaded based on a predefined list of versions. - static TCHAR* d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES; - - for (size_t i = 0; i < ArraySize(d3dCompilerNames); ++i) + if (!mCapsInitialized) { - if (GetModuleHandleEx(0, d3dCompilerNames[i], &mD3dCompilerModule)) - { - break; - } + generateCaps(&mCaps, &mTextureCaps, &mExtensions); + mCapsInitialized = true; } -#endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES - - // Load the compiler DLL specified by the environment, or default to QT_D3DCOMPILER_DLL -#if !defined(ANGLE_OS_WINRT) - const wchar_t *defaultCompiler = _wgetenv(L"QT_D3DCOMPILER_DLL"); - if (!defaultCompiler) - defaultCompiler = QT_D3DCOMPILER_DLL; -#else // !ANGLE_OS_WINRT -# ifdef _DEBUG - const wchar_t *defaultCompiler = L"d3dcompiler_qtd.dll"; -# else - const wchar_t *defaultCompiler = L"d3dcompiler_qt.dll"; -# endif -#endif // ANGLE_OS_WINRT - - const wchar_t *compilerDlls[] = { - defaultCompiler, - L"d3dcompiler_47.dll", - L"d3dcompiler_46.dll", - L"d3dcompiler_45.dll", - L"d3dcompiler_44.dll", - L"d3dcompiler_43.dll", - 0 - }; - // Load the first available known compiler DLL - for (int i = 0; compilerDlls[i]; ++i) - { - // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with. - mD3dCompilerModule = LoadLibrary(compilerDlls[i]); - if (mD3dCompilerModule) - break; - } - - if (!mD3dCompilerModule) - { - ERR("No D3D compiler module found - aborting!\n"); - return false; - } - - mD3DCompileFunc = reinterpret_cast<pCompileFunc>(GetProcAddress(mD3dCompilerModule, "D3DCompile")); - ASSERT(mD3DCompileFunc); - - return mD3DCompileFunc != NULL; + return mCaps; } -// Compiles HLSL code into executable binaries -ShaderBlob *Renderer::compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile, UINT optimizationFlags, bool alternateFlags) +const gl::TextureCapsMap &Renderer::getRendererTextureCaps() const { - if (!hlsl) + if (!mCapsInitialized) { - return NULL; + generateCaps(&mCaps, &mTextureCaps, &mExtensions); + mCapsInitialized = true; } - HRESULT result = S_OK; - UINT flags = 0; - std::string sourceText; - if (gl::perfActive()) - { - flags |= D3DCOMPILE_DEBUG; - -#ifdef NDEBUG - flags |= optimizationFlags; -#else - flags |= D3DCOMPILE_SKIP_OPTIMIZATION; -#endif + return mTextureCaps; +} - std::string sourcePath = getTempPath(); - sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl); - writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); - } - else +const gl::Extensions &Renderer::getRendererExtensions() const +{ + if (!mCapsInitialized) { - flags |= optimizationFlags; - sourceText = hlsl; + generateCaps(&mCaps, &mTextureCaps, &mExtensions); + mCapsInitialized = true; } - // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. - // Try the default flags first and if compilation fails, try some alternatives. - const static UINT extraFlags[] = - { - 0, - D3DCOMPILE_AVOID_FLOW_CONTROL, - D3DCOMPILE_PREFER_FLOW_CONTROL - }; - - const static char * const extraFlagNames[] = - { - "default", - "avoid flow control", - "prefer flow control" - }; - - int attempts = alternateFlags ? ArraySize(extraFlags) : 1; - pD3DCompile compileFunc = reinterpret_cast<pD3DCompile>(mD3DCompileFunc); - for (int i = 0; i < attempts; ++i) - { - ID3DBlob *errorMessage = NULL; - ID3DBlob *binary = NULL; - - result = compileFunc(hlsl, strlen(hlsl), gl::g_fakepath, NULL, NULL, - "main", profile, flags | extraFlags[i], 0, &binary, &errorMessage); - if (errorMessage) - { - const char *message = (const char*)errorMessage->GetBufferPointer(); - - infoLog.appendSanitized(message); - TRACE("\n%s", hlsl); - TRACE("\n%s", message); - - errorMessage->Release(); - errorMessage = NULL; - } - - if (SUCCEEDED(result)) - { - return (ShaderBlob*)binary; - } - else - { - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) - { - return gl::error(GL_OUT_OF_MEMORY, (ShaderBlob*) NULL); - } + return mExtensions; +} - infoLog.append("Warning: D3D shader compilation failed with "); - infoLog.append(extraFlagNames[i]); - infoLog.append(" flags."); - if (i + 1 < attempts) - { - infoLog.append(" Retrying with "); - infoLog.append(extraFlagNames[i + 1]); - infoLog.append(".\n"); - } - } - } +typedef Renderer *(*CreateRendererFunction)(egl::Display*, EGLNativeDisplayType, EGLint); - return NULL; +template <typename RendererType> +Renderer *CreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, EGLint requestedDisplayType) +{ + return new RendererType(display, nativeDisplay, requestedDisplayType); } } @@ -224,56 +89,64 @@ ShaderBlob *Renderer::compileToBinary(gl::InfoLog &infoLog, const char *hlsl, co extern "C" { -rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType displayId) +rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, EGLint requestedDisplayType) { - rx::Renderer *renderer = NULL; - EGLint status = EGL_BAD_ALLOC; - -#if defined(ANGLE_OS_WINRT) - if (displayId == EGL_DEFAULT_DISPLAY) - displayId = EGL_D3D11_ONLY_DISPLAY_ANGLE; -#endif - -#if defined(ANGLE_ENABLE_D3D11) - if (displayId == EGL_DEFAULT_DISPLAY || - displayId == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || - displayId == EGL_D3D11_ONLY_DISPLAY_ANGLE) - { - renderer = new rx::Renderer11(display); + std::vector<rx::CreateRendererFunction> rendererCreationFunctions; - if (renderer) +# if defined(ANGLE_ENABLE_D3D11) + if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || + nativeDisplay == EGL_D3D11_ONLY_DISPLAY_ANGLE || + requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE || + requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE) { - status = renderer->initialize(); + rendererCreationFunctions.push_back(rx::CreateRenderer<rx::Renderer11>); } +# endif - if (status == EGL_SUCCESS) +# if defined(ANGLE_ENABLE_D3D9) + if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || + requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE) { - return renderer; + rendererCreationFunctions.push_back(rx::CreateRenderer<rx::Renderer9>); } - else if (displayId == EGL_D3D11_ONLY_DISPLAY_ANGLE) - { - return NULL; - } - - // Failed to create a D3D11 renderer, try creating a D3D9 renderer - delete renderer; - } -#endif // ANGLE_ENABLE_D3D11 +# endif -#if defined(ANGLE_ENABLE_D3D9) - bool softwareDevice = (displayId == EGL_SOFTWARE_DISPLAY_ANGLE); - renderer = new rx::Renderer9(display, displayId, softwareDevice); - - if (renderer) + if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE && + nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE && + requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE) { - status = renderer->initialize(); + // The default display is requested, try the D3D9 and D3D11 renderers, order them using + // the definition of ANGLE_DEFAULT_D3D11 +# if ANGLE_DEFAULT_D3D11 +# if defined(ANGLE_ENABLE_D3D11) + rendererCreationFunctions.push_back(rx::CreateRenderer<rx::Renderer11>); +# endif +# if defined(ANGLE_ENABLE_D3D9) + rendererCreationFunctions.push_back(rx::CreateRenderer<rx::Renderer9>); +# endif +# else +# if defined(ANGLE_ENABLE_D3D9) + rendererCreationFunctions.push_back(rx::CreateRenderer<rx::Renderer9>); +# endif +# if defined(ANGLE_ENABLE_D3D11) + rendererCreationFunctions.push_back(rx::CreateRenderer<rx::Renderer11>); +# endif +# endif } - if (status == EGL_SUCCESS) + for (size_t i = 0; i < rendererCreationFunctions.size(); i++) { - return renderer; + rx::Renderer *renderer = rendererCreationFunctions[i](display, nativeDisplay, requestedDisplayType); + if (renderer->initialize() == EGL_SUCCESS) + { + return renderer; + } + else + { + // Failed to create the renderer, try the next + SafeDelete(renderer); + } } -#endif // ANGLE_ENABLE_D3D9 return NULL; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h index 79578b2458..f1e0fd2d99 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h @@ -1,6 +1,5 @@ -#include "../precompiled.h" // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -13,24 +12,15 @@ #include "libGLESv2/Uniform.h" #include "libGLESv2/angletypes.h" +#include "libGLESv2/Caps.h" #if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) -#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 +#include <d3dcompiler.h> +// WARNING: D3DCOMPILE_OPTIMIZATION_LEVEL3 may lead to a DX9 shader compiler hang. +// It should only be used selectively to work around specific bugs. +#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL1 #endif -const int versionWindowsVista = MAKEWORD(0x00, 0x06); -const int versionWindows7 = MAKEWORD(0x01, 0x06); - -// Return the version of the operating system in a format suitable for ordering -// comparison. -inline int getComparableOSVersion() -{ - DWORD version = GetVersion(); - int majorVersion = LOBYTE(LOWORD(version)); - int minorVersion = HIBYTE(LOWORD(version)); - return MAKEWORD(minorVersion, majorVersion); -} - namespace egl { class Display; @@ -40,31 +30,38 @@ namespace gl { class InfoLog; class ProgramBinary; -class VertexAttribute; +struct LinkedVarying; +struct VertexAttribute; class Buffer; class Texture; class Framebuffer; +struct VertexAttribCurrentValueData; } namespace rx { class TextureStorageInterface2D; class TextureStorageInterfaceCube; +class TextureStorageInterface3D; +class TextureStorageInterface2DArray; class VertexBuffer; class IndexBuffer; class QueryImpl; class FenceImpl; +class BufferImpl; +class VertexArrayImpl; class BufferStorage; -class Blit; struct TranslatedIndexData; class ShaderExecutable; class SwapChain; class RenderTarget; class Image; class TextureStorage; - -typedef void * ShaderBlob; -typedef void (*pCompileFunc)(); +class UniformStorage; +class Texture2DImpl; +class TextureCubeImpl; +class Texture3DImpl; +class Texture2DArrayImpl; struct ConfigDesc { @@ -72,6 +69,7 @@ struct ConfigDesc GLenum depthStencilFormat; GLint multiSample; bool fastConfig; + bool es3Capable; }; struct dx_VertexConstants @@ -94,12 +92,6 @@ enum ShaderType SHADER_GEOMETRY }; -enum D3DWorkaroundType -{ - ANGLE_D3D_WORKAROUND_NONE, - ANGLE_D3D_WORKAROUND_SM3_OPTIMIZER -}; - class Renderer { public: @@ -116,11 +108,14 @@ class Renderer virtual SwapChain *createSwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0; + virtual void generateSwizzle(gl::Texture *texture) = 0; virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler) = 0; virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture) = 0; + virtual bool setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]) = 0; + virtual void setRasterizerState(const gl::RasterizerState &rasterState) = 0; - virtual void setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::Color &blendColor, + virtual void setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, unsigned int sampleMask) = 0; virtual void setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, int stencilBackRef, bool frontFaceCCW) = 0; @@ -130,14 +125,18 @@ class Renderer bool ignoreViewport) = 0; virtual bool applyRenderTarget(gl::Framebuffer *frameBuffer) = 0; - virtual void applyShaders(gl::ProgramBinary *programBinary) = 0; - virtual void applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray) = 0; + virtual void applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive) = 0; + virtual void applyUniforms(const gl::ProgramBinary &programBinary) = 0; virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount) = 0; - virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances) = 0; + virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], + GLint first, GLsizei count, GLsizei instances) = 0; virtual GLenum applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0; + virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) = 0; - virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances) = 0; - virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0; + virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) = 0; + virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0; virtual void clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) = 0; @@ -149,20 +148,15 @@ class Renderer virtual bool testDeviceLost(bool notify) = 0; virtual bool testDeviceResettable() = 0; - // Renderer capabilities + // Renderer capabilities (virtual because it is used by egl::Display, do not override) + virtual const gl::Caps &getRendererCaps() const; + virtual const gl::TextureCapsMap &getRendererTextureCaps() const; + virtual const gl::Extensions &getRendererExtensions() const; + virtual DWORD getAdapterVendor() const = 0; virtual std::string getRendererDescription() const = 0; virtual GUID getAdapterIdentifier() const = 0; - virtual bool getBGRATextureSupport() const = 0; - virtual bool getDXT1TextureSupport() = 0; - virtual bool getDXT3TextureSupport() = 0; - virtual bool getDXT5TextureSupport() = 0; - virtual bool getEventQuerySupport() = 0; - virtual bool getFloat32TextureSupport(bool *filtering, bool *renderable) = 0; - virtual bool getFloat16TextureSupport(bool *filtering, bool *renderable) = 0; - virtual bool getLuminanceTextureSupport() = 0; - virtual bool getLuminanceAlphaTextureSupport() = 0; bool getVertexTextureSupport() const { return getMaxVertexTextureImageUnits() > 0; } virtual unsigned int getMaxVertexTextureImageUnits() const = 0; virtual unsigned int getMaxCombinedTextureImageUnits() const = 0; @@ -171,80 +165,117 @@ class Renderer virtual unsigned int getMaxVertexUniformVectors() const = 0; virtual unsigned int getMaxFragmentUniformVectors() const = 0; virtual unsigned int getMaxVaryingVectors() const = 0; - virtual bool getNonPower2TextureSupport() const = 0; - virtual bool getDepthTextureSupport() const = 0; - virtual bool getOcclusionQuerySupport() const = 0; - virtual bool getInstancingSupport() const = 0; - virtual bool getTextureFilterAnisotropySupport() const = 0; - virtual float getTextureMaxAnisotropy() const = 0; + virtual unsigned int getMaxVertexShaderUniformBuffers() const = 0; + virtual unsigned int getMaxFragmentShaderUniformBuffers() const = 0; + virtual unsigned int getReservedVertexUniformBuffers() const = 0; + virtual unsigned int getReservedFragmentUniformBuffers() const = 0; + virtual unsigned int getMaxTransformFeedbackBuffers() const = 0; + virtual unsigned int getMaxTransformFeedbackSeparateComponents() const = 0; + virtual unsigned int getMaxTransformFeedbackInterleavedComponents() const = 0; + virtual unsigned int getMaxUniformBufferSize() const = 0; virtual bool getShareHandleSupport() const = 0; - virtual bool getDerivativeInstructionSupport() const = 0; virtual bool getPostSubBufferSupport() const = 0; + virtual int getMaxRecommendedElementsIndices() const = 0; + virtual int getMaxRecommendedElementsVertices() const = 0; + virtual bool getSRGBTextureSupport() const = 0; virtual int getMajorShaderModel() const = 0; - virtual float getMaxPointSize() const = 0; - virtual int getMaxViewportDimension() const = 0; - virtual int getMaxTextureWidth() const = 0; - virtual int getMaxTextureHeight() const = 0; - virtual bool get32BitIndexSupport() const = 0; virtual int getMinSwapInterval() const = 0; virtual int getMaxSwapInterval() const = 0; virtual GLsizei getMaxSupportedSamples() const = 0; - - virtual unsigned int getMaxRenderTargets() const = 0; + virtual GLsizei getMaxSupportedFormatSamples(GLenum internalFormat) const = 0; + virtual GLsizei getNumSampleCounts(GLenum internalFormat) const = 0; + virtual void getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const = 0; // Pixel operations virtual bool copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source) = 0; virtual bool copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source) = 0; + virtual bool copyToRenderTarget(TextureStorageInterface3D *dest, TextureStorageInterface3D *source) = 0; + virtual bool copyToRenderTarget(TextureStorageInterface2DArray *dest, TextureStorageInterface2DArray *source) = 0; virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level) = 0; virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level) = 0; + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface3D *storage, GLint level) = 0; + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level) = 0; virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - bool blitRenderTarget, bool blitDepthStencil) = 0; - virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, - GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels) = 0; + const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) = 0; + virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void* pixels) = 0; // RenderTarget creation virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth) = 0; - virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth) = 0; + virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples) = 0; // Shader operations - virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type) = 0; - virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, D3DWorkaroundType workaround) = 0; + virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers) = 0; + virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround) = 0; + virtual UniformStorage *createUniformStorage(size_t storageSize) = 0; // Image operations virtual Image *createImage() = 0; virtual void generateMipmap(Image *dest, Image *source) = 0; virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain) = 0; - virtual TextureStorage *createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height) = 0; - virtual TextureStorage *createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size) = 0; + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) = 0; + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) = 0; + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; + + // Texture creation + virtual Texture2DImpl *createTexture2D() = 0; + virtual TextureCubeImpl *createTextureCube() = 0; + virtual Texture3DImpl *createTexture3D() = 0; + virtual Texture2DArrayImpl *createTexture2DArray() = 0; // Buffer creation + virtual BufferImpl *createBuffer() = 0; virtual VertexBuffer *createVertexBuffer() = 0; virtual IndexBuffer *createIndexBuffer() = 0; - virtual BufferStorage *createBufferStorage() = 0; + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray() = 0; // Query and Fence creation virtual QueryImpl *createQuery(GLenum type) = 0; virtual FenceImpl *createFence() = 0; + // Current GLES client version + void setCurrentClientVersion(int clientVersion) { mCurrentClientVersion = clientVersion; } + int getCurrentClientVersion() const { return mCurrentClientVersion; } + + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const = 0; + virtual bool fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) = 0; + virtual bool getLUID(LUID *adapterLuid) const = 0; + virtual GLenum getNativeTextureFormat(GLenum internalFormat) const = 0; + virtual rx::VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const = 0; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const = 0; protected: - bool initializeCompiler(); - ShaderBlob *compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile, UINT optimizationFlags, bool alternateFlags); - egl::Display *mDisplay; private: DISALLOW_COPY_AND_ASSIGN(Renderer); - HMODULE mD3dCompilerModule; - pCompileFunc mD3DCompileFunc; + virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps, gl::Extensions *outExtensions) const = 0; + + mutable bool mCapsInitialized; + mutable gl::Caps mCaps; + mutable gl::TextureCapsMap mTextureCaps; + mutable gl::Extensions mExtensions; + + int mCurrentClientVersion; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h b/src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h index 293e340845..054d00a712 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h @@ -11,6 +11,7 @@ #define LIBGLESV2_RENDERER_SHADEREXECUTABLE_H_ #include "common/angleutils.h" +#include "common/debug.h" namespace rx { @@ -18,32 +19,44 @@ namespace rx class ShaderExecutable { public: - ShaderExecutable(const void *function, size_t length) : mLength(length) + ShaderExecutable(const void *function, size_t length) + : mFunctionBuffer(length) { - mFunction = new char[length]; - memcpy(mFunction, function, length); - } - - virtual ~ShaderExecutable() - { - delete[] mFunction; + memcpy(mFunctionBuffer.data(), function, length); } - void *getFunction() const + virtual ~ShaderExecutable() {} + + const uint8_t *getFunction() const { - return mFunction; + return mFunctionBuffer.data(); } size_t getLength() const { - return mLength; + return mFunctionBuffer.size(); } private: DISALLOW_COPY_AND_ASSIGN(ShaderExecutable); - void *mFunction; - const size_t mLength; + std::vector<uint8_t> mFunctionBuffer; +}; + +class UniformStorage +{ + public: + UniformStorage(size_t initialSize) + : mSize(initialSize) + { + } + + virtual ~UniformStorage() {} + + size_t size() const { return mSize; } + + private: + size_t mSize; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h b/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h index 8231fbcb25..77546f81e7 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h @@ -1,4 +1,3 @@ -#include "../precompiled.h" // // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -11,6 +10,7 @@ #ifndef LIBGLESV2_RENDERER_SWAPCHAIN_H_ #define LIBGLESV2_RENDERER_SWAPCHAIN_H_ +#include <EGL/eglplatform.h> #include "common/angleutils.h" #if !defined(ANGLE_FORCE_VSYNC_OFF) @@ -20,6 +20,14 @@ namespace rx { +enum SwapFlags +{ + SWAP_NORMAL = 0, + SWAP_ROTATE_90 = 1, + SWAP_ROTATE_270 = 2, + SWAP_ROTATE_180 = SWAP_ROTATE_90|SWAP_ROTATE_270, +}; + class SwapChain { public: @@ -32,13 +40,13 @@ class SwapChain virtual EGLint resize(EGLint backbufferWidth, EGLint backbufferSize) = 0; virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval) = 0; - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height) = 0; + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint flags) = 0; virtual void recreate() = 0; virtual HANDLE getShareHandle() {return mShareHandle;}; protected: - const EGLNativeWindowType mWindow; // Window that the surface is created for. + const EGLNativeWindowType mWindow; // Window that the surface is created for. const GLenum mBackBufferFormat; const GLenum mDepthBufferFormat; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/TextureImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/TextureImpl.h new file mode 100644 index 0000000000..35c9166023 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/TextureImpl.h @@ -0,0 +1,166 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureImpl.h: Defines the abstract rx::TextureImpl classes. + +#ifndef LIBGLESV2_RENDERER_TEXTUREIMPL_H_ +#define LIBGLESV2_RENDERER_TEXTUREIMPL_H_ + +#include "common/angleutils.h" + +namespace egl +{ +class Surface; +} + +namespace gl +{ +class Framebuffer; +struct PixelUnpackState; +struct SamplerState; +} + +namespace rx +{ + +class Image; +class RenderTarget; +class Renderer; +class TextureStorageInterface; + +class Texture2DImpl +{ + public: + virtual ~Texture2DImpl() {} + + // TODO: If this methods could go away that would be ideal; + // TextureStorage should only be necessary for the D3D backend, and as such + // higher level code should not rely on it. + virtual TextureStorageInterface *getNativeTexture() = 0; + + virtual Image *getImage(int level) const = 0; + + virtual void setUsage(GLenum usage) = 0; + virtual bool hasDirtyImages() const = 0; + virtual void resetDirty() = 0; + + virtual bool isSamplerComplete(const gl::SamplerState &samplerState) const = 0; + virtual void bindTexImage(egl::Surface *surface) = 0; + virtual void releaseTexImage() = 0; + + virtual void setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) = 0; + virtual void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) = 0; + virtual void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; + virtual void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) = 0; + virtual void generateMipmaps() = 0; + + virtual unsigned int getRenderTargetSerial(GLint level) = 0; + + virtual RenderTarget *getRenderTarget(GLint level) = 0; + virtual RenderTarget *getDepthSencil(GLint level) = 0; + + virtual void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height) = 0; +}; + +class TextureCubeImpl +{ + public: + virtual ~TextureCubeImpl() {} + + virtual TextureStorageInterface *getNativeTexture() = 0; + + virtual Image *getImage(GLenum target, int level) const = 0; + + virtual void setUsage(GLenum usage) = 0; + virtual bool hasDirtyImages() const = 0; + virtual void resetDirty() = 0; + + virtual bool isSamplerComplete(const gl::SamplerState &samplerState) const = 0; + virtual bool isCubeComplete() const = 0; + + virtual void setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) = 0; + virtual void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) = 0; + virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; + virtual void storage(GLsizei levels, GLenum internalformat, GLsizei size) = 0; + virtual void generateMipmaps() = 0; + + virtual unsigned int getRenderTargetSerial(GLenum target, GLint level) = 0; + + virtual RenderTarget *getRenderTarget(GLenum target, GLint level) = 0; + virtual RenderTarget *getDepthStencil(GLenum target, GLint level) = 0; +}; + +class Texture3DImpl +{ + public: + virtual ~Texture3DImpl() {} + + virtual TextureStorageInterface *getNativeTexture() = 0; + + virtual Image *getImage(int level) const = 0; + + virtual void setUsage(GLenum usage) = 0; + virtual bool hasDirtyImages() const = 0; + virtual void resetDirty() = 0; + + virtual bool isSamplerComplete(const gl::SamplerState &samplerState) const = 0; + virtual bool isMipmapComplete() const = 0; + + virtual void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) = 0; + virtual void subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) = 0; + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; + virtual void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) = 0; + virtual void generateMipmaps() = 0; + + virtual unsigned int getRenderTargetSerial(GLint level, GLint layer) = 0; + + virtual RenderTarget *getRenderTarget(GLint level) = 0; + virtual RenderTarget *getRenderTarget(GLint level, GLint layer) = 0; + virtual RenderTarget *getDepthStencil(GLint level, GLint layer) = 0; +}; + +class Texture2DArrayImpl +{ + public: + virtual ~Texture2DArrayImpl() {} + + virtual TextureStorageInterface *getNativeTexture() = 0; + + virtual Image *getImage(int level, int layer) const = 0; + virtual GLsizei getLayerCount(int level) const = 0; + + virtual void setUsage(GLenum usage) = 0; + virtual bool hasDirtyImages() const = 0; + virtual void resetDirty() = 0; + + virtual bool isSamplerComplete(const gl::SamplerState &samplerState) const = 0; + virtual bool isMipmapComplete() const = 0; + + virtual void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) = 0; + virtual void subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) = 0; + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; + virtual void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) = 0; + virtual void generateMipmaps() = 0; + + virtual unsigned int getRenderTargetSerial(GLint level, GLint layer) = 0; + + virtual RenderTarget *getRenderTarget(GLint level, GLint layer) = 0; + virtual RenderTarget *getDepthStencil(GLint level, GLint layer) = 0; +}; + +} + +#endif // LIBGLESV2_RENDERER_TEXTUREIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/TextureStorage.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/TextureStorage.cpp deleted file mode 100644 index 00b316f1cc..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/TextureStorage.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// TextureStorage.cpp: Implements the abstract rx::TextureStorageInterface class and its concrete derived -// classes TextureStorageInterface2D and TextureStorageInterfaceCube, which act as the interface to the -// GPU-side texture. - -#include "libGLESv2/renderer/TextureStorage.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/Texture.h" - -#include "common/debug.h" - -namespace rx -{ -unsigned int TextureStorageInterface::mCurrentTextureSerial = 1; - -TextureStorageInterface::TextureStorageInterface() - : mTextureSerial(issueTextureSerial()), - mInstance(NULL) -{ -} - -TextureStorageInterface::~TextureStorageInterface() -{ - delete mInstance; -} - -bool TextureStorageInterface::isRenderTarget() const -{ - return mInstance->isRenderTarget(); -} - - -bool TextureStorageInterface::isManaged() const -{ - return mInstance->isManaged(); -} - -unsigned int TextureStorageInterface::getTextureSerial() const -{ - return mTextureSerial; -} - -unsigned int TextureStorageInterface::issueTextureSerial() -{ - return mCurrentTextureSerial++; -} - -int TextureStorageInterface::getLodOffset() const -{ - return mInstance->getLodOffset(); -} - - -int TextureStorageInterface::levelCount() -{ - return mInstance->levelCount(); -} - -TextureStorageInterface2D::TextureStorageInterface2D(Renderer *renderer, SwapChain *swapchain) - : mRenderTargetSerial(gl::RenderbufferStorage::issueSerial()) -{ - mInstance = renderer->createTextureStorage2D(swapchain); -} - -TextureStorageInterface2D::TextureStorageInterface2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height) - : mRenderTargetSerial(gl::RenderbufferStorage::issueSerial()) -{ - mInstance = renderer->createTextureStorage2D(levels, internalformat, usage, forceRenderable, width, height); -} - -TextureStorageInterface2D::~TextureStorageInterface2D() -{ -} - -RenderTarget *TextureStorageInterface2D::getRenderTarget() const -{ - return mInstance->getRenderTarget(); -} - -void TextureStorageInterface2D::generateMipmap(int level) -{ - mInstance->generateMipmap(level); -} - -unsigned int TextureStorageInterface2D::getRenderTargetSerial(GLenum target) const -{ - return mRenderTargetSerial; -} - -TextureStorageInterfaceCube::TextureStorageInterfaceCube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size) - : mFirstRenderTargetSerial(gl::RenderbufferStorage::issueCubeSerials()) -{ - mInstance = renderer->createTextureStorageCube(levels, internalformat, usage, forceRenderable, size); -} - -TextureStorageInterfaceCube::~TextureStorageInterfaceCube() -{ -} - -RenderTarget *TextureStorageInterfaceCube::getRenderTarget(GLenum faceTarget) const -{ - return mInstance->getRenderTarget(faceTarget); -} - -void TextureStorageInterfaceCube::generateMipmap(int face, int level) -{ - mInstance->generateMipmap(face, level); -} - -unsigned int TextureStorageInterfaceCube::getRenderTargetSerial(GLenum target) const -{ - return mFirstRenderTargetSerial + gl::TextureCubeMap::faceIndex(target); -} - -}
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/TextureStorage.h b/src/3rdparty/angle/src/libGLESv2/renderer/TextureStorage.h deleted file mode 100644 index edddb75f3f..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/TextureStorage.h +++ /dev/null @@ -1,110 +0,0 @@ -// -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// TextureStorage.h: Defines the abstract rx::TextureStorageInterface class and its concrete derived -// classes TextureStorageInterface2D and TextureStorageInterfaceCube, which act as the interface to the -// GPU-side texture. - -#ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ -#define LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ - -#include "common/debug.h" - -namespace rx -{ -class Renderer; -class SwapChain; -class RenderTarget; -class Blit; - -class TextureStorage -{ - public: - TextureStorage() {}; - virtual ~TextureStorage() {}; - - virtual int getLodOffset() const = 0; - virtual bool isRenderTarget() const = 0; - virtual bool isManaged() const = 0; - virtual int levelCount() = 0; - - virtual RenderTarget *getRenderTarget() = 0; - virtual RenderTarget *getRenderTarget(GLenum faceTarget) = 0; - virtual void generateMipmap(int level) = 0; - virtual void generateMipmap(int face, int level) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage); - -}; - -class TextureStorageInterface -{ - public: - TextureStorageInterface(); - virtual ~TextureStorageInterface(); - - TextureStorage *getStorageInstance() { return mInstance; } - - unsigned int getTextureSerial() const; - virtual unsigned int getRenderTargetSerial(GLenum target) const = 0; - - virtual int getLodOffset() const; - virtual bool isRenderTarget() const; - virtual bool isManaged() const; - virtual int levelCount(); - - protected: - TextureStorage *mInstance; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorageInterface); - - const unsigned int mTextureSerial; - static unsigned int issueTextureSerial(); - - static unsigned int mCurrentTextureSerial; -}; - -class TextureStorageInterface2D : public TextureStorageInterface -{ - public: - TextureStorageInterface2D(Renderer *renderer, SwapChain *swapchain); - TextureStorageInterface2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height); - virtual ~TextureStorageInterface2D(); - - void generateMipmap(int level); - RenderTarget *getRenderTarget() const; - - virtual unsigned int getRenderTargetSerial(GLenum target) const; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorageInterface2D); - - const unsigned int mRenderTargetSerial; -}; - -class TextureStorageInterfaceCube : public TextureStorageInterface -{ - public: - TextureStorageInterfaceCube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size); - virtual ~TextureStorageInterfaceCube(); - - void generateMipmap(int face, int level); - RenderTarget *getRenderTarget(GLenum faceTarget) const; - - virtual unsigned int getRenderTargetSerial(GLenum target) const; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorageInterfaceCube); - - const unsigned int mFirstRenderTargetSerial; -}; - -} - -#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ - diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/VertexArrayImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/VertexArrayImpl.h new file mode 100644 index 0000000000..b013f9cdf4 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/VertexArrayImpl.h @@ -0,0 +1,32 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexAttribImpl.h: Defines the abstract rx::VertexAttribImpl class. + +#ifndef LIBGLESV2_RENDERER_VERTEXARRAYIMPL_H_ +#define LIBGLESV2_RENDERER_VERTEXARRAYIMPL_H_ + +#include "common/angleutils.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/VertexAttribute.h" + +namespace rx +{ + +class VertexArrayImpl +{ + public: + virtual ~VertexArrayImpl() { } + + virtual void setElementArrayBuffer(const gl::Buffer *buffer) = 0; + virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) = 0; + virtual void setAttributeDivisor(size_t idx, GLuint divisor) = 0; + virtual void enableAttribute(size_t idx, bool enabledState) = 0; +}; + +} + +#endif // LIBGLESV2_RENDERER_VERTEXARRAYIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.cpp new file mode 100644 index 0000000000..765089cc96 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.cpp @@ -0,0 +1,23 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// copyimage.cpp: Defines image copying functions + +#include "libGLESv2/renderer/copyImage.h" + +namespace rx +{ + +void CopyBGRAUByteToRGBAUByte(const void *source, void *dest) +{ + unsigned int argb = *(unsigned int*)source; + *(unsigned int*)dest = (argb & 0xFF00FF00) | // Keep alpha and green + (argb & 0x00FF0000) >> 16 | // Move red to blue + (argb & 0x000000FF) << 16; // Move blue to red +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.h b/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.h new file mode 100644 index 0000000000..9b94404ee3 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.h @@ -0,0 +1,42 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// copyimage.h: Defines image copying functions + +#ifndef LIBGLESV2_RENDERER_COPYIMAGE_H_ +#define LIBGLESV2_RENDERER_COPYIMAGE_H_ + +#include "common/mathutil.h" +#include "libGLESv2/angletypes.h" + +namespace rx +{ + +template <typename sourceType, typename colorDataType> +void ReadColor(const void *source, void *dest) +{ + sourceType::readColor(reinterpret_cast<gl::Color<colorDataType>*>(dest), reinterpret_cast<const sourceType*>(source)); +} + +template <typename destType, typename colorDataType> +void WriteColor(const void *source, void *dest) +{ + destType::writeColor(reinterpret_cast<destType*>(dest), reinterpret_cast<const gl::Color<colorDataType>*>(source)); +} + +template <typename sourceType, typename destType, typename colorDataType> +void CopyPixel(const void *source, void *dest) +{ + colorDataType temp; + ReadColor<sourceType, colorDataType>(source, &temp); + WriteColor<destType, colorDataType>(&temp, dest); +} + +void CopyBGRAUByteToRGBAUByte(const void *source, void *dest); + +} + +#endif // LIBGLESV2_RENDERER_COPYIMAGE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/copyvertex.h b/src/3rdparty/angle/src/libGLESv2/renderer/copyvertex.h new file mode 100644 index 0000000000..aca031701e --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/copyvertex.h @@ -0,0 +1,309 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// copyvertex.h: Defines vertex buffer copying and conversion functions + +#ifndef LIBGLESV2_RENDERER_COPYVERTEX_H_ +#define LIBGLESV2_RENDERER_COPYVERTEX_H_ + +#include "common/mathutil.h" + +// 'widenDefaultValueBits' gives the default value for the alpha channel (4th component) +// the sentinel value 0 means we do not want to widen the input or add an alpha channel +template <typename T, unsigned int componentCount, unsigned int widenDefaultValueBits> +inline void copyVertexData(const void *input, size_t stride, size_t count, void *output) +{ + const unsigned int attribSize = sizeof(T) * componentCount; + const T defaultValue = gl::bitCast<T>(widenDefaultValueBits); + const bool widen = (widenDefaultValueBits != 0); + + if (attribSize == stride && !widen) + { + memcpy(output, input, count * attribSize); + } + else + { + unsigned int outputStride = widen ? 4 : componentCount; + + for (unsigned int i = 0; i < count; i++) + { + const T *offsetInput = reinterpret_cast<const T*>(reinterpret_cast<const char*>(input) + i * stride); + T *offsetOutput = reinterpret_cast<T*>(output) + i * outputStride; + + for (unsigned int j = 0; j < componentCount; j++) + { + offsetOutput[j] = offsetInput[j]; + } + + if (widen) + { + offsetOutput[3] = defaultValue; + } + } + } +} + +template <unsigned int componentCount> +inline void copyFixedVertexData(const void* input, size_t stride, size_t count, void* output) +{ + static const float divisor = 1.0f / (1 << 16); + + for (unsigned int i = 0; i < count; i++) + { + const GLfixed* offsetInput = reinterpret_cast<const GLfixed*>(reinterpret_cast<const char*>(input) + stride * i); + float* offsetOutput = reinterpret_cast<float*>(output) + i * componentCount; + + for (unsigned int j = 0; j < componentCount; j++) + { + offsetOutput[j] = static_cast<float>(offsetInput[j]) * divisor; + } + } +} + +template <typename T, unsigned int componentCount, bool normalized> +inline void copyToFloatVertexData(const void* input, size_t stride, size_t count, void* output) +{ + typedef std::numeric_limits<T> NL; + + for (unsigned int i = 0; i < count; i++) + { + const T *offsetInput = reinterpret_cast<const T*>(reinterpret_cast<const char*>(input) + stride * i); + float *offsetOutput = reinterpret_cast<float*>(output) + i * componentCount; + + for (unsigned int j = 0; j < componentCount; j++) + { + if (normalized) + { + if (NL::is_signed) + { + const float divisor = 1.0f / (2 * static_cast<float>(NL::max()) + 1); + offsetOutput[j] = (2 * static_cast<float>(offsetInput[j]) + 1) * divisor; + } + else + { + offsetOutput[j] = static_cast<float>(offsetInput[j]) / NL::max(); + } + } + else + { + offsetOutput[j] = static_cast<float>(offsetInput[j]); + } + } + } +} + +inline void copyPackedUnsignedVertexData(const void* input, size_t stride, size_t count, void* output) +{ + const unsigned int attribSize = 4; + + if (attribSize == stride) + { + memcpy(output, input, count * attribSize); + } + else + { + for (unsigned int i = 0; i < count; i++) + { + const GLuint *offsetInput = reinterpret_cast<const GLuint*>(reinterpret_cast<const char*>(input) + (i * stride)); + GLuint *offsetOutput = reinterpret_cast<GLuint*>(output) + (i * attribSize); + + offsetOutput[i] = offsetInput[i]; + } + } +} + +template <bool isSigned, bool normalized, bool toFloat> +static inline void copyPackedRGB(unsigned int data, void *output) +{ + const unsigned int rgbSignMask = 0x200; // 1 set at the 9 bit + const unsigned int negativeMask = 0xFFFFFC00; // All bits from 10 to 31 set to 1 + + if (toFloat) + { + GLfloat *floatOutput = reinterpret_cast<GLfloat*>(output); + if (isSigned) + { + GLfloat finalValue = 0; + if (data & rgbSignMask) + { + int negativeNumber = data | negativeMask; + finalValue = static_cast<GLfloat>(negativeNumber); + } + else + { + finalValue = static_cast<GLfloat>(data); + } + + if (normalized) + { + const int maxValue = 0x1FF; // 1 set in bits 0 through 8 + const int minValue = 0xFFFFFE01; // Inverse of maxValue + + // A 10-bit two's complement number has the possibility of being minValue - 1 but + // OpenGL's normalization rules dictate that it should be clamped to minValue in this + // case. + if (finalValue < minValue) + { + finalValue = minValue; + } + + const int halfRange = (maxValue - minValue) >> 1; + *floatOutput = ((finalValue - minValue) / halfRange) - 1.0f; + } + else + { + *floatOutput = finalValue; + } + } + else + { + if (normalized) + { + const unsigned int maxValue = 0x3FF; // 1 set in bits 0 through 9 + *floatOutput = static_cast<GLfloat>(data) / static_cast<GLfloat>(maxValue); + } + else + { + *floatOutput = static_cast<GLfloat>(data); + } + } + } + else + { + if (isSigned) + { + GLshort *intOutput = reinterpret_cast<GLshort*>(output); + + if (data & rgbSignMask) + { + *intOutput = data | negativeMask; + } + else + { + *intOutput = data; + } + } + else + { + GLushort *uintOutput = reinterpret_cast<GLushort*>(output); + *uintOutput = data; + } + } +} + +template <bool isSigned, bool normalized, bool toFloat> +inline void copyPackedAlpha(unsigned int data, void *output) +{ + if (toFloat) + { + GLfloat *floatOutput = reinterpret_cast<GLfloat*>(output); + if (isSigned) + { + if (normalized) + { + switch (data) + { + case 0x0: *floatOutput = 0.0f; break; + case 0x1: *floatOutput = 1.0f; break; + case 0x2: *floatOutput = -1.0f; break; + case 0x3: *floatOutput = -1.0f; break; + default: UNREACHABLE(); + } + } + else + { + switch (data) + { + case 0x0: *floatOutput = 0.0f; break; + case 0x1: *floatOutput = 1.0f; break; + case 0x2: *floatOutput = -2.0f; break; + case 0x3: *floatOutput = -1.0f; break; + default: UNREACHABLE(); + } + } + } + else + { + if (normalized) + { + switch (data) + { + case 0x0: *floatOutput = 0.0f / 3.0f; break; + case 0x1: *floatOutput = 1.0f / 3.0f; break; + case 0x2: *floatOutput = 2.0f / 3.0f; break; + case 0x3: *floatOutput = 3.0f / 3.0f; break; + default: UNREACHABLE(); + } + } + else + { + switch (data) + { + case 0x0: *floatOutput = 0.0f; break; + case 0x1: *floatOutput = 1.0f; break; + case 0x2: *floatOutput = 2.0f; break; + case 0x3: *floatOutput = 3.0f; break; + default: UNREACHABLE(); + } + } + } + } + else + { + if (isSigned) + { + GLshort *intOutput = reinterpret_cast<GLshort*>(output); + switch (data) + { + case 0x0: *intOutput = 0; break; + case 0x1: *intOutput = 1; break; + case 0x2: *intOutput = -2; break; + case 0x3: *intOutput = -1; break; + default: UNREACHABLE(); + } + } + else + { + GLushort *uintOutput = reinterpret_cast<GLushort*>(output); + switch (data) + { + case 0x0: *uintOutput = 0; break; + case 0x1: *uintOutput = 1; break; + case 0x2: *uintOutput = 2; break; + case 0x3: *uintOutput = 3; break; + default: UNREACHABLE(); + } + } + } +} + +template <bool isSigned, bool normalized, bool toFloat> +inline void copyPackedVertexData(const void* input, size_t stride, size_t count, void* output) +{ + const unsigned int outputComponentSize = toFloat ? 4 : 2; + const unsigned int componentCount = 4; + + const unsigned int rgbMask = 0x3FF; // 1 set in bits 0 through 9 + const unsigned int redShift = 0; // red is bits 0 through 9 + const unsigned int greenShift = 10; // green is bits 10 through 19 + const unsigned int blueShift = 20; // blue is bits 20 through 29 + + const unsigned int alphaMask = 0x3; // 1 set in bits 0 and 1 + const unsigned int alphaShift = 30; // Alpha is the 30 and 31 bits + + for (unsigned int i = 0; i < count; i++) + { + GLuint packedValue = *reinterpret_cast<const GLuint*>(reinterpret_cast<const char*>(input) + (i * stride)); + GLbyte *offsetOutput = reinterpret_cast<GLbyte*>(output) + (i * outputComponentSize * componentCount); + + copyPackedRGB<isSigned, normalized, toFloat>( (packedValue >> redShift) & rgbMask, offsetOutput + (0 * outputComponentSize)); + copyPackedRGB<isSigned, normalized, toFloat>( (packedValue >> greenShift) & rgbMask, offsetOutput + (1 * outputComponentSize)); + copyPackedRGB<isSigned, normalized, toFloat>( (packedValue >> blueShift) & rgbMask, offsetOutput + (2 * outputComponentSize)); + copyPackedAlpha<isSigned, normalized, toFloat>((packedValue >> alphaShift) & alphaMask, offsetOutput + (3* outputComponentSize)); + } +} + +#endif // LIBGLESV2_RENDERER_COPYVERTEX_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp new file mode 100644 index 0000000000..08457af76d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp @@ -0,0 +1,83 @@ +#include "precompiled.h" +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BufferD3D.cpp Defines common functionality between the Buffer9 and Buffer11 classes. + +#include "libGLESv2/renderer/d3d/BufferD3D.h" +#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/d3d/VertexBuffer.h" +#include "libGLESv2/renderer/d3d/IndexBuffer.h" +#include "libGLESv2/main.h" + +namespace rx +{ + +unsigned int BufferD3D::mNextSerial = 1; + +BufferD3D::BufferD3D() + : BufferImpl(), + mStaticVertexBuffer(NULL), + mStaticIndexBuffer(NULL) +{ + updateSerial(); +} + +BufferD3D::~BufferD3D() +{ + SafeDelete(mStaticVertexBuffer); + SafeDelete(mStaticIndexBuffer); +} + +BufferD3D *BufferD3D::makeBufferD3D(BufferImpl *buffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(BufferD3D*, buffer)); + return static_cast<BufferD3D*>(buffer); +} + +void BufferD3D::updateSerial() +{ + mSerial = mNextSerial++; +} + +void BufferD3D::initializeStaticData() +{ + if (!mStaticVertexBuffer) + { + mStaticVertexBuffer = new rx::StaticVertexBufferInterface(getRenderer()); + } + if (!mStaticIndexBuffer) + { + mStaticIndexBuffer = new rx::StaticIndexBufferInterface(getRenderer()); + } +} + +void BufferD3D::invalidateStaticData() +{ + if ((mStaticVertexBuffer && mStaticVertexBuffer->getBufferSize() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0)) + { + SafeDelete(mStaticVertexBuffer); + SafeDelete(mStaticIndexBuffer); + } + + mUnmodifiedDataUse = 0; +} + +// Creates static buffers if sufficient used data has been left unmodified +void BufferD3D::promoteStaticUsage(int dataSize) +{ + if (!mStaticVertexBuffer && !mStaticIndexBuffer) + { + mUnmodifiedDataUse += dataSize; + + if (mUnmodifiedDataUse > 3 * getSize()) + { + initializeStaticData(); + } + } +} + +}
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.h new file mode 100644 index 0000000000..8e204b9139 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.h @@ -0,0 +1,60 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BufferImpl.h: Defines the abstract rx::BufferImpl class. + +#ifndef LIBGLESV2_RENDERER_BUFFERD3D_H_ +#define LIBGLESV2_RENDERER_BUFFERD3D_H_ + +#include "libGLESv2/renderer/BufferImpl.h" +#include "libGLESv2/angletypes.h" +#include "libGLESv2/renderer/IndexRangeCache.h" + +namespace rx +{ + +class Renderer; +class StaticIndexBufferInterface; +class StaticVertexBufferInterface; + +class BufferD3D : public BufferImpl +{ + public: + BufferD3D(); + virtual ~BufferD3D(); + + static BufferD3D *makeBufferD3D(BufferImpl *buffer); + + unsigned int getSerial() const { return mSerial; } + + virtual size_t getSize() const = 0; + virtual void clear() = 0; + virtual bool supportsDirectBinding() const = 0; + virtual Renderer* getRenderer() = 0; + + rx::StaticVertexBufferInterface *getStaticVertexBuffer() { return mStaticVertexBuffer; } + rx::StaticIndexBufferInterface *getStaticIndexBuffer() { return mStaticIndexBuffer; } + rx::IndexRangeCache *getIndexRangeCache() { return &mIndexRangeCache; } + + void initializeStaticData(); + void invalidateStaticData(); + void promoteStaticUsage(int dataSize); + + protected: + unsigned int mSerial; + static unsigned int mNextSerial; + + void updateSerial(); + + rx::StaticVertexBufferInterface *mStaticVertexBuffer; + rx::StaticIndexBufferInterface *mStaticIndexBuffer; + rx::IndexRangeCache mIndexRangeCache; + unsigned int mUnmodifiedDataUse; +}; + +} + +#endif // LIBGLESV2_RENDERER_BUFFERIMPLD3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp new file mode 100644 index 0000000000..e3b88d506d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp @@ -0,0 +1,171 @@ +#include "precompiled.h" +#include "libGLESv2/renderer/d3d/HLSLCompiler.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/main.h" + +#include "common/utilities.h" +#include "common/platform.h" + +#include "third_party/trace_event/trace_event.h" + +#include <d3dcompiler.h> + +#if defined(__MINGW32__) && !defined(D3DCOMPILER_DLL) + +// Add define + typedefs for older MinGW-w64 headers (pre 5783) + +#define D3DCOMPILER_DLL L"d3dcompiler_43.dll" + +HRESULT WINAPI D3DCompile(const void *data, SIZE_T data_size, const char *filename, + const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, + const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages); +typedef HRESULT (WINAPI *pD3DCompile)(const void *data, SIZE_T data_size, const char *filename, + const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, + const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages); + +#endif // __MINGW32__ && !D3DCOMPILER_DLL + +#ifndef QT_D3DCOMPILER_DLL +#define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL +#endif + +#ifndef LoadLibrary +#define LoadLibrary(dll) LoadPackagedLibrary(dll, NULL) +#endif + +namespace rx +{ + +HLSLCompiler::HLSLCompiler() + : mD3DCompilerModule(NULL), + mD3DCompileFunc(NULL) +{ +} + +HLSLCompiler::~HLSLCompiler() +{ + release(); +} + +bool HLSLCompiler::initialize() +{ + TRACE_EVENT0("gpu", "initializeCompiler"); +#if !defined(ANGLE_PLATFORM_WINRT) +#if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES) + // Find a D3DCompiler module that had already been loaded based on a predefined list of versions. + static const char *d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES; + + for (size_t i = 0; i < ArraySize(d3dCompilerNames); ++i) + { + if (GetModuleHandleExA(0, d3dCompilerNames[i], &mD3DCompilerModule)) + { + break; + } + } +#endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES + + // Load the compiler DLL specified by the environment, or default to QT_D3DCOMPILER_DLL + const wchar_t *defaultCompiler = _wgetenv(L"QT_D3DCOMPILER_DLL"); + if (!defaultCompiler) + defaultCompiler = QT_D3DCOMPILER_DLL; + + const wchar_t *compilerDlls[] = { + defaultCompiler, + L"d3dcompiler_47.dll", + L"d3dcompiler_46.dll", + L"d3dcompiler_45.dll", + L"d3dcompiler_44.dll", + L"d3dcompiler_43.dll", + 0 + }; + + // Load the first available known compiler DLL + for (int i = 0; compilerDlls[i]; ++i) + { + mD3DCompilerModule = LoadLibrary(compilerDlls[i]); + if (mD3DCompilerModule) + break; + } + + if (!mD3DCompilerModule) + { + ERR("No D3D compiler module found - aborting!\n"); + return false; + } + + mD3DCompileFunc = reinterpret_cast<CompileFuncPtr>(GetProcAddress(mD3DCompilerModule, "D3DCompile")); + ASSERT(mD3DCompileFunc); +#else + mD3DCompileFunc = reinterpret_cast<CompileFuncPtr>(&D3DCompile); +#endif + return mD3DCompileFunc != NULL; +} + +void HLSLCompiler::release() +{ + if (mD3DCompilerModule) + { + FreeLibrary(mD3DCompilerModule); + mD3DCompilerModule = NULL; + mD3DCompileFunc = NULL; + } +} + +ShaderBlob *HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile, + const UINT optimizationFlags[], const char *flagNames[], int attempts) const +{ +#if !defined(ANGLE_PLATFORM_WINRT) + ASSERT(mD3DCompilerModule && mD3DCompileFunc); +#endif + + if (!hlsl) + { + return NULL; + } + + pD3DCompile compileFunc = reinterpret_cast<pD3DCompile>(mD3DCompileFunc); + for (int i = 0; i < attempts; ++i) + { + ID3DBlob *errorMessage = NULL; + ID3DBlob *binary = NULL; + + HRESULT result = compileFunc(hlsl, strlen(hlsl), gl::g_fakepath, NULL, NULL, "main", profile, optimizationFlags[i], 0, &binary, &errorMessage); + + if (errorMessage) + { + const char *message = (const char*)errorMessage->GetBufferPointer(); + + infoLog.appendSanitized(message); + TRACE("\n%s", hlsl); + TRACE("\n%s", message); + + SafeRelease(errorMessage); + } + + if (SUCCEEDED(result)) + { + return (ShaderBlob*)binary; + } + else + { + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, (ShaderBlob*)NULL); + } + + infoLog.append("Warning: D3D shader compilation failed with "); + infoLog.append(flagNames[i]); + infoLog.append(" flags."); + if (i + 1 < attempts) + { + infoLog.append(" Retrying with "); + infoLog.append(flagNames[i + 1]); + infoLog.append(".\n"); + } + } + } + + return NULL; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h new file mode 100644 index 0000000000..0ce9e44be5 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h @@ -0,0 +1,38 @@ +#ifndef LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_ +#define LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_ + +#include "common/angleutils.h" + +namespace gl +{ +class InfoLog; +} + +namespace rx +{ + +typedef void* ShaderBlob; +typedef void(*CompileFuncPtr)(); + +class HLSLCompiler +{ + public: + HLSLCompiler(); + ~HLSLCompiler(); + + bool initialize(); + void release(); + + ShaderBlob *compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile, + const UINT optimizationFlags[], const char *flagNames[], int attempts) const; + + private: + DISALLOW_COPY_AND_ASSIGN(HLSLCompiler); + + HMODULE mD3DCompilerModule; + CompileFuncPtr mD3DCompileFunc; +}; + +} + +#endif // LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp new file mode 100644 index 0000000000..615d11a1f1 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp @@ -0,0 +1,27 @@ +#include "precompiled.h" +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image.h: Implements the rx::Image class, an abstract base class for the +// renderer-specific classes which will define the interface to the underlying +// surfaces or resources. + +#include "libGLESv2/renderer/d3d/ImageD3D.h" + +namespace rx +{ + +ImageD3D::ImageD3D() +{ +} + +ImageD3D *ImageD3D::makeImageD3D(Image *img) +{ + ASSERT(HAS_DYNAMIC_TYPE(rx::ImageD3D*, img)); + return static_cast<rx::ImageD3D*>(img); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.h new file mode 100644 index 0000000000..242ce5af70 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.h @@ -0,0 +1,54 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image.h: Defines the rx::Image class, an abstract base class for the +// renderer-specific classes which will define the interface to the underlying +// surfaces or resources. + +#ifndef LIBGLESV2_RENDERER_IMAGED3D_H_ +#define LIBGLESV2_RENDERER_IMAGED3D_H_ + +#include "common/debug.h" +#include "libGLESv2/renderer/Image.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class TextureStorageInterface2D; +class TextureStorageInterfaceCube; +class TextureStorageInterface3D; +class TextureStorageInterface2DArray; + +class ImageD3D : public Image +{ + public: + ImageD3D(); + virtual ~ImageD3D() {}; + + static ImageD3D *makeImageD3D(Image *img); + + virtual bool isDirty() const = 0; + + virtual void setManagedSurface(TextureStorageInterface2D *storage, int level) {}; + virtual void setManagedSurface(TextureStorageInterfaceCube *storage, int face, int level) {}; + virtual void setManagedSurface(TextureStorageInterface3D *storage, int level) {}; + virtual void setManagedSurface(TextureStorageInterface2DArray *storage, int layer, int level) {}; + virtual bool copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0; + virtual bool copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0; + virtual bool copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) = 0; + virtual bool copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(ImageD3D); +}; + +} + +#endif // LIBGLESV2_RENDERER_IMAGED3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/IndexBuffer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.cpp index 37dbd3e195..13e35e09ec 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/IndexBuffer.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.cpp @@ -8,7 +8,7 @@ // IndexBuffer.cpp: Defines the abstract IndexBuffer class and IndexBufferInterface // class with derivations, classes that perform graphics API agnostic index buffer operations. -#include "libGLESv2/renderer/IndexBuffer.h" +#include "libGLESv2/renderer/d3d/IndexBuffer.h" #include "libGLESv2/renderer/Renderer.h" namespace rx @@ -194,4 +194,3 @@ IndexRangeCache *StaticIndexBufferInterface::getIndexRangeCache() } } - diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/IndexBuffer.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.h index 6fb885a1cd..6fb885a1cd 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/IndexBuffer.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.h diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/IndexDataManager.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.cpp index 49bace8193..932524c132 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/IndexDataManager.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.cpp @@ -8,13 +8,13 @@ // IndexDataManager.cpp: Defines the IndexDataManager, a class that // runs the Buffer translation process for index buffers. -#include "libGLESv2/renderer/IndexDataManager.h" -#include "libGLESv2/renderer/BufferStorage.h" +#include "libGLESv2/renderer/d3d/IndexDataManager.h" +#include "libGLESv2/renderer/d3d/BufferD3D.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/main.h" -#include "libGLESv2/utilities.h" -#include "libGLESv2/renderer/IndexBuffer.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/renderer/d3d/IndexBuffer.h" namespace rx { @@ -118,7 +118,7 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer unsigned int offset = 0; bool alignedOffset = false; - BufferStorage *storage = NULL; + BufferD3D *storage = NULL; if (buffer != NULL) { @@ -128,7 +128,7 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer } offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices)); - storage = buffer->getStorage(); + storage = BufferD3D::makeBufferD3D(buffer->getImplementation()); switch (type) { @@ -138,7 +138,7 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer default: UNREACHABLE(); alignedOffset = false; } - unsigned int typeSize = gl::ComputeTypeSize(type); + unsigned int typeSize = gl::GetTypeBytes(type); // check for integer overflows if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeSize) || @@ -157,7 +157,7 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort; - StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL; + StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL; IndexBufferInterface *indexBuffer = streamingBuffer; bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() && destinationIndexType == type; @@ -167,23 +167,23 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer { indexBuffer = streamingBuffer; streamOffset = offset; - storage->markBufferUsage(); - if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex, + if (!storage->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex, &translated->maxIndex, NULL)) { computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); - buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, + storage->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, translated->maxIndex, offset); } } else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset) { indexBuffer = staticBuffer; + if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex, &translated->maxIndex, &streamOffset)) { - streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType); + streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType); computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, translated->maxIndex, streamOffset); @@ -198,11 +198,11 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer if (staticBuffer->getBufferSize() == 0 && alignedOffset) { indexBuffer = staticBuffer; - convertCount = storage->getSize() / gl::ComputeTypeSize(type); + convertCount = storage->getSize() / gl::GetTypeBytes(type); } else { - buffer->invalidateStaticData(); + storage->invalidateStaticData(); staticBuffer = NULL; } } @@ -213,7 +213,7 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer return GL_INVALID_OPERATION; } - unsigned int indexTypeSize = gl::ComputeTypeSize(destinationIndexType); + unsigned int indexTypeSize = gl::GetTypeBytes(destinationIndexType); if (convertCount > std::numeric_limits<unsigned int>::max() / indexTypeSize) { ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, indexTypeSize); @@ -246,7 +246,7 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer if (staticBuffer) { - streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType); + streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType); staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, translated->maxIndex, streamOffset); } @@ -255,12 +255,12 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer translated->storage = directStorage ? storage : NULL; translated->indexBuffer = indexBuffer->getIndexBuffer(); translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial(); - translated->startIndex = streamOffset / gl::ComputeTypeSize(destinationIndexType); + translated->startIndex = streamOffset / gl::GetTypeBytes(destinationIndexType); translated->startOffset = streamOffset; - if (buffer) + if (storage) { - buffer->promoteStaticUsage(count * gl::ComputeTypeSize(type)); + storage->promoteStaticUsage(count * gl::GetTypeBytes(type)); } return GL_NO_ERROR; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/IndexDataManager.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.h index 0e77c81d1b..8f981936ea 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/IndexDataManager.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.h @@ -27,7 +27,7 @@ namespace rx class StaticIndexBufferInterface; class StreamingIndexBufferInterface; class IndexBuffer; -class BufferStorage; +class BufferD3D; class Renderer; struct TranslatedIndexData @@ -38,7 +38,7 @@ struct TranslatedIndexData unsigned int startOffset; // In bytes IndexBuffer *indexBuffer; - BufferStorage *storage; + BufferD3D *storage; unsigned int serial; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.cpp new file mode 100644 index 0000000000..301bbe8d3d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.cpp @@ -0,0 +1,72 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "libGLESv2/renderer/d3d/MemoryBuffer.h" + +#include <algorithm> +#include <cstdlib> + +namespace rx +{ + +MemoryBuffer::MemoryBuffer() + : mSize(0), + mData(NULL) +{ +} + +MemoryBuffer::~MemoryBuffer() +{ + free(mData); + mData = NULL; +} + +bool MemoryBuffer::resize(size_t size) +{ + if (size == 0) + { + free(mData); + mData = NULL; + mSize = 0; + } + else + { + uint8_t *newMemory = reinterpret_cast<uint8_t*>(malloc(sizeof(uint8_t) * size)); + if (newMemory == NULL) + { + return false; + } + + if (mData) + { + // Copy the intersection of the old data and the new data + std::copy(mData, mData + std::min(mSize, size), newMemory); + free(mData); + } + + mData = newMemory; + mSize = size; + } + + return true; +} + +size_t MemoryBuffer::size() const +{ + return mSize; +} + +const uint8_t *MemoryBuffer::data() const +{ + return mData; +} + +uint8_t *MemoryBuffer::data() +{ + return mData; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.h new file mode 100644 index 0000000000..2484c07455 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef LIBGLESV2_RENDERER_D3D_MEMORYBUFFER_H_ +#define LIBGLESV2_RENDERER_D3D_MEMORYBUFFER_H_ + +#include <cstddef> +#include <cstdint> + +namespace rx +{ + +class MemoryBuffer +{ + public: + MemoryBuffer(); + ~MemoryBuffer(); + + bool resize(size_t size); + size_t size() const; + + const uint8_t *data() const; + uint8_t *data(); + + private: + size_t mSize; + uint8_t *mData; +}; + +} + +#endif // LIBGLESV2_RENDERER_D3D_MEMORYBUFFER_H diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp new file mode 100644 index 0000000000..e725e2fefe --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp @@ -0,0 +1,2550 @@ +#include "precompiled.h" +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends. + +#include "common/mathutil.h" +#include "common/utilities.h" +#include "libEGL/Surface.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/main.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/renderer/BufferImpl.h" +#include "libGLESv2/renderer/RenderTarget.h" +#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/d3d/ImageD3D.h" +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/TextureStorage.h" + +namespace rx +{ + +bool IsMipmapFiltered(const gl::SamplerState &samplerState) +{ + switch (samplerState.minFilter) + { + case GL_NEAREST: + case GL_LINEAR: + return false; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + return true; + default: UNREACHABLE(); + return false; + } +} + +bool IsRenderTargetUsage(GLenum usage) +{ + return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); +} + +TextureD3D::TextureD3D(Renderer *renderer) + : mRenderer(renderer), + mUsage(GL_NONE), + mDirtyImages(true), + mImmutable(false) +{ +} + +TextureD3D::~TextureD3D() +{ +} + +GLint TextureD3D::getBaseLevelWidth() const +{ + const Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getWidth() : 0); +} + +GLint TextureD3D::getBaseLevelHeight() const +{ + const Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getHeight() : 0); +} + +GLint TextureD3D::getBaseLevelDepth() const +{ + const Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getDepth() : 0); +} + +// Note: "base level image" is loosely defined to be any image from the base level, +// where in the base of 2D array textures and cube maps there are several. Don't use +// the base level image for anything except querying texture format and size. +GLenum TextureD3D::getBaseLevelInternalFormat() const +{ + const Image *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getInternalFormat() : GL_NONE); +} + +void TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image) +{ + // No-op + if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) + { + return; + } + + // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. + // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. + const void *pixelData = pixels; + + if (unpack.pixelBuffer.id() != 0) + { + // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported + gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); + ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels); + // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data. + // This functionality should be moved into renderer and the getData method of BufferImpl removed. + const void *bufferData = pixelBuffer->getImplementation()->getData(); + pixelData = static_cast<const unsigned char *>(bufferData) + offset; + } + + if (pixelData != NULL) + { + image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData); + mDirtyImages = true; + } +} + +bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, Image *image) +{ + const void *pixelData = pixels; + + // CPU readback & copy where direct GPU copy is not supported + if (unpack.pixelBuffer.id() != 0) + { + gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); + unsigned int offset = reinterpret_cast<unsigned int>(pixels); + // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data. + // This functionality should be moved into renderer and the getData method of BufferImpl removed. + const void *bufferData = pixelBuffer->getImplementation()->getData(); + pixelData = static_cast<const unsigned char *>(bufferData) + offset; + } + + if (pixelData != NULL) + { + image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData); + mDirtyImages = true; + } + + return true; +} + +void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels); + mDirtyImages = true; + } +} + +bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLsizei imageSize, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels); + mDirtyImages = true; + } + + return true; +} + +bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat) +{ + return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); +} + +bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea, + GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget) +{ + if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0) + { + return true; + } + + // In order to perform the fast copy through the shader, we must have the right format, and be able + // to create a render target. + ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat)); + + unsigned int offset = reinterpret_cast<unsigned int>(pixels); + + return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea); +} + +GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const +{ + if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT) + { + // Maximum number of levels + return gl::log2(std::max(std::max(width, height), depth)) + 1; + } + else + { + // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. + return 1; + } +} + +int TextureD3D::mipLevels() const +{ + return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; +} + + +TextureD3D_2D::TextureD3D_2D(Renderer *renderer) + : TextureD3D(renderer), + Texture2DImpl(), + mTexStorage(NULL) +{ + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage()); + } +} + +TextureD3D_2D::~TextureD3D_2D() +{ + SafeDelete(mTexStorage); + + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + delete mImageArray[i]; + } +} + +TextureD3D_2D *TextureD3D_2D::makeTextureD3D_2D(Texture2DImpl *texture) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_2D*, texture)); + return static_cast<TextureD3D_2D*>(texture); +} + +TextureStorageInterface *TextureD3D_2D::getNativeTexture() +{ + // ensure the underlying texture is created + initializeStorage(false); + + TextureStorageInterface *storage = getBaseLevelStorage(); + if (storage) + { + updateStorage(); + } + + return storage; +} + +Image *TextureD3D_2D::getImage(int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return mImageArray[level]; +} + +void TextureD3D_2D::setUsage(GLenum usage) +{ + mUsage = usage; +} + +void TextureD3D_2D::resetDirty() +{ + mDirtyImages = false; +} + +GLsizei TextureD3D_2D::getWidth(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getWidth(); + else + return 0; +} + +GLsizei TextureD3D_2D::getHeight(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getHeight(); + else + return 0; +} + +GLenum TextureD3D_2D::getInternalFormat(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getInternalFormat(); + else + return GL_NONE; +} + +GLenum TextureD3D_2D::getActualFormat(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getActualFormat(); + else + return GL_NONE; +} + +bool TextureD3D_2D::isDepth(GLint level) const +{ + return gl::GetDepthBits(getInternalFormat(level)) > 0; +} + +void TextureD3D_2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +{ + GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat + : gl::GetSizedInternalFormat(format, type); + bool fastUnpacked = false; + + // Attempt a fast gpu copy of the pixel data to the surface + if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level)) + { + // Will try to create RT storage if it does not exist + RenderTarget *destRenderTarget = getRenderTarget(level); + gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1); + + if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget)) + { + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; + } + } + + if (!fastUnpacked) + { + TextureD3D::setImage(unpack, type, pixels, mImageArray[level]); + } +} + +void TextureD3D_2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) +{ + TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]); +} + +void TextureD3D_2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +{ + bool fastUnpacked = false; + + if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level)) + { + RenderTarget *renderTarget = getRenderTarget(level); + gl::Box destArea(xoffset, yoffset, 0, width, height, 1); + + if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget)) + { + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; + } + } + + if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level])) + { + commitRect(level, xoffset, yoffset, width, height); + } +} + +void TextureD3D_2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) +{ + if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level])) + { + commitRect(level, xoffset, yoffset, width, height); + } +} + +void TextureD3D_2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +{ + if (!mImageArray[level]->isRenderableFormat()) + { + mImageArray[level]->copy(0, 0, 0, x, y, width, height, source); + mDirtyImages = true; + } + else + { + ensureRenderTarget(); + mImageArray[level]->markClean(); + + if (width != 0 && height != 0 && isValidLevel(level)) + { + gl::Rectangle sourceRect; + sourceRect.x = x; + sourceRect.width = width; + sourceRect.y = y; + sourceRect.height = height; + + mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level); + } + } +} + +void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +{ + // can only make our texture storage to a render target if level 0 is defined (with a width & height) and + // the current level we're copying to is defined (with appropriate format, width & height) + bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); + + if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) + { + mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source); + mDirtyImages = true; + } + else + { + ensureRenderTarget(); + + if (isValidLevel(level)) + { + updateStorageLevel(level); + + gl::Rectangle sourceRect; + sourceRect.x = x; + sourceRect.width = width; + sourceRect.y = y; + sourceRect.height = height; + + mRenderer->copyImage(source, sourceRect, + gl::GetFormat(getBaseLevelInternalFormat()), + xoffset, yoffset, mTexStorage, level); + } + } +} + +void TextureD3D_2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + for (int level = 0; level < levels; level++) + { + GLsizei levelWidth = std::max(1, width >> level); + GLsizei levelHeight = std::max(1, height >> level); + mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true); + } + + for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true); + } + + mImmutable = true; + + setCompleteTexStorage(new TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels)); +} + +// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. +bool TextureD3D_2D::isSamplerComplete(const gl::SamplerState &samplerState) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + + if (width <= 0 || height <= 0) + { + return false; + } + + if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(0)).filterable) + { + if (samplerState.magFilter != GL_NEAREST || + (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) + { + return false; + } + } + + // TODO(geofflang): use context's extensions + bool npotSupport = mRenderer->getRendererExtensions().textureNPOT; + + if (!npotSupport) + { + if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(width)) || + (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(height))) + { + return false; + } + } + + if (IsMipmapFiltered(samplerState)) + { + if (!npotSupport) + { + if (!gl::isPow2(width) || !gl::isPow2(height)) + { + return false; + } + } + + if (!isMipmapComplete()) + { + return false; + } + } + + // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if: + // The internalformat specified for the texture arrays is a sized internal depth or + // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_- + // MODE is NONE, and either the magnification filter is not NEAREST or the mini- + // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST. + if (gl::GetDepthBits(getInternalFormat(0)) > 0 && mRenderer->getCurrentClientVersion() > 2) + { + if (samplerState.compareMode == GL_NONE) + { + if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) || + samplerState.magFilter != GL_NEAREST) + { + return false; + } + } + } + + return true; +} + +void TextureD3D_2D::bindTexImage(egl::Surface *surface) +{ + GLenum internalformat = surface->getFormat(); + + mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true); + + if (mTexStorage) + { + SafeDelete(mTexStorage); + } + mTexStorage = new TextureStorageInterface2D(mRenderer, surface->getSwapChain()); + + mDirtyImages = true; +} + +void TextureD3D_2D::releaseTexImage() +{ + if (mTexStorage) + { + SafeDelete(mTexStorage); + } + + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true); + } +} + +void TextureD3D_2D::generateMipmaps() +{ + int levelCount = mipLevels(); + + if (mTexStorage && mTexStorage->isRenderTarget()) + { + for (int level = 1; level < levelCount; level++) + { + mTexStorage->generateMipmap(level); + + mImageArray[level]->markClean(); + } + } + else + { + for (int level = 1; level < levelCount; level++) + { + mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]); + } + } +} + +unsigned int TextureD3D_2D::getRenderTargetSerial(GLint level) +{ + return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0); +} + +RenderTarget *TextureD3D_2D::getRenderTarget(GLint level) +{ + // ensure the underlying texture is created + if (!ensureRenderTarget()) + { + return NULL; + } + + updateStorageLevel(level); + + // ensure this is NOT a depth texture + if (isDepth(level)) + { + return NULL; + } + + return mTexStorage->getRenderTarget(level); +} + +RenderTarget *TextureD3D_2D::getDepthSencil(GLint level) +{ + // ensure the underlying texture is created + if (!ensureRenderTarget()) + { + return NULL; + } + + updateStorageLevel(level); + + // ensure this is actually a depth texture + if (!isDepth(level)) + { + return NULL; + } + + return mTexStorage->getRenderTarget(level); +} + +// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool TextureD3D_2D::isMipmapComplete() const +{ + int levelCount = mipLevels(); + + for (int level = 0; level < levelCount; level++) + { + if (!isLevelComplete(level)) + { + return false; + } + } + + return true; +} + +bool TextureD3D_2D::isValidLevel(int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false); +} + +bool TextureD3D_2D::isLevelComplete(int level) const +{ + if (isImmutable()) + { + return true; + } + + const Image *baseImage = getBaseLevelImage(); + + GLsizei width = baseImage->getWidth(); + GLsizei height = baseImage->getHeight(); + + if (width <= 0 || height <= 0) + { + return false; + } + + // The base image level is complete if the width and height are positive + if (level == 0) + { + return true; + } + + ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ImageD3D *image = mImageArray[level]; + + if (image->getInternalFormat() != baseImage->getInternalFormat()) + { + return false; + } + + if (image->getWidth() != std::max(1, width >> level)) + { + return false; + } + + if (image->getHeight() != std::max(1, height >> level)) + { + return false; + } + + return true; +} + +// Constructs a native texture resource from the texture images +void TextureD3D_2D::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return; + } + + // do not attempt to create storage for nonexistant data + if (!isLevelComplete(0)) + { + return; + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + + setCompleteTexStorage(createCompleteStorage(createRenderTarget)); + ASSERT(mTexStorage); + + // flush image data to the storage + updateStorage(); +} + +TextureStorageInterface2D *TextureD3D_2D::createCompleteStorage(bool renderTarget) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + + ASSERT(width > 0 && height > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); + + return new TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels); +} + +void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage) +{ + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + + if (mTexStorage && mTexStorage->isManaged()) + { + for (int level = 0; level < mTexStorage->getLevelCount(); level++) + { + mImageArray[level]->setManagedSurface(mTexStorage, level); + } + } + + mDirtyImages = true; +} + +void TextureD3D_2D::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int level = 0; level < storageLevels; level++) + { + if (mImageArray[level]->isDirty() && isLevelComplete(level)) + { + updateStorageLevel(level); + } + } +} + +bool TextureD3D_2D::ensureRenderTarget() +{ + initializeStorage(true); + + if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0) + { + ASSERT(mTexStorage); + if (!mTexStorage->isRenderTarget()) + { + TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true); + + if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage)) + { + delete newRenderTargetStorage; + return gl::error(GL_OUT_OF_MEMORY, false); + } + + setCompleteTexStorage(newRenderTargetStorage); + } + } + + return (mTexStorage && mTexStorage->isRenderTarget()); +} + +TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage() +{ + return mTexStorage; +} + +const ImageD3D *TextureD3D_2D::getBaseLevelImage() const +{ + return mImageArray[0]; +} + +void TextureD3D_2D::updateStorageLevel(int level) +{ + ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(isLevelComplete(level)); + + if (mImageArray[level]->isDirty()) + { + commitRect(level, 0, 0, getWidth(level), getHeight(level)); + } +} + +void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height) +{ + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false); + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + width != storageWidth || + height != storageHeight || + internalformat != storageFormat) // Discard mismatched storage + { + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + + SafeDelete(mTexStorage); + mDirtyImages = true; + } + } +} + +void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + if (isValidLevel(level)) + { + ImageD3D *image = mImageArray[level]; + if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height)) + { + image->markClean(); + } + } +} + + +TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer) + : TextureCubeImpl(), + TextureD3D(renderer), + mTexStorage(NULL) +{ + for (int i = 0; i < 6; i++) + { + for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + { + mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage()); + } + } +} + +TextureD3D_Cube::~TextureD3D_Cube() +{ + SafeDelete(mTexStorage); + + for (int i = 0; i < 6; i++) + { + for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + { + SafeDelete(mImageArray[i][j]); + } + } +} + +TextureD3D_Cube *TextureD3D_Cube::makeTextureD3D_Cube(TextureCubeImpl *texture) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_Cube*, texture)); + return static_cast<TextureD3D_Cube*>(texture); +} + +TextureStorageInterface *TextureD3D_Cube::getNativeTexture() +{ + // ensure the underlying texture is created + initializeStorage(false); + + TextureStorageInterface *storage = getBaseLevelStorage(); + if (storage) + { + updateStorage(); + } + + return storage; +} + +Image *TextureD3D_Cube::getImage(GLenum target, int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return mImageArray[targetToIndex(target)][level]; +} + +void TextureD3D_Cube::setUsage(GLenum usage) +{ + mUsage = usage; +} + +void TextureD3D_Cube::resetDirty() +{ + mDirtyImages = false; +} + +GLenum TextureD3D_Cube::getInternalFormat(GLenum target, GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[targetToIndex(target)][level]->getInternalFormat(); + else + return GL_NONE; +} + +bool TextureD3D_Cube::isDepth(GLenum target, GLint level) const +{ + return gl::GetDepthBits(getInternalFormat(target, level)) > 0; +} + +void TextureD3D_Cube::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +{ + GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat + : gl::GetSizedInternalFormat(format, type); + + redefineImage(faceIndex, level, sizedInternalFormat, width, height); + + TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]); +} + +void TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) +{ + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + int faceIndex = targetToIndex(target); + redefineImage(faceIndex, level, format, width, height); + + TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]); +} + +void TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +{ + int faceIndex = targetToIndex(target); + if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level])) + { + commitRect(faceIndex, level, xoffset, yoffset, width, height); + } +} + +void TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) +{ + int faceIndex = targetToIndex(target); + if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level])) + { + commitRect(faceIndex, level, xoffset, yoffset, width, height); + } +} + +void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +{ + int faceIndex = targetToIndex(target); + GLenum sizedInternalFormat = gl::IsSizedInternalFormat(format) ? format + : gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); + redefineImage(faceIndex, level, sizedInternalFormat, width, height); + + if (!mImageArray[faceIndex][level]->isRenderableFormat()) + { + mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source); + mDirtyImages = true; + } + else + { + ensureRenderTarget(); + mImageArray[faceIndex][level]->markClean(); + + ASSERT(width == height); + + if (width > 0 && isValidFaceLevel(faceIndex, level)) + { + gl::Rectangle sourceRect; + sourceRect.x = x; + sourceRect.width = width; + sourceRect.y = y; + sourceRect.height = height; + + mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level); + } + } +} + +void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +{ + int faceIndex = targetToIndex(target); + + // We can only make our texture storage to a render target if the level we're copying *to* is complete + // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot + // rely on the "getBaseLevel*" methods reliably otherwise. + bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete(); + + if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) + { + mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source); + mDirtyImages = true; + } + else + { + ensureRenderTarget(); + + if (isValidFaceLevel(faceIndex, level)) + { + updateStorageFaceLevel(faceIndex, level); + + gl::Rectangle sourceRect; + sourceRect.x = x; + sourceRect.width = width; + sourceRect.y = y; + sourceRect.height = height; + + mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat()), + xoffset, yoffset, mTexStorage, target, level); + } + } +} + +void TextureD3D_Cube::storage(GLsizei levels, GLenum internalformat, GLsizei size) +{ + for (int level = 0; level < levels; level++) + { + GLsizei mipSize = std::max(1, size >> level); + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true); + } + } + + for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true); + } + } + + mImmutable = true; + + setCompleteTexStorage(new TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels)); +} + +bool TextureD3D_Cube::isSamplerComplete(const gl::SamplerState &samplerState) const +{ + int size = getBaseLevelWidth(); + + bool mipmapping = IsMipmapFiltered(samplerState); + + // TODO(geofflang): use context's texture caps + if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)).filterable) + { + if (samplerState.magFilter != GL_NEAREST || + (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) + { + return false; + } + } + + // TODO(geofflang): use context's extensions + if (!gl::isPow2(size) && !mRenderer->getRendererExtensions().textureNPOT) + { + if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping) + { + return false; + } + } + + if (!mipmapping) + { + if (!isCubeComplete()) + { + return false; + } + } + else + { + if (!isMipmapCubeComplete()) // Also tests for isCubeComplete() + { + return false; + } + } + + return true; +} + +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool TextureD3D_Cube::isCubeComplete() const +{ + int baseWidth = getBaseLevelWidth(); + int baseHeight = getBaseLevelHeight(); + GLenum baseFormat = getBaseLevelInternalFormat(); + + if (baseWidth <= 0 || baseWidth != baseHeight) + { + return false; + } + + for (int faceIndex = 1; faceIndex < 6; faceIndex++) + { + const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0]; + + if (faceBaseImage.getWidth() != baseWidth || + faceBaseImage.getHeight() != baseHeight || + faceBaseImage.getInternalFormat() != baseFormat ) + { + return false; + } + } + + return true; +} + +void TextureD3D_Cube::generateMipmaps() +{ + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + int levelCount = mipLevels(); + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + for (int level = 1; level < levelCount; level++) + { + int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1)); + redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize); + } + } + + if (mTexStorage && mTexStorage->isRenderTarget()) + { + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + for (int level = 1; level < levelCount; level++) + { + mTexStorage->generateMipmap(faceIndex, level); + + mImageArray[faceIndex][level]->markClean(); + } + } + } + else + { + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + for (int level = 1; level < levelCount; level++) + { + mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]); + } + } + } +} + +unsigned int TextureD3D_Cube::getRenderTargetSerial(GLenum target, GLint level) +{ + return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0); +} + +RenderTarget *TextureD3D_Cube::getRenderTarget(GLenum target, GLint level) +{ + ASSERT(gl::IsCubemapTextureTarget(target)); + + // ensure the underlying texture is created + if (!ensureRenderTarget()) + { + return NULL; + } + + updateStorageFaceLevel(targetToIndex(target), level); + + // ensure this is NOT a depth texture + if (isDepth(target, level)) + { + return NULL; + } + + return mTexStorage->getRenderTarget(target, level); +} + +RenderTarget *TextureD3D_Cube::getDepthStencil(GLenum target, GLint level) +{ + ASSERT(gl::IsCubemapTextureTarget(target)); + + // ensure the underlying texture is created + if (!ensureRenderTarget()) + { + return NULL; + } + + updateStorageFaceLevel(targetToIndex(target), level); + + // ensure this is a depth texture + if (!isDepth(target, level)) + { + return NULL; + } + + return mTexStorage->getRenderTarget(target, level); +} + +int TextureD3D_Cube::targetToIndex(GLenum target) +{ + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1); + META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2); + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3); + META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4); + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5); + + return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X; +} + +void TextureD3D_Cube::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return; + } + + // do not attempt to create storage for nonexistant data + if (!isFaceLevelComplete(0, 0)) + { + return; + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + + setCompleteTexStorage(createCompleteStorage(createRenderTarget)); + ASSERT(mTexStorage); + + // flush image data to the storage + updateStorage(); +} + +TextureStorageInterfaceCube *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const +{ + GLsizei size = getBaseLevelWidth(); + + ASSERT(size > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1)); + + return new TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels); +} + +void TextureD3D_Cube::setCompleteTexStorage(TextureStorageInterfaceCube *newCompleteTexStorage) +{ + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + + if (mTexStorage && mTexStorage->isManaged()) + { + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + for (int level = 0; level < mTexStorage->getLevelCount(); level++) + { + mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level); + } + } + } + + mDirtyImages = true; +} + +void TextureD3D_Cube::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < storageLevels; level++) + { + if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level)) + { + updateStorageFaceLevel(face, level); + } + } + } +} + +bool TextureD3D_Cube::ensureRenderTarget() +{ + initializeStorage(true); + + if (getBaseLevelWidth() > 0) + { + ASSERT(mTexStorage); + if (!mTexStorage->isRenderTarget()) + { + TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true); + + if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage)) + { + delete newRenderTargetStorage; + return gl::error(GL_OUT_OF_MEMORY, false); + } + + setCompleteTexStorage(newRenderTargetStorage); + } + } + + return (mTexStorage && mTexStorage->isRenderTarget()); +} + +TextureStorageInterface *TextureD3D_Cube::getBaseLevelStorage() +{ + return mTexStorage; +} + +const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const +{ + // Note: if we are not cube-complete, there is no single base level image that can describe all + // cube faces, so this method is only well-defined for a cube-complete base level. + return mImageArray[0][0]; +} + +bool TextureD3D_Cube::isMipmapCubeComplete() const +{ + if (isImmutable()) + { + return true; + } + + if (!isCubeComplete()) + { + return false; + } + + int levelCount = mipLevels(); + + for (int face = 0; face < 6; face++) + { + for (int level = 1; level < levelCount; level++) + { + if (!isFaceLevelComplete(face, level)) + { + return false; + } + } + } + + return true; +} + +bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); +} + + +bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const +{ + ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); + + if (isImmutable()) + { + return true; + } + + int baseSize = getBaseLevelWidth(); + + if (baseSize <= 0) + { + return false; + } + + // "isCubeComplete" checks for base level completeness and we must call that + // to determine if any face at level 0 is complete. We omit that check here + // to avoid re-checking cube-completeness for every face at level 0. + if (level == 0) + { + return true; + } + + // Check that non-zero levels are consistent with the base level. + const ImageD3D *faceLevelImage = mImageArray[faceIndex][level]; + + if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) + { + return false; + } + + if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) + { + return false; + } + + return true; +} + +void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) +{ + ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); + ImageD3D *image = mImageArray[faceIndex][level]; + + if (image->isDirty()) + { + commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight()); + } +} + +void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height) +{ + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false); + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + width != storageWidth || + height != storageHeight || + internalformat != storageFormat) // Discard mismatched storage + { + for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + mImageArray[faceIndex][level]->markDirty(); + } + } + + SafeDelete(mTexStorage); + + mDirtyImages = true; + } + } +} + +void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + if (isValidFaceLevel(faceIndex, level)) + { + ImageD3D *image = mImageArray[faceIndex][level]; + if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height)) + image->markClean(); + } +} + + +TextureD3D_3D::TextureD3D_3D(Renderer *renderer) + : Texture3DImpl(), + TextureD3D(renderer), + mTexStorage(NULL) +{ + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage()); + } +} + +TextureD3D_3D::~TextureD3D_3D() +{ + SafeDelete(mTexStorage); + + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + delete mImageArray[i]; + } +} + +TextureD3D_3D *TextureD3D_3D::makeTextureD3D_3D(Texture3DImpl *texture) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_3D*, texture)); + return static_cast<TextureD3D_3D*>(texture); +} + +TextureStorageInterface *TextureD3D_3D::getNativeTexture() +{ + // ensure the underlying texture is created + initializeStorage(false); + + TextureStorageInterface *storage = getBaseLevelStorage(); + if (storage) + { + updateStorage(); + } + + return storage; +} + +Image *TextureD3D_3D::getImage(int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return mImageArray[level]; +} + +void TextureD3D_3D::setUsage(GLenum usage) +{ + mUsage = usage; +} + +void TextureD3D_3D::resetDirty() +{ + mDirtyImages = false; +} + +GLsizei TextureD3D_3D::getWidth(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getWidth(); + else + return 0; +} + +GLsizei TextureD3D_3D::getHeight(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getHeight(); + else + return 0; +} + +GLsizei TextureD3D_3D::getDepth(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getDepth(); + else + return 0; +} + +GLenum TextureD3D_3D::getInternalFormat(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getInternalFormat(); + else + return GL_NONE; +} + +bool TextureD3D_3D::isDepth(GLint level) const +{ + return gl::GetDepthBits(getInternalFormat(level)) > 0; +} + +void TextureD3D_3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +{ + GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat + : gl::GetSizedInternalFormat(format, type); + redefineImage(level, sizedInternalFormat, width, height, depth); + + bool fastUnpacked = false; + + // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer + if (isFastUnpackable(unpack, sizedInternalFormat)) + { + // Will try to create RT storage if it does not exist + RenderTarget *destRenderTarget = getRenderTarget(level); + gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); + + if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget)) + { + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; + } + } + + if (!fastUnpacked) + { + TextureD3D::setImage(unpack, type, pixels, mImageArray[level]); + } +} + +void TextureD3D_3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +{ + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(level, format, width, height, depth); + + TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]); +} + +void TextureD3D_3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +{ + bool fastUnpacked = false; + + // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer + if (isFastUnpackable(unpack, getInternalFormat(level))) + { + RenderTarget *destRenderTarget = getRenderTarget(level); + gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth); + + if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget)) + { + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; + } + } + + if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level])) + { + commitRect(level, xoffset, yoffset, zoffset, width, height, depth); + } +} + +void TextureD3D_3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) +{ + if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level])) + { + commitRect(level, xoffset, yoffset, zoffset, width, height, depth); + } +} + +void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +{ + // can only make our texture storage to a render target if level 0 is defined (with a width & height) and + // the current level we're copying to is defined (with appropriate format, width & height) + bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); + + if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) + { + mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source); + mDirtyImages = true; + } + else + { + ensureRenderTarget(); + + if (isValidLevel(level)) + { + updateStorageLevel(level); + + gl::Rectangle sourceRect; + sourceRect.x = x; + sourceRect.width = width; + sourceRect.y = y; + sourceRect.height = height; + + mRenderer->copyImage(source, sourceRect, + gl::GetFormat(getBaseLevelInternalFormat()), + xoffset, yoffset, zoffset, mTexStorage, level); + } + } +} + +void TextureD3D_3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +{ + for (int level = 0; level < levels; level++) + { + GLsizei levelWidth = std::max(1, width >> level); + GLsizei levelHeight = std::max(1, height >> level); + GLsizei levelDepth = std::max(1, depth >> level); + mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true); + } + + for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true); + } + + mImmutable = true; + + setCompleteTexStorage(new TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels)); +} + +bool TextureD3D_3D::isSamplerComplete(const gl::SamplerState &samplerState) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei depth = getBaseLevelDepth(); + + if (width <= 0 || height <= 0 || depth <= 0) + { + return false; + } + + // TODO(geofflang): use context's texture caps + if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(0)).filterable) + { + if (samplerState.magFilter != GL_NEAREST || + (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) + { + return false; + } + } + + if (IsMipmapFiltered(samplerState) && !isMipmapComplete()) + { + return false; + } + + return true; +} + +bool TextureD3D_3D::isMipmapComplete() const +{ + int levelCount = mipLevels(); + + for (int level = 0; level < levelCount; level++) + { + if (!isLevelComplete(level)) + { + return false; + } + } + + return true; +} + +void TextureD3D_3D::generateMipmaps() +{ + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + int levelCount = mipLevels(); + for (int level = 1; level < levelCount; level++) + { + redefineImage(level, getBaseLevelInternalFormat(), + std::max(getBaseLevelWidth() >> level, 1), + std::max(getBaseLevelHeight() >> level, 1), + std::max(getBaseLevelDepth() >> level, 1)); + } + + if (mTexStorage && mTexStorage->isRenderTarget()) + { + for (int level = 1; level < levelCount; level++) + { + mTexStorage->generateMipmap(level); + + mImageArray[level]->markClean(); + } + } + else + { + for (int level = 1; level < levelCount; level++) + { + mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]); + } + } +} + +unsigned int TextureD3D_3D::getRenderTargetSerial(GLint level, GLint layer) +{ + return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0); +} + +RenderTarget *TextureD3D_3D::getRenderTarget(GLint level) +{ + // ensure the underlying texture is created + if (!ensureRenderTarget()) + { + return NULL; + } + + updateStorageLevel(level); + + // ensure this is NOT a depth texture + if (isDepth(level)) + { + return NULL; + } + + return mTexStorage->getRenderTarget(level); +} + +RenderTarget *TextureD3D_3D::getRenderTarget(GLint level, GLint layer) +{ + // ensure the underlying texture is created + if (!ensureRenderTarget()) + { + return NULL; + } + + updateStorage(); + + // ensure this is NOT a depth texture + if (isDepth(level)) + { + return NULL; + } + + return mTexStorage->getRenderTarget(level, layer); +} + +RenderTarget *TextureD3D_3D::getDepthStencil(GLint level, GLint layer) +{ + // ensure the underlying texture is created + if (!ensureRenderTarget()) + { + return NULL; + } + + updateStorageLevel(level); + + // ensure this is a depth texture + if (!isDepth(level)) + { + return NULL; + } + + return mTexStorage->getRenderTarget(level, layer); +} + +void TextureD3D_3D::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return; + } + + // do not attempt to create storage for nonexistant data + if (!isLevelComplete(0)) + { + return; + } + + bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + + setCompleteTexStorage(createCompleteStorage(createRenderTarget)); + ASSERT(mTexStorage); + + // flush image data to the storage + updateStorage(); +} + +TextureStorageInterface3D *TextureD3D_3D::createCompleteStorage(bool renderTarget) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei depth = getBaseLevelDepth(); + + ASSERT(width > 0 && height > 0 && depth > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth)); + + return new TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels); +} + +void TextureD3D_3D::setCompleteTexStorage(TextureStorageInterface3D *newCompleteTexStorage) +{ + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + mDirtyImages = true; + + // We do not support managed 3D storage, as that is D3D9/ES2-only + ASSERT(!mTexStorage->isManaged()); +} + +void TextureD3D_3D::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int level = 0; level < storageLevels; level++) + { + if (mImageArray[level]->isDirty() && isLevelComplete(level)) + { + updateStorageLevel(level); + } + } +} + +bool TextureD3D_3D::ensureRenderTarget() +{ + initializeStorage(true); + + if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0) + { + ASSERT(mTexStorage); + if (!mTexStorage->isRenderTarget()) + { + TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true); + + if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage)) + { + delete newRenderTargetStorage; + return gl::error(GL_OUT_OF_MEMORY, false); + } + + setCompleteTexStorage(newRenderTargetStorage); + } + } + + return (mTexStorage && mTexStorage->isRenderTarget()); +} + +TextureStorageInterface *TextureD3D_3D::getBaseLevelStorage() +{ + return mTexStorage; +} + +const ImageD3D *TextureD3D_3D::getBaseLevelImage() const +{ + return mImageArray[0]; +} + +bool TextureD3D_3D::isValidLevel(int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); +} + +bool TextureD3D_3D::isLevelComplete(int level) const +{ + ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + + if (isImmutable()) + { + return true; + } + + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei depth = getBaseLevelDepth(); + + if (width <= 0 || height <= 0 || depth <= 0) + { + return false; + } + + if (level == 0) + { + return true; + } + + ImageD3D *levelImage = mImageArray[level]; + + if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) + { + return false; + } + + if (levelImage->getWidth() != std::max(1, width >> level)) + { + return false; + } + + if (levelImage->getHeight() != std::max(1, height >> level)) + { + return false; + } + + if (levelImage->getDepth() != std::max(1, depth >> level)) + { + return false; + } + + return true; +} + +void TextureD3D_3D::updateStorageLevel(int level) +{ + ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(isLevelComplete(level)); + + if (mImageArray[level]->isDirty()) + { + commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); + } +} + +void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +{ + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const int storageDepth = std::max(1, getBaseLevelDepth() >> level); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false); + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + width != storageWidth || + height != storageHeight || + depth != storageDepth || + internalformat != storageFormat) // Discard mismatched storage + { + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + + SafeDelete(mTexStorage); + mDirtyImages = true; + } + } +} + +void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) +{ + if (isValidLevel(level)) + { + ImageD3D *image = mImageArray[level]; + if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth)) + { + image->markClean(); + } + } +} + + +TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer) + : Texture2DArrayImpl(), + TextureD3D(renderer), + mTexStorage(NULL) +{ + for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) + { + mLayerCounts[level] = 0; + mImageArray[level] = NULL; + } +} + +TextureD3D_2DArray::~TextureD3D_2DArray() +{ + SafeDelete(mTexStorage); + + deleteImages(); +} + +TextureD3D_2DArray *TextureD3D_2DArray::makeTextureD3D_2DArray(Texture2DArrayImpl *texture) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_2DArray*, texture)); + return static_cast<TextureD3D_2DArray*>(texture); +} + +TextureStorageInterface *TextureD3D_2DArray::getNativeTexture() +{ + // ensure the underlying texture is created + initializeStorage(false); + + TextureStorageInterface *storage = getBaseLevelStorage(); + if (storage) + { + updateStorage(); + } + + return storage; +} + +Image *TextureD3D_2DArray::getImage(int level, int layer) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(layer < mLayerCounts[level]); + return mImageArray[level][layer]; +} + +GLsizei TextureD3D_2DArray::getLayerCount(int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return mLayerCounts[level]; +} + +void TextureD3D_2DArray::setUsage(GLenum usage) +{ + mUsage = usage; +} + +void TextureD3D_2DArray::resetDirty() +{ + mDirtyImages = false; +} + +GLsizei TextureD3D_2DArray::getWidth(GLint level) const +{ + return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0; +} + +GLsizei TextureD3D_2DArray::getHeight(GLint level) const +{ + return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0; +} + +GLsizei TextureD3D_2DArray::getLayers(GLint level) const +{ + return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0; +} + +GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const +{ + return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE; +} + +bool TextureD3D_2DArray::isDepth(GLint level) const +{ + return gl::GetDepthBits(getInternalFormat(level)) > 0; +} + +void TextureD3D_2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +{ + GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat + : gl::GetSizedInternalFormat(format, type); + redefineImage(level, sizedInternalFormat, width, height, depth); + + GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, width, height, unpack.alignment); + + for (int i = 0; i < depth; i++) + { + const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; + TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]); + } +} + +void TextureD3D_2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +{ + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(level, format, width, height, depth); + + GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1); + + for (int i = 0; i < depth; i++) + { + const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; + TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]); + } +} + +void TextureD3D_2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +{ + GLenum internalformat = getInternalFormat(level); + GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, width, height, unpack.alignment); + + for (int i = 0; i < depth; i++) + { + int layer = zoffset + i; + const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; + + if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer])) + { + commitRect(level, xoffset, yoffset, layer, width, height); + } + } +} + +void TextureD3D_2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) +{ + GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1); + + for (int i = 0; i < depth; i++) + { + int layer = zoffset + i; + const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; + + if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer])) + { + commitRect(level, xoffset, yoffset, layer, width, height); + } + } +} + +void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +{ + // can only make our texture storage to a render target if level 0 is defined (with a width & height) and + // the current level we're copying to is defined (with appropriate format, width & height) + bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); + + if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) + { + mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source); + mDirtyImages = true; + } + else + { + ensureRenderTarget(); + + if (isValidLevel(level)) + { + updateStorageLevel(level); + + gl::Rectangle sourceRect; + sourceRect.x = x; + sourceRect.width = width; + sourceRect.y = y; + sourceRect.height = height; + + mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0)), + xoffset, yoffset, zoffset, mTexStorage, level); + } + } +} + +void TextureD3D_2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +{ + deleteImages(); + + for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + GLsizei levelWidth = std::max(1, width >> level); + GLsizei levelHeight = std::max(1, height >> level); + + mLayerCounts[level] = (level < levels ? depth : 0); + + if (mLayerCounts[level] > 0) + { + // Create new images for this level + mImageArray[level] = new ImageD3D*[mLayerCounts[level]]; + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage()); + mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth, + levelHeight, 1, true); + } + } + } + + mImmutable = true; + setCompleteTexStorage(new TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels)); +} + +bool TextureD3D_2DArray::isSamplerComplete(const gl::SamplerState &samplerState) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei depth = getLayers(0); + + if (width <= 0 || height <= 0 || depth <= 0) + { + return false; + } + + // TODO(geofflang): use context's texture caps + if (!mRenderer->getRendererTextureCaps().get(getBaseLevelInternalFormat()).filterable) + { + if (samplerState.magFilter != GL_NEAREST || + (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) + { + return false; + } + } + + if (IsMipmapFiltered(samplerState) && !isMipmapComplete()) + { + return false; + } + + return true; +} + +bool TextureD3D_2DArray::isMipmapComplete() const +{ + int levelCount = mipLevels(); + + for (int level = 1; level < levelCount; level++) + { + if (!isLevelComplete(level)) + { + return false; + } + } + + return true; +} + +void TextureD3D_2DArray::generateMipmaps() +{ + int baseWidth = getBaseLevelWidth(); + int baseHeight = getBaseLevelHeight(); + int baseDepth = getBaseLevelDepth(); + GLenum baseFormat = getBaseLevelInternalFormat(); + + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + int levelCount = mipLevels(); + for (int level = 1; level < levelCount; level++) + { + redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth); + } + + if (mTexStorage && mTexStorage->isRenderTarget()) + { + for (int level = 1; level < levelCount; level++) + { + mTexStorage->generateMipmap(level); + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + mImageArray[level][layer]->markClean(); + } + } + } + else + { + for (int level = 1; level < levelCount; level++) + { + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]); + } + } + } +} + +unsigned int TextureD3D_2DArray::getRenderTargetSerial(GLint level, GLint layer) +{ + return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0); +} + +RenderTarget *TextureD3D_2DArray::getRenderTarget(GLint level, GLint layer) +{ + // ensure the underlying texture is created + if (!ensureRenderTarget()) + { + return NULL; + } + + updateStorageLevel(level); + + // ensure this is NOT a depth texture + if (isDepth(level)) + { + return NULL; + } + + return mTexStorage->getRenderTarget(level, layer); +} + +RenderTarget *TextureD3D_2DArray::getDepthStencil(GLint level, GLint layer) +{ + // ensure the underlying texture is created + if (!ensureRenderTarget()) + { + return NULL; + } + + updateStorageLevel(level); + + // ensure this is a depth texture + if (!isDepth(level)) + { + return NULL; + } + + return mTexStorage->getRenderTarget(level, layer); +} + +void TextureD3D_2DArray::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return; + } + + // do not attempt to create storage for nonexistant data + if (!isLevelComplete(0)) + { + return; + } + + bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + + setCompleteTexStorage(createCompleteStorage(createRenderTarget)); + ASSERT(mTexStorage); + + // flush image data to the storage + updateStorage(); +} + +TextureStorageInterface2DArray *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei depth = getLayers(0); + + ASSERT(width > 0 && height > 0 && depth > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); + + return new TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels); +} + +void TextureD3D_2DArray::setCompleteTexStorage(TextureStorageInterface2DArray *newCompleteTexStorage) +{ + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + mDirtyImages = true; + + // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only + ASSERT(!mTexStorage->isManaged()); +} + +void TextureD3D_2DArray::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int level = 0; level < storageLevels; level++) + { + if (isLevelComplete(level)) + { + updateStorageLevel(level); + } + } +} + +bool TextureD3D_2DArray::ensureRenderTarget() +{ + initializeStorage(true); + + if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0) + { + ASSERT(mTexStorage); + if (!mTexStorage->isRenderTarget()) + { + TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true); + + if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage)) + { + delete newRenderTargetStorage; + return gl::error(GL_OUT_OF_MEMORY, false); + } + + setCompleteTexStorage(newRenderTargetStorage); + } + } + + return (mTexStorage && mTexStorage->isRenderTarget()); +} + +const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const +{ + return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL); +} + +TextureStorageInterface *TextureD3D_2DArray::getBaseLevelStorage() +{ + return mTexStorage; +} + +bool TextureD3D_2DArray::isValidLevel(int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); +} + +bool TextureD3D_2DArray::isLevelComplete(int level) const +{ + ASSERT(level >= 0 && level < (int)ArraySize(mImageArray)); + + if (isImmutable()) + { + return true; + } + + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei layers = getLayers(0); + + if (width <= 0 || height <= 0 || layers <= 0) + { + return false; + } + + if (level == 0) + { + return true; + } + + if (getInternalFormat(level) != getInternalFormat(0)) + { + return false; + } + + if (getWidth(level) != std::max(1, width >> level)) + { + return false; + } + + if (getHeight(level) != std::max(1, height >> level)) + { + return false; + } + + if (getLayers(level) != layers) + { + return false; + } + + return true; +} + +void TextureD3D_2DArray::updateStorageLevel(int level) +{ + ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts)); + ASSERT(isLevelComplete(level)); + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL); + if (mImageArray[level][layer]->isDirty()) + { + commitRect(level, 0, 0, layer, getWidth(level), getHeight(level)); + } + } +} + +void TextureD3D_2DArray::deleteImages() +{ + for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) + { + for (int layer = 0; layer < mLayerCounts[level]; ++layer) + { + delete mImageArray[level][layer]; + } + delete[] mImageArray[level]; + mImageArray[level] = NULL; + mLayerCounts[level] = 0; + } +} + +void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +{ + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const int storageDepth = getLayers(0); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + delete mImageArray[level][layer]; + } + delete[] mImageArray[level]; + mImageArray[level] = NULL; + mLayerCounts[level] = depth; + + if (depth > 0) + { + mImageArray[level] = new ImageD3D*[depth](); + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage()); + mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false); + } + } + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + width != storageWidth || + height != storageHeight || + depth != storageDepth || + internalformat != storageFormat) // Discard mismatched storage + { + for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + mImageArray[level][layer]->markDirty(); + } + } + + delete mTexStorage; + mTexStorage = NULL; + mDirtyImages = true; + } + } +} + +void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height) +{ + if (isValidLevel(level) && layerTarget < getLayers(level)) + { + ImageD3D *image = mImageArray[level][layerTarget]; + if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height)) + { + image->markClean(); + } + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.h new file mode 100644 index 0000000000..4a1737a9c4 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.h @@ -0,0 +1,343 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureD3D.h: Implementations of the Texture interfaces shared betweeen the D3D backends. + +#ifndef LIBGLESV2_RENDERER_TEXTURED3D_H_ +#define LIBGLESV2_RENDERER_TEXTURED3D_H_ + +#include "libGLESv2/renderer/TextureImpl.h" +#include "libGLESv2/angletypes.h" +#include "libGLESv2/constants.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ + +class Image; +class ImageD3D; +class Renderer; +class TextureStorageInterface; +class TextureStorageInterface2D; +class TextureStorageInterfaceCube; +class TextureStorageInterface3D; +class TextureStorageInterface2DArray; + +bool IsMipmapFiltered(const gl::SamplerState &samplerState); + +class TextureD3D +{ + public: + TextureD3D(Renderer *renderer); + virtual ~TextureD3D(); + + GLint getBaseLevelWidth() const; + GLint getBaseLevelHeight() const; + GLint getBaseLevelDepth() const; + GLenum getBaseLevelInternalFormat() const; + + bool isImmutable() const { return mImmutable; } + + protected: + void setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image); + bool subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, Image *image); + void setCompressedImage(GLsizei imageSize, const void *pixels, Image *image); + bool subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLsizei imageSize, const void *pixels, Image *image); + bool isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat); + bool fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea, + GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget); + + GLint creationLevels(GLsizei width, GLsizei height, GLsizei depth) const; + int mipLevels() const; + + Renderer *mRenderer; + + GLenum mUsage; + + bool mDirtyImages; + + bool mImmutable; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureD3D); + + virtual TextureStorageInterface *getBaseLevelStorage() = 0; + virtual const ImageD3D *getBaseLevelImage() const = 0; +}; + +class TextureD3D_2D : public Texture2DImpl, public TextureD3D +{ + public: + TextureD3D_2D(Renderer *renderer); + virtual ~TextureD3D_2D(); + + static TextureD3D_2D *makeTextureD3D_2D(Texture2DImpl *texture); + + virtual TextureStorageInterface *getNativeTexture(); + + virtual Image *getImage(int level) const; + + virtual void setUsage(GLenum usage); + virtual bool hasDirtyImages() const { return mDirtyImages; } + virtual void resetDirty(); + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLenum getInternalFormat(GLint level) const; + GLenum getActualFormat(GLint level) const; + bool isDepth(GLint level) const; + + virtual void setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); + virtual void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); + virtual void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); + + virtual bool isSamplerComplete(const gl::SamplerState &samplerState) const; + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); + + virtual void generateMipmaps(); + + virtual unsigned int getRenderTargetSerial(GLint level); + + virtual RenderTarget *getRenderTarget(GLint level); + virtual RenderTarget *getDepthSencil(GLint level); + + private: + DISALLOW_COPY_AND_ASSIGN(TextureD3D_2D); + + void initializeStorage(bool renderTarget); + TextureStorageInterface2D *createCompleteStorage(bool renderTarget) const; + void setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage); + + void updateStorage(); + bool ensureRenderTarget(); + virtual TextureStorageInterface *getBaseLevelStorage(); + virtual const ImageD3D *getBaseLevelImage() const; + + bool isMipmapComplete() const; + bool isValidLevel(int level) const; + bool isLevelComplete(int level) const; + + void updateStorageLevel(int level); + + virtual void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height); + void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + + TextureStorageInterface2D *mTexStorage; + ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureD3D_Cube : public TextureCubeImpl, public TextureD3D +{ + public: + TextureD3D_Cube(Renderer *renderer); + virtual ~TextureD3D_Cube(); + + static TextureD3D_Cube *makeTextureD3D_Cube(TextureCubeImpl *texture); + + virtual TextureStorageInterface *getNativeTexture(); + + virtual Image *getImage(GLenum target, int level) const; + + virtual void setUsage(GLenum usage); + virtual bool hasDirtyImages() const { return mDirtyImages; } + virtual void resetDirty(); + + GLenum getInternalFormat(GLenum target, GLint level) const; + bool isDepth(GLenum target, GLint level) const; + + virtual void setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); + virtual void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); + virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual void storage(GLsizei levels, GLenum internalformat, GLsizei size); + + virtual bool isSamplerComplete(const gl::SamplerState &samplerState) const; + virtual bool isCubeComplete() const; + + virtual void generateMipmaps(); + + virtual unsigned int getRenderTargetSerial(GLenum target, GLint level); + + virtual RenderTarget *getRenderTarget(GLenum target, GLint level); + virtual RenderTarget *getDepthStencil(GLenum target, GLint level); + + static int targetToIndex(GLenum target); + + private: + DISALLOW_COPY_AND_ASSIGN(TextureD3D_Cube); + + void initializeStorage(bool renderTarget); + TextureStorageInterfaceCube *createCompleteStorage(bool renderTarget) const; + void setCompleteTexStorage(TextureStorageInterfaceCube *newCompleteTexStorage); + + void updateStorage(); + bool ensureRenderTarget(); + virtual TextureStorageInterface *getBaseLevelStorage(); + virtual const ImageD3D *getBaseLevelImage() const; + + bool isMipmapCubeComplete() const; + bool isValidFaceLevel(int faceIndex, int level) const; + bool isFaceLevelComplete(int faceIndex, int level) const; + void updateStorageFaceLevel(int faceIndex, int level); + + void redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height); + void commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + + ImageD3D *mImageArray[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + TextureStorageInterfaceCube *mTexStorage; +}; + +class TextureD3D_3D : public Texture3DImpl, public TextureD3D +{ + public: + TextureD3D_3D(Renderer *renderer); + virtual ~TextureD3D_3D(); + + static TextureD3D_3D *makeTextureD3D_3D(Texture3DImpl *texture); + + virtual TextureStorageInterface *getNativeTexture(); + + virtual Image *getImage(int level) const; + + virtual void setUsage(GLenum usage); + virtual bool hasDirtyImages() const { return mDirtyImages; } + virtual void resetDirty(); + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLsizei getDepth(GLint level) const; + GLenum getInternalFormat(GLint level) const; + bool isDepth(GLint level) const; + + virtual void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels); + virtual void subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + + virtual bool isSamplerComplete(const gl::SamplerState &samplerState) const; + virtual bool isMipmapComplete() const; + + virtual void generateMipmaps(); + + virtual unsigned int getRenderTargetSerial(GLint level, GLint layer); + + virtual RenderTarget *getRenderTarget(GLint level); + virtual RenderTarget *getRenderTarget(GLint level, GLint layer); + virtual RenderTarget *getDepthStencil(GLint level, GLint layer); + + private: + DISALLOW_COPY_AND_ASSIGN(TextureD3D_3D); + + virtual void initializeStorage(bool renderTarget); + TextureStorageInterface3D *createCompleteStorage(bool renderTarget) const; + void setCompleteTexStorage(TextureStorageInterface3D *newCompleteTexStorage); + + void updateStorage(); + bool ensureRenderTarget(); + virtual TextureStorageInterface *getBaseLevelStorage(); + virtual const ImageD3D *getBaseLevelImage() const; + + bool isValidLevel(int level) const; + bool isLevelComplete(int level) const; + void updateStorageLevel(int level); + + void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + void commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); + + ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + TextureStorageInterface3D *mTexStorage; +}; + +class TextureD3D_2DArray : public Texture2DArrayImpl, public TextureD3D +{ + public: + TextureD3D_2DArray(Renderer *renderer); + virtual ~TextureD3D_2DArray(); + + static TextureD3D_2DArray *makeTextureD3D_2DArray(Texture2DArrayImpl *texture); + + virtual TextureStorageInterface *getNativeTexture(); + + virtual Image *getImage(int level, int layer) const; + virtual GLsizei getLayerCount(int level) const; + + virtual void setUsage(GLenum usage); + virtual bool hasDirtyImages() const { return mDirtyImages; } + virtual void resetDirty(); + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLsizei getLayers(GLint level) const; + GLenum getInternalFormat(GLint level) const; + bool isDepth(GLint level) const; + + virtual void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels); + virtual void subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + + virtual bool isSamplerComplete(const gl::SamplerState &samplerState) const; + virtual bool isMipmapComplete() const; + + virtual void generateMipmaps(); + + virtual unsigned int getRenderTargetSerial(GLint level, GLint layer); + + virtual RenderTarget *getRenderTarget(GLint level, GLint layer); + virtual RenderTarget *getDepthStencil(GLint level, GLint layer); + + private: + DISALLOW_COPY_AND_ASSIGN(TextureD3D_2DArray); + + virtual void initializeStorage(bool renderTarget); + TextureStorageInterface2DArray *createCompleteStorage(bool renderTarget) const; + void setCompleteTexStorage(TextureStorageInterface2DArray *newCompleteTexStorage); + + void updateStorage(); + bool ensureRenderTarget(); + virtual TextureStorageInterface *getBaseLevelStorage(); + virtual const ImageD3D *getBaseLevelImage() const; + + bool isValidLevel(int level) const; + bool isLevelComplete(int level) const; + void updateStorageLevel(int level); + + void deleteImages(); + void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + void commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height); + + // Storing images as an array of single depth textures since D3D11 treats each array level of a + // Texture2D object as a separate subresource. Each layer would have to be looped over + // to update all the texture layers since they cannot all be updated at once and it makes the most + // sense for the Image class to not have to worry about layer subresource as well as mip subresources. + GLsizei mLayerCounts[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + ImageD3D **mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + TextureStorageInterface2DArray *mTexStorage; +}; + +} + +#endif // LIBGLESV2_RENDERER_TEXTURED3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.cpp new file mode 100644 index 0000000000..846586984c --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.cpp @@ -0,0 +1,181 @@ +#include "precompiled.h" +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage.cpp: Implements the abstract rx::TextureStorageInterface class and its concrete derived +// classes TextureStorageInterface2D and TextureStorageInterfaceCube, which act as the interface to the +// GPU-side texture. + +#include "libGLESv2/renderer/d3d/TextureStorage.h" +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/Texture.h" + +#include "common/debug.h" +#include "common/mathutil.h" + +namespace rx +{ +unsigned int TextureStorageInterface::mCurrentTextureSerial = 1; + +TextureStorageInterface::TextureStorageInterface() + : mTextureSerial(issueTextureSerial()), + mInstance(NULL) +{ +} + +TextureStorageInterface::~TextureStorageInterface() +{ + delete mInstance; +} + +bool TextureStorageInterface::isRenderTarget() const +{ + return mInstance->isRenderTarget(); +} + +bool TextureStorageInterface::isManaged() const +{ + return mInstance->isManaged(); +} + +unsigned int TextureStorageInterface::getTextureSerial() const +{ + return mTextureSerial; +} + +unsigned int TextureStorageInterface::issueTextureSerial() +{ + return mCurrentTextureSerial++; +} + +int TextureStorageInterface::getTopLevel() const +{ + return mInstance->getTopLevel(); +} + +int TextureStorageInterface::getLevelCount() const +{ + return mInstance->getLevelCount(); +} + +TextureStorageInterface2D::TextureStorageInterface2D(Renderer *renderer, SwapChain *swapchain) +{ + mFirstRenderTargetSerial = gl::RenderbufferStorage::issueSerials(1); + + mInstance = renderer->createTextureStorage2D(swapchain); +} + +TextureStorageInterface2D::TextureStorageInterface2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) +{ + mInstance = renderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels); + mFirstRenderTargetSerial = gl::RenderbufferStorage::issueSerials(static_cast<GLuint>(mInstance->getLevelCount())); +} + +TextureStorageInterface2D::~TextureStorageInterface2D() +{ +} + +RenderTarget *TextureStorageInterface2D::getRenderTarget(GLint level) const +{ + return mInstance->getRenderTarget(level); +} + +void TextureStorageInterface2D::generateMipmap(int level) +{ + mInstance->generateMipmap(level); +} + +unsigned int TextureStorageInterface2D::getRenderTargetSerial(GLint level) const +{ + return mFirstRenderTargetSerial + level; +} + +TextureStorageInterfaceCube::TextureStorageInterfaceCube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels) +{ + mInstance = renderer->createTextureStorageCube(internalformat, renderTarget, size, levels); + mFirstRenderTargetSerial = gl::RenderbufferStorage::issueSerials(static_cast<GLuint>(mInstance->getLevelCount() * 6)); +} + +TextureStorageInterfaceCube::~TextureStorageInterfaceCube() +{ +} + +RenderTarget *TextureStorageInterfaceCube::getRenderTarget(GLenum faceTarget, GLint level) const +{ + return mInstance->getRenderTargetFace(faceTarget, level); +} + +void TextureStorageInterfaceCube::generateMipmap(int faceIndex, int level) +{ + mInstance->generateMipmap(faceIndex, level); +} + +unsigned int TextureStorageInterfaceCube::getRenderTargetSerial(GLenum target, GLint level) const +{ + return mFirstRenderTargetSerial + (level * 6) + TextureD3D_Cube::targetToIndex(target); +} + +TextureStorageInterface3D::TextureStorageInterface3D(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + + mInstance = renderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels); + mFirstRenderTargetSerial = gl::RenderbufferStorage::issueSerials(static_cast<GLuint>(mInstance->getLevelCount() * depth)); +} + +TextureStorageInterface3D::~TextureStorageInterface3D() +{ +} + +void TextureStorageInterface3D::generateMipmap(int level) +{ + mInstance->generateMipmap(level); +} + +RenderTarget *TextureStorageInterface3D::getRenderTarget(GLint level) const +{ + return mInstance->getRenderTarget(level); +} + +RenderTarget *TextureStorageInterface3D::getRenderTarget(GLint level, GLint layer) const +{ + return mInstance->getRenderTargetLayer(level, layer); +} + +unsigned int TextureStorageInterface3D::getRenderTargetSerial(GLint level, GLint layer) const +{ + return mFirstRenderTargetSerial + static_cast<unsigned int>((layer * mInstance->getLevelCount()) + level); +} + +TextureStorageInterface2DArray::TextureStorageInterface2DArray(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + mInstance = renderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels); + mFirstRenderTargetSerial = gl::RenderbufferStorage::issueSerials(static_cast<GLuint>(mInstance->getLevelCount() * depth)); +} + +TextureStorageInterface2DArray::~TextureStorageInterface2DArray() +{ +} + +void TextureStorageInterface2DArray::generateMipmap(int level) +{ + mInstance->generateMipmap(level); +} + +RenderTarget *TextureStorageInterface2DArray::getRenderTarget(GLint level, GLint layer) const +{ + return mInstance->getRenderTargetLayer(level, layer); +} + +unsigned int TextureStorageInterface2DArray::getRenderTargetSerial(GLint level, GLint layer) const +{ + return mFirstRenderTargetSerial + static_cast<unsigned int>((layer * mInstance->getLevelCount()) + level); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.h new file mode 100644 index 0000000000..0a212e16f2 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.h @@ -0,0 +1,145 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage.h: Defines the abstract rx::TextureStorageInterface class and its concrete derived +// classes TextureStorageInterface2D and TextureStorageInterfaceCube, which act as the interface to the +// GPU-side texture. + +#ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ +#define LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ + +#include "common/debug.h" + +namespace rx +{ +class Renderer; +class SwapChain; +class RenderTarget; + +class TextureStorage +{ + public: + TextureStorage() {}; + virtual ~TextureStorage() {}; + + virtual int getTopLevel() const = 0; + virtual bool isRenderTarget() const = 0; + virtual bool isManaged() const = 0; + virtual int getLevelCount() const = 0; + + virtual RenderTarget *getRenderTarget(int level) = 0; + virtual RenderTarget *getRenderTargetFace(GLenum faceTarget, int level) = 0; + virtual RenderTarget *getRenderTargetLayer(int mipLevel, int layer) = 0; + virtual void generateMipmap(int level) = 0; + virtual void generateMipmap(int face, int level) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage); + +}; + +class TextureStorageInterface +{ + public: + TextureStorageInterface(); + virtual ~TextureStorageInterface(); + + TextureStorage *getStorageInstance() { return mInstance; } + + unsigned int getTextureSerial() const; + + virtual int getTopLevel() const; + virtual bool isRenderTarget() const; + virtual bool isManaged() const; + virtual int getLevelCount() const; + + protected: + TextureStorage *mInstance; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorageInterface); + + const unsigned int mTextureSerial; + static unsigned int issueTextureSerial(); + + static unsigned int mCurrentTextureSerial; +}; + +class TextureStorageInterface2D : public TextureStorageInterface +{ + public: + TextureStorageInterface2D(Renderer *renderer, SwapChain *swapchain); + TextureStorageInterface2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + virtual ~TextureStorageInterface2D(); + + void generateMipmap(int level); + RenderTarget *getRenderTarget(GLint level) const; + + unsigned int getRenderTargetSerial(GLint level) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorageInterface2D); + + unsigned int mFirstRenderTargetSerial; +}; + +class TextureStorageInterfaceCube : public TextureStorageInterface +{ + public: + TextureStorageInterfaceCube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels); + virtual ~TextureStorageInterfaceCube(); + + void generateMipmap(int faceIndex, int level); + RenderTarget *getRenderTarget(GLenum faceTarget, GLint level) const; + + virtual unsigned int getRenderTargetSerial(GLenum target, GLint level) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorageInterfaceCube); + + unsigned int mFirstRenderTargetSerial; +}; + +class TextureStorageInterface3D : public TextureStorageInterface +{ + public: + TextureStorageInterface3D(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual ~TextureStorageInterface3D(); + + void generateMipmap(int level); + RenderTarget *getRenderTarget(GLint level) const; + RenderTarget *getRenderTarget(GLint level, GLint layer) const; + + virtual unsigned int getRenderTargetSerial(GLint level, GLint layer) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorageInterface3D); + + unsigned int mFirstRenderTargetSerial; +}; + +class TextureStorageInterface2DArray : public TextureStorageInterface +{ + public: + TextureStorageInterface2DArray(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual ~TextureStorageInterface2DArray(); + + void generateMipmap(int level); + RenderTarget *getRenderTarget(GLint level, GLint layer) const; + + virtual unsigned int getRenderTargetSerial(GLint level, GLint layer) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorageInterface2DArray); + + unsigned int mFirstRenderTargetSerial; +}; + +} + +#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/VertexBuffer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.cpp index a073d95033..901ca196a8 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/VertexBuffer.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.cpp @@ -8,9 +8,11 @@ // VertexBuffer.cpp: Defines the abstract VertexBuffer class and VertexBufferInterface // class with derivations, classes that perform graphics API agnostic vertex buffer operations. -#include "libGLESv2/renderer/VertexBuffer.h" +#include "libGLESv2/renderer/d3d/VertexBuffer.h" #include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/Context.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/renderer/d3d/BufferD3D.h" +#include "common/mathutil.h" namespace rx { @@ -87,8 +89,8 @@ bool VertexBufferInterface::discard() return mVertexBuffer->discard(); } -bool VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances, - unsigned int *outStreamOffset) +bool VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) { unsigned int spaceRequired; if (!mVertexBuffer->getSpaceRequired(attrib, count, instances, &spaceRequired)) @@ -107,7 +109,7 @@ bool VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &att } mReservedSpace = 0; - if (!mVertexBuffer->storeVertexAttributes(attrib, start, count, instances, mWritePosition)) + if (!mVertexBuffer->storeVertexAttributes(attrib, currentValue, start, count, instances, mWritePosition)) { return false; } @@ -119,73 +121,73 @@ bool VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &att mWritePosition += spaceRequired; + // Align to 16-byte boundary + mWritePosition = rx::roundUp(mWritePosition, 16u); + return true; } -bool VertexBufferInterface::storeRawData(const void* data, unsigned int size, unsigned int *outStreamOffset) +bool VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances) { - if (mWritePosition + size < mWritePosition) - { - return false; - } - - if (!reserveSpace(mReservedSpace)) + unsigned int requiredSpace; + if (!mVertexBuffer->getSpaceRequired(attrib, count, instances, &requiredSpace)) { return false; } - mReservedSpace = 0; - if (!mVertexBuffer->storeRawData(data, size, mWritePosition)) + // Protect against integer overflow + if (mReservedSpace + requiredSpace < mReservedSpace) { - return false; + return false; } - if (outStreamOffset) - { - *outStreamOffset = mWritePosition; - } + mReservedSpace += requiredSpace; - mWritePosition += size; + // Align to 16-byte boundary + mReservedSpace = rx::roundUp(mReservedSpace, 16u); return true; } -bool VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances) +VertexBuffer* VertexBufferInterface::getVertexBuffer() const { - unsigned int requiredSpace; - if (!mVertexBuffer->getSpaceRequired(attribute, count, instances, &requiredSpace)) + return mVertexBuffer; +} + +bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue) const +{ + gl::Buffer *buffer = attrib.buffer.get(); + BufferD3D *storage = buffer ? BufferD3D::makeBufferD3D(buffer->getImplementation()) : NULL; + + if (!storage || !storage->supportsDirectBinding()) { return false; } - // Protect against integer overflow - if (mReservedSpace + requiredSpace < mReservedSpace) + // Alignment restrictions: In D3D, vertex data must be aligned to + // the format stride, or to a 4-byte boundary, whichever is smaller. + // (Undocumented, and experimentally confirmed) + size_t alignment = 4; + bool requiresConversion = false; + + if (attrib.type != GL_FLOAT) { - return false; - } + gl::VertexFormat vertexFormat(attrib, currentValue.Type); - mReservedSpace += requiredSpace; - return true; -} + unsigned int outputElementSize; + getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); + alignment = std::min<size_t>(outputElementSize, 4); -bool VertexBufferInterface::reserveRawDataSpace(unsigned int size) -{ - // Protect against integer overflow - if (mReservedSpace + size < mReservedSpace) - { - return false; + requiresConversion = (mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) != 0; } - mReservedSpace += size; - return true; -} + bool isAligned = (static_cast<size_t>(ComputeVertexAttributeStride(attrib)) % alignment == 0) && + (static_cast<size_t>(attrib.offset) % alignment == 0); -VertexBuffer* VertexBufferInterface::getVertexBuffer() const -{ - return mVertexBuffer; + return !requiresConversion && isAligned; } - StreamingVertexBufferInterface::StreamingVertexBufferInterface(rx::Renderer *renderer, std::size_t initialSize) : VertexBufferInterface(renderer, true) { setBufferSize(initialSize); @@ -224,16 +226,18 @@ StaticVertexBufferInterface::~StaticVertexBufferInterface() { } -bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attribute, unsigned int *outStreamOffset) +bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attrib, unsigned int *outStreamOffset) { for (unsigned int element = 0; element < mCache.size(); element++) { - if (mCache[element].type == attribute.mType && - mCache[element].size == attribute.mSize && - mCache[element].stride == attribute.stride() && - mCache[element].normalized == attribute.mNormalized) + if (mCache[element].type == attrib.type && + mCache[element].size == attrib.size && + mCache[element].stride == ComputeVertexAttributeStride(attrib) && + mCache[element].normalized == attrib.normalized && + mCache[element].pureInteger == attrib.pureInteger) { - if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride()) + size_t offset = (static_cast<size_t>(attrib.offset) % ComputeVertexAttributeStride(attrib)); + if (mCache[element].attributeOffset == offset) { if (outStreamOffset) { @@ -266,14 +270,14 @@ bool StaticVertexBufferInterface::reserveSpace(unsigned int size) } } -bool StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances, - unsigned int *outStreamOffset) +bool StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) { unsigned int streamOffset; - if (VertexBufferInterface::storeVertexAttributes(attrib, start, count, instances, &streamOffset)) + if (VertexBufferInterface::storeVertexAttributes(attrib, currentValue, start, count, instances, &streamOffset)) { - int attributeOffset = attrib.mOffset % attrib.stride(); - VertexElement element = { attrib.mType, attrib.mSize, attrib.stride(), attrib.mNormalized, attributeOffset, streamOffset }; + size_t attributeOffset = static_cast<size_t>(attrib.offset) % ComputeVertexAttributeStride(attrib); + VertexElement element = { attrib.type, attrib.size, ComputeVertexAttributeStride(attrib), attrib.normalized, attrib.pureInteger, attributeOffset, streamOffset }; mCache.push_back(element); if (outStreamOffset) diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/VertexBuffer.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.h index cbafdd20f6..c5022d8c9c 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/VertexBuffer.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.h @@ -14,7 +14,8 @@ namespace gl { -class VertexAttribute; +struct VertexAttribute; +struct VertexAttribCurrentValueData; } namespace rx @@ -29,15 +30,11 @@ class VertexBuffer virtual bool initialize(unsigned int size, bool dynamicUsage) = 0; - virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, - GLsizei instances, unsigned int offset) = 0; - virtual bool storeRawData(const void* data, unsigned int size, unsigned int offset) = 0; - + virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) = 0; virtual bool getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const = 0; - virtual bool requiresConversion(const gl::VertexAttribute &attrib) const = 0; - virtual unsigned int getBufferSize() const = 0; virtual bool setBufferSize(unsigned int size) = 0; virtual bool discard() = 0; @@ -61,15 +58,16 @@ class VertexBufferInterface virtual ~VertexBufferInterface(); bool reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances); - bool reserveRawDataSpace(unsigned int size); unsigned int getBufferSize() const; unsigned int getSerial() const; - virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances, - unsigned int *outStreamOffset); - virtual bool storeRawData(const void* data, unsigned int size, unsigned int *outStreamOffset); + virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset); + + bool directStoragePossible(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue) const; VertexBuffer* getVertexBuffer() const; @@ -111,10 +109,10 @@ class StaticVertexBufferInterface : public VertexBufferInterface explicit StaticVertexBufferInterface(rx::Renderer *renderer); ~StaticVertexBufferInterface(); - bool storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances, - unsigned int *outStreamOffset); + bool storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset); - bool lookupAttribute(const gl::VertexAttribute &attribute, unsigned int* outStreamOffset); + bool lookupAttribute(const gl::VertexAttribute &attribute, unsigned int* outStreamFffset); protected: bool reserveSpace(unsigned int size); @@ -123,10 +121,11 @@ class StaticVertexBufferInterface : public VertexBufferInterface struct VertexElement { GLenum type; - GLint size; - GLsizei stride; + GLuint size; + GLuint stride; bool normalized; - int attributeOffset; + bool pureInteger; + size_t attributeOffset; unsigned int streamOffset; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/VertexDataManager.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp index 8034aed8c9..fc2b8ff0df 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/VertexDataManager.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp @@ -8,13 +8,14 @@ // VertexDataManager.h: Defines the VertexDataManager, a class that // runs the Buffer translation process. -#include "libGLESv2/renderer/VertexDataManager.h" -#include "libGLESv2/renderer/BufferStorage.h" +#include "libGLESv2/renderer/d3d/VertexDataManager.h" +#include "libGLESv2/renderer/d3d/BufferD3D.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/renderer/VertexBuffer.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/renderer/d3d/VertexBuffer.h" +#include "libGLESv2/renderer/Renderer.h" namespace { @@ -26,7 +27,7 @@ namespace namespace rx { -static int elementsInBuffer(const gl::VertexAttribute &attribute, unsigned int size) +static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size) { // Size cannot be larger than a GLsizei if (size > static_cast<unsigned int>(std::numeric_limits<int>::max())) @@ -34,19 +35,19 @@ static int elementsInBuffer(const gl::VertexAttribute &attribute, unsigned int s size = static_cast<unsigned int>(std::numeric_limits<int>::max()); } - GLsizei stride = attribute.stride(); - return (size - attribute.mOffset % stride + (stride - attribute.typeSize())) / stride; + GLsizei stride = ComputeVertexAttributeStride(attrib); + return (size - attrib.offset % stride + (stride - ComputeVertexAttributeTypeSize(attrib))) / stride; } -static int StreamingBufferElementCount(const gl::VertexAttribute &attribute, int vertexDrawCount, int instanceDrawCount) +static int StreamingBufferElementCount(const gl::VertexAttribute &attrib, int vertexDrawCount, int instanceDrawCount) { // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices. // // A vertex attribute with a positive divisor loads one instanced vertex for every set of // non-instanced vertices, and the instanced vertex index advances once every "mDivisor" instances. - if (instanceDrawCount > 0 && attribute.mDivisor > 0) + if (instanceDrawCount > 0 && attrib.divisor > 0) { - return instanceDrawCount / attribute.mDivisor; + return instanceDrawCount / attrib.divisor; } return vertexDrawCount; @@ -56,10 +57,11 @@ VertexDataManager::VertexDataManager(Renderer *renderer) : mRenderer(renderer) { for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { - mCurrentValue[i][0] = std::numeric_limits<float>::quiet_NaN(); - mCurrentValue[i][1] = std::numeric_limits<float>::quiet_NaN(); - mCurrentValue[i][2] = std::numeric_limits<float>::quiet_NaN(); - mCurrentValue[i][3] = std::numeric_limits<float>::quiet_NaN(); + mCurrentValue[i].FloatValues[0] = std::numeric_limits<float>::quiet_NaN(); + mCurrentValue[i].FloatValues[1] = std::numeric_limits<float>::quiet_NaN(); + mCurrentValue[i].FloatValues[2] = std::numeric_limits<float>::quiet_NaN(); + mCurrentValue[i].FloatValues[3] = std::numeric_limits<float>::quiet_NaN(); + mCurrentValue[i].Type = GL_FLOAT; mCurrentValueBuffer[i] = NULL; mCurrentValueOffsets[i] = 0; } @@ -82,17 +84,8 @@ VertexDataManager::~VertexDataManager() } } -static bool directStoragePossible(VertexBufferInterface* vb, const gl::VertexAttribute& attrib) -{ - gl::Buffer *buffer = attrib.mBoundBuffer.get(); - BufferStorage *storage = buffer ? buffer->getStorage() : NULL; - - const bool isAligned = (attrib.stride() % 4 == 0) && (attrib.mOffset % 4 == 0); - - return storage && storage->supportsDirectBinding() && !vb->getVertexBuffer()->requiresConversion(attrib) && isAligned; -} - -GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances) +GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], const gl::VertexAttribCurrentValueData currentValues[], + gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances) { if (!mStreamingBuffer) { @@ -107,15 +100,20 @@ GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], // Invalidate static buffers that don't contain matching attributes for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { - if (translated[i].active && attribs[i].mArrayEnabled) + if (translated[i].active && attribs[i].enabled) { - gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); - StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; + gl::Buffer *buffer = attribs[i].buffer.get(); - if (staticBuffer && staticBuffer->getBufferSize() > 0 && !staticBuffer->lookupAttribute(attribs[i], NULL) && - !directStoragePossible(staticBuffer, attribs[i])) + if (buffer) { - buffer->invalidateStaticData(); + BufferD3D *bufferImpl = BufferD3D::makeBufferD3D(buffer->getImplementation()); + StaticVertexBufferInterface *staticBuffer = bufferImpl->getStaticVertexBuffer(); + + if (staticBuffer && staticBuffer->getBufferSize() > 0 && !staticBuffer->lookupAttribute(attribs[i], NULL) && + !staticBuffer->directStoragePossible(attribs[i], currentValues[i])) + { + bufferImpl->invalidateStaticData(); + } } } } @@ -123,19 +121,20 @@ GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], // Reserve the required space in the buffers for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { - if (translated[i].active && attribs[i].mArrayEnabled) + if (translated[i].active && attribs[i].enabled) { - gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); - StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; + gl::Buffer *buffer = attribs[i].buffer.get(); + BufferD3D *bufferImpl = buffer ? BufferD3D::makeBufferD3D(buffer->getImplementation()) : NULL; + StaticVertexBufferInterface *staticBuffer = bufferImpl ? bufferImpl->getStaticVertexBuffer() : NULL; VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); - if (!directStoragePossible(vertexBuffer, attribs[i])) + if (!vertexBuffer->directStoragePossible(attribs[i], currentValues[i])) { if (staticBuffer) { if (staticBuffer->getBufferSize() == 0) { - int totalCount = elementsInBuffer(attribs[i], buffer->size()); + int totalCount = ElementsInBuffer(attribs[i], bufferImpl->getSize()); if (!staticBuffer->reserveVertexSpace(attribs[i], totalCount, 0)) { return GL_OUT_OF_MEMORY; @@ -146,9 +145,9 @@ GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], { int totalCount = StreamingBufferElementCount(attribs[i], count, instances); - // Undefined behaviour: + // [OpenGL ES 3.0.2] section 2.9.4 page 40: // We can return INVALID_OPERATION if our vertex attribute does not have enough backing data. - if (buffer && elementsInBuffer(attribs[i], buffer->size()) < totalCount) + if (bufferImpl && ElementsInBuffer(attribs[i], bufferImpl->getSize()) < totalCount) { return GL_INVALID_OPERATION; } @@ -167,31 +166,29 @@ GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], { if (translated[i].active) { - if (attribs[i].mArrayEnabled) + if (attribs[i].enabled) { - gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); + gl::Buffer *buffer = attribs[i].buffer.get(); - if (!buffer && attribs[i].mPointer == NULL) + if (!buffer && attribs[i].pointer == NULL) { // This is an application error that would normally result in a crash, but we catch it and return an error ERR("An enabled vertex array has no buffer and no pointer."); return GL_INVALID_OPERATION; } - StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; + BufferD3D *storage = buffer ? BufferD3D::makeBufferD3D(buffer->getImplementation()) : NULL; + StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer() : NULL; VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); - - BufferStorage *storage = buffer ? buffer->getStorage() : NULL; - bool directStorage = directStoragePossible(vertexBuffer, attribs[i]); + bool directStorage = vertexBuffer->directStoragePossible(attribs[i], currentValues[i]); unsigned int streamOffset = 0; unsigned int outputElementSize = 0; if (directStorage) { - outputElementSize = attribs[i].stride(); - streamOffset = attribs[i].mOffset + outputElementSize * start; - storage->markBufferUsage(); + outputElementSize = ComputeVertexAttributeStride(attribs[i]); + streamOffset = attribs[i].offset + outputElementSize * start; } else if (staticBuffer) { @@ -203,17 +200,18 @@ GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], if (!staticBuffer->lookupAttribute(attribs[i], &streamOffset)) { // Convert the entire buffer - int totalCount = elementsInBuffer(attribs[i], storage->getSize()); - int startIndex = attribs[i].mOffset / attribs[i].stride(); + int totalCount = ElementsInBuffer(attribs[i], storage->getSize()); + int startIndex = attribs[i].offset / ComputeVertexAttributeStride(attribs[i]); - if (!staticBuffer->storeVertexAttributes(attribs[i], -startIndex, totalCount, 0, &streamOffset)) + if (!staticBuffer->storeVertexAttributes(attribs[i], currentValues[i], -startIndex, totalCount, + 0, &streamOffset)) { return GL_OUT_OF_MEMORY; } } - unsigned int firstElementOffset = (attribs[i].mOffset / attribs[i].stride()) * outputElementSize; - unsigned int startOffset = (instances == 0 || attribs[i].mDivisor == 0) ? start * outputElementSize : 0; + unsigned int firstElementOffset = (attribs[i].offset / ComputeVertexAttributeStride(attribs[i])) * outputElementSize; + unsigned int startOffset = (instances == 0 || attribs[i].divisor == 0) ? start * outputElementSize : 0; if (streamOffset + firstElementOffset + startOffset < streamOffset) { return GL_OUT_OF_MEMORY; @@ -225,7 +223,8 @@ GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], { int totalCount = StreamingBufferElementCount(attribs[i], count, instances); if (!mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0, &outputElementSize) || - !mStreamingBuffer->storeVertexAttributes(attribs[i], start, totalCount, instances, &streamOffset)) + !mStreamingBuffer->storeVertexAttributes(attribs[i], currentValues[i], start, totalCount, instances, + &streamOffset)) { return GL_OUT_OF_MEMORY; } @@ -234,9 +233,10 @@ GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], translated[i].storage = directStorage ? storage : NULL; translated[i].vertexBuffer = vertexBuffer->getVertexBuffer(); translated[i].serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial(); - translated[i].divisor = attribs[i].mDivisor; + translated[i].divisor = attribs[i].divisor; translated[i].attribute = &attribs[i]; + translated[i].currentValueType = currentValues[i].Type; translated[i].stride = outputElementSize; translated[i].offset = streamOffset; } @@ -249,27 +249,20 @@ GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], StreamingVertexBufferInterface *buffer = mCurrentValueBuffer[i]; - if (mCurrentValue[i][0] != attribs[i].mCurrentValue[0] || - mCurrentValue[i][1] != attribs[i].mCurrentValue[1] || - mCurrentValue[i][2] != attribs[i].mCurrentValue[2] || - mCurrentValue[i][3] != attribs[i].mCurrentValue[3]) + if (mCurrentValue[i] != currentValues[i]) { - unsigned int requiredSpace = sizeof(float) * 4; - if (!buffer->reserveRawDataSpace(requiredSpace)) + if (!buffer->reserveVertexSpace(attribs[i], 1, 0)) { return GL_OUT_OF_MEMORY; } unsigned int streamOffset; - if (!buffer->storeRawData(attribs[i].mCurrentValue, requiredSpace, &streamOffset)) + if (!buffer->storeVertexAttributes(attribs[i], currentValues[i], 0, 1, 0, &streamOffset)) { return GL_OUT_OF_MEMORY; } - mCurrentValue[i][0] = attribs[i].mCurrentValue[0]; - mCurrentValue[i][1] = attribs[i].mCurrentValue[1]; - mCurrentValue[i][2] = attribs[i].mCurrentValue[2]; - mCurrentValue[i][3] = attribs[i].mCurrentValue[3]; + mCurrentValue[i] = currentValues[i]; mCurrentValueOffsets[i] = streamOffset; } @@ -279,6 +272,7 @@ GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], translated[i].divisor = 0; translated[i].attribute = &attribs[i]; + translated[i].currentValueType = currentValues[i].Type; translated[i].stride = 0; translated[i].offset = mCurrentValueOffsets[i]; } @@ -287,13 +281,14 @@ GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { - if (translated[i].active && attribs[i].mArrayEnabled) + if (translated[i].active && attribs[i].enabled) { - gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); + gl::Buffer *buffer = attribs[i].buffer.get(); if (buffer) { - buffer->promoteStaticUsage(count * attribs[i].typeSize()); + BufferD3D *bufferImpl = BufferD3D::makeBufferD3D(buffer->getImplementation()); + bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(attribs[i])); } } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/VertexDataManager.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h index 1a8786552a..4164fbecbb 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/VertexDataManager.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h @@ -11,17 +11,19 @@ #define LIBGLESV2_RENDERER_VERTEXDATAMANAGER_H_ #include "libGLESv2/Constants.h" +#include "libGLESv2/VertexAttribute.h" #include "common/angleutils.h" namespace gl { -class VertexAttribute; +struct VertexAttribute; class ProgramBinary; +struct VertexAttribCurrentValueData; } namespace rx { -class BufferStorage; +class BufferD3D; class StreamingVertexBufferInterface; class VertexBuffer; class Renderer; @@ -31,11 +33,12 @@ struct TranslatedAttribute bool active; const gl::VertexAttribute *attribute; + GLenum currentValueType; unsigned int offset; unsigned int stride; // 0 means not to advance the read pointer at all VertexBuffer *vertexBuffer; - BufferStorage *storage; + BufferD3D *storage; unsigned int serial; unsigned int divisor; }; @@ -46,7 +49,8 @@ class VertexDataManager VertexDataManager(rx::Renderer *renderer); virtual ~VertexDataManager(); - GLenum prepareVertexData(const gl::VertexAttribute attribs[], gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *outAttribs, GLsizei instances); + GLenum prepareVertexData(const gl::VertexAttribute attribs[], const gl::VertexAttribCurrentValueData currentValues[], + gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *outAttribs, GLsizei instances); private: DISALLOW_COPY_AND_ASSIGN(VertexDataManager); @@ -55,7 +59,8 @@ class VertexDataManager StreamingVertexBufferInterface *mStreamingBuffer; - float mCurrentValue[gl::MAX_VERTEX_ATTRIBS][4]; + gl::VertexAttribCurrentValueData mCurrentValue[gl::MAX_VERTEX_ATTRIBS]; + StreamingVertexBufferInterface *mCurrentValueBuffer[gl::MAX_VERTEX_ATTRIBS]; std::size_t mCurrentValueOffsets[gl::MAX_VERTEX_ATTRIBS]; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp new file mode 100644 index 0000000000..9b0f336ac7 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp @@ -0,0 +1,1049 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Blit11.cpp: Texture copy utility class. + +#include "libGLESv2/main.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/renderer/d3d/d3d11/Blit11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2dvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughdepth2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlum2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha2dps.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough3dvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough3dgs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3duips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3dips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlum3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha3dps.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlef2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlei2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzleui2dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlef3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlei3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzleui3dps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlef2darrayps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlei2darrayps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzleui2darrayps.h" + +namespace rx +{ + +static DXGI_FORMAT GetTextureFormat(ID3D11Resource *resource) +{ + ID3D11Texture2D *texture = d3d11::DynamicCastComObject<ID3D11Texture2D>(resource); + if (!texture) + { + return DXGI_FORMAT_UNKNOWN; + } + + D3D11_TEXTURE2D_DESC desc; + texture->GetDesc(&desc); + + SafeRelease(texture); + + return desc.Format; +} + +static ID3D11Resource *CreateStagingTexture(ID3D11Device *device, ID3D11DeviceContext *context, + ID3D11Resource *source, unsigned int subresource, + const gl::Extents &size, unsigned int cpuAccessFlags) +{ + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = size.width; + stagingDesc.Height = size.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = GetTextureFormat(source); + stagingDesc.SampleDesc.Count = 1; + stagingDesc.SampleDesc.Quality = 0; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.CPUAccessFlags = cpuAccessFlags; + stagingDesc.MiscFlags = 0; + stagingDesc.BindFlags = 0; + + ID3D11Texture2D *stagingTexture = NULL; + HRESULT result = device->CreateTexture2D(&stagingDesc, NULL, &stagingTexture); + if (FAILED(result)) + { + ERR("Failed to create staging texture for depth stencil blit. HRESULT: 0x%X.", result); + return NULL; + } + + context->CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, source, subresource, NULL); + + return stagingTexture; +} + +inline static void GenerateVertexCoords(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + float *x1, float *y1, float *x2, float *y2, + float *u1, float *v1, float *u2, float *v2) +{ + *x1 = (destArea.x / float(destSize.width)) * 2.0f - 1.0f; + *y1 = ((destSize.height - destArea.y - destArea.height) / float(destSize.height)) * 2.0f - 1.0f; + *x2 = ((destArea.x + destArea.width) / float(destSize.width)) * 2.0f - 1.0f; + *y2 = ((destSize.height - destArea.y) / float(destSize.height)) * 2.0f - 1.0f; + + *u1 = sourceArea.x / float(sourceSize.width); + *v1 = sourceArea.y / float(sourceSize.height); + *u2 = (sourceArea.x + sourceArea.width) / float(sourceSize.width); + *v2 = (sourceArea.y + sourceArea.height) / float(sourceSize.height); +} + +static void Write2DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology) +{ + float x1, y1, x2, y2, u1, v1, u2, v2; + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2); + + d3d11::PositionTexCoordVertex *vertices = static_cast<d3d11::PositionTexCoordVertex*>(outVertices); + + d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v2); + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v1); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v2); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v1); + + *outStride = sizeof(d3d11::PositionTexCoordVertex); + *outVertexCount = 4; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; +} + +static void Write3DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology) +{ + ASSERT(sourceSize.depth > 0 && destSize.depth > 0); + + float x1, y1, x2, y2, u1, v1, u2, v2; + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2); + + d3d11::PositionLayerTexCoord3DVertex *vertices = static_cast<d3d11::PositionLayerTexCoord3DVertex*>(outVertices); + + for (int i = 0; i < destSize.depth; i++) + { + float readDepth = (float)i / std::max(destSize.depth - 1, 1); + + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 0], x1, y1, i, u1, v2, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 1], x1, y2, i, u1, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 2], x2, y1, i, u2, v2, readDepth); + + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 3], x1, y2, i, u1, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 4], x2, y2, i, u2, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 5], x2, y1, i, u2, v2, readDepth); + } + + *outStride = sizeof(d3d11::PositionLayerTexCoord3DVertex); + *outVertexCount = destSize.depth * 6; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; +} + +Blit11::Blit11(rx::Renderer11 *renderer) + : mRenderer(renderer), mBlitShaderMap(compareBlitParameters), mSwizzleShaderMap(compareSwizzleParameters), + mVertexBuffer(NULL), mPointSampler(NULL), mLinearSampler(NULL), mScissorEnabledRasterizerState(NULL), + mScissorDisabledRasterizerState(NULL), mDepthStencilState(NULL), + mQuad2DIL(NULL), mQuad2DVS(NULL), mDepthPS(NULL), + mQuad3DIL(NULL), mQuad3DVS(NULL), mQuad3DGS(NULL), + mSwizzleCB(NULL) +{ + HRESULT result; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_BUFFER_DESC vbDesc; + vbDesc.ByteWidth = std::max(sizeof(d3d11::PositionLayerTexCoord3DVertex), sizeof(d3d11::PositionTexCoordVertex)) * + 6 * renderer->getRendererCaps().max3DTextureSize; + vbDesc.Usage = D3D11_USAGE_DYNAMIC; + vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbDesc.MiscFlags = 0; + vbDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mVertexBuffer, "Blit11 vertex buffer"); + + D3D11_SAMPLER_DESC pointSamplerDesc; + pointSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; + pointSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.MipLODBias = 0.0f; + pointSamplerDesc.MaxAnisotropy = 0; + pointSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + pointSamplerDesc.BorderColor[0] = 0.0f; + pointSamplerDesc.BorderColor[1] = 0.0f; + pointSamplerDesc.BorderColor[2] = 0.0f; + pointSamplerDesc.BorderColor[3] = 0.0f; + pointSamplerDesc.MinLOD = 0.0f; + pointSamplerDesc.MaxLOD = mRenderer->isLevel9() ? FLT_MAX : 0.0f; + + result = device->CreateSamplerState(&pointSamplerDesc, &mPointSampler); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPointSampler, "Blit11 point sampler"); + + D3D11_SAMPLER_DESC linearSamplerDesc; + linearSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + linearSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.MipLODBias = 0.0f; + linearSamplerDesc.MaxAnisotropy = 0; + linearSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + linearSamplerDesc.BorderColor[0] = 0.0f; + linearSamplerDesc.BorderColor[1] = 0.0f; + linearSamplerDesc.BorderColor[2] = 0.0f; + linearSamplerDesc.BorderColor[3] = 0.0f; + linearSamplerDesc.MinLOD = 0.0f; + linearSamplerDesc.MaxLOD = mRenderer->isLevel9() ? FLT_MAX : 0.0f; + + result = device->CreateSamplerState(&linearSamplerDesc, &mLinearSampler); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mLinearSampler, "Blit11 linear sampler"); + + // Use a rasterizer state that will not cull so that inverted quads will not be culled + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = D3D11_CULL_NONE; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + rasterDesc.ScissorEnable = TRUE; + result = device->CreateRasterizerState(&rasterDesc, &mScissorEnabledRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mScissorEnabledRasterizerState, "Blit11 scissoring rasterizer state"); + + rasterDesc.ScissorEnable = FALSE; + result = device->CreateRasterizerState(&rasterDesc, &mScissorDisabledRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mScissorDisabledRasterizerState, "Blit11 no scissoring rasterizer state"); + + D3D11_DEPTH_STENCIL_DESC depthStencilDesc; + depthStencilDesc.DepthEnable = true; + depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.StencilEnable = FALSE; + depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + result = device->CreateDepthStencilState(&depthStencilDesc, &mDepthStencilState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthStencilState, "Blit11 depth stencil state"); + + D3D11_INPUT_ELEMENT_DESC quad2DLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quad2DLayout, ArraySize(quad2DLayout), g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), &mQuad2DIL); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad2DIL, "Blit11 2D input layout"); + + result = device->CreateVertexShader(g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), NULL, &mQuad2DVS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad2DVS, "Blit11 2D vertex shader"); + + if (!renderer->isLevel9()) + { + result = device->CreatePixelShader(g_PS_PassthroughDepth2D, ArraySize(g_PS_PassthroughDepth2D), NULL, &mDepthPS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthPS, "Blit11 2D depth pixel shader"); + + D3D11_INPUT_ELEMENT_DESC quad3DLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "LAYER", 0, DXGI_FORMAT_R32_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quad3DLayout, ArraySize(quad3DLayout), g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), &mQuad3DIL); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DIL, "Blit11 3D input layout"); + + result = device->CreateVertexShader(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), NULL, &mQuad3DVS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DVS, "Blit11 3D vertex shader"); + + result = device->CreateGeometryShader(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), NULL, &mQuad3DGS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DGS, "Renderer11 copy 3D texture geometry shader"); + + } + + buildShaderMap(); + + D3D11_BUFFER_DESC swizzleBufferDesc; + swizzleBufferDesc.ByteWidth = sizeof(unsigned int) * 4; + swizzleBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + swizzleBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + swizzleBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + swizzleBufferDesc.MiscFlags = 0; + swizzleBufferDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&swizzleBufferDesc, NULL, &mSwizzleCB); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mSwizzleCB, "Blit11 swizzle constant buffer"); +} + +Blit11::~Blit11() +{ + SafeRelease(mVertexBuffer); + SafeRelease(mPointSampler); + SafeRelease(mLinearSampler); + SafeRelease(mScissorEnabledRasterizerState); + SafeRelease(mScissorDisabledRasterizerState); + SafeRelease(mDepthStencilState); + + SafeRelease(mQuad2DIL); + SafeRelease(mQuad2DVS); + SafeRelease(mDepthPS); + + SafeRelease(mQuad3DIL); + SafeRelease(mQuad3DVS); + SafeRelease(mQuad3DGS); + + SafeRelease(mSwizzleCB); + + clearShaderMap(); +} + +static inline unsigned int GetSwizzleIndex(GLenum swizzle) +{ + unsigned int colorIndex = 0; + + switch (swizzle) + { + case GL_RED: colorIndex = 0; break; + case GL_GREEN: colorIndex = 1; break; + case GL_BLUE: colorIndex = 2; break; + case GL_ALPHA: colorIndex = 3; break; + case GL_ZERO: colorIndex = 4; break; + case GL_ONE: colorIndex = 5; break; + default: UNREACHABLE(); break; + } + + return colorIndex; +} + +bool Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, + GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; + source->GetDesc(&sourceSRVDesc); + GLenum sourceInternalFormat = d3d11_gl::GetInternalFormat(sourceSRVDesc.Format); + + GLenum shaderType = GL_NONE; + switch (gl::GetComponentType(sourceInternalFormat)) + { + case GL_UNSIGNED_NORMALIZED: + case GL_SIGNED_NORMALIZED: + case GL_FLOAT: + shaderType = GL_FLOAT; + break; + case GL_INT: + shaderType = GL_INT; + break; + case GL_UNSIGNED_INT: + shaderType = GL_UNSIGNED_INT; + break; + default: + UNREACHABLE(); + break; + } + + SwizzleParameters parameters = { 0 }; + parameters.mDestinationType = shaderType; + parameters.mViewDimension = sourceSRVDesc.ViewDimension; + + SwizzleShaderMap::const_iterator i = mSwizzleShaderMap.find(parameters); + if (i == mSwizzleShaderMap.end()) + { + UNREACHABLE(); + return false; + } + + const Shader &shader = i->second; + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Failed to map vertex buffer for texture swizzle, HRESULT: 0x%X.", result); + return false; + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + gl::Box area(0, 0, 0, size.width, size.height, size.depth); + shader.mVertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Set constant buffer + result = deviceContext->Map(mSwizzleCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Failed to map constant buffer for texture swizzle, HRESULT: 0x%X.", result); + return false; + } + + unsigned int *swizzleIndices = reinterpret_cast<unsigned int*>(mappedResource.pData); + swizzleIndices[0] = GetSwizzleIndex(swizzleRed); + swizzleIndices[1] = GetSwizzleIndex(swizzleGreen); + swizzleIndices[2] = GetSwizzleIndex(swizzleBlue); + swizzleIndices[3] = GetSwizzleIndex(swizzleAlpha); + + deviceContext->Unmap(mSwizzleCB, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply constant buffer + deviceContext->PSSetConstantBuffers(0, 1, &mSwizzleCB); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + deviceContext->RSSetState(mScissorDisabledRasterizerState); + + // Apply shaders + deviceContext->IASetInputLayout(shader.mInputLayout); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(shader.mVertexShader, NULL, 0); + + deviceContext->PSSetShader(shader.mPixelShader, NULL, 0); + deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + ID3D11ShaderResourceView *const nullSRV = NULL; + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + // Apply render target + mRenderer->setOneTimeRenderTarget(dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = size.width; + viewport.Height = size.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + deviceContext->PSSetShaderResources(0, 1, &source); + + // Apply samplers + deviceContext->PSSetSamplers(0, 1, &mPointSampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return true; +} + +bool Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, GLenum destFormat, GLenum filter) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // Determine if the source format is a signed integer format, the destFormat will already + // be GL_XXXX_INTEGER but it does not tell us if it is signed or unsigned. + D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; + source->GetDesc(&sourceSRVDesc); + GLenum sourceInternalFormat = d3d11_gl::GetInternalFormat(sourceSRVDesc.Format); + + BlitParameters parameters = { 0 }; + parameters.mDestinationFormat = destFormat; + parameters.mSignedInteger = gl::GetComponentType(sourceInternalFormat) == GL_INT; + parameters.m3DBlit = sourceArea.depth > 1; + + BlitShaderMap::const_iterator i = mBlitShaderMap.find(parameters); + if (i == mBlitShaderMap.end()) + { + UNREACHABLE(); + return false; + } + + const Shader& shader = i->second; + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Failed to map vertex buffer for texture copy, HRESULT: 0x%X.", result); + return false; + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + shader.mVertexWriteFunction(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, + &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + + if (scissor) + { + D3D11_RECT scissorRect; + scissorRect.left = scissor->x; + scissorRect.right = scissor->x + scissor->width; + scissorRect.top = scissor->y; + scissorRect.bottom = scissor->y + scissor->height; + + deviceContext->RSSetScissorRects(1, &scissorRect); + deviceContext->RSSetState(mScissorEnabledRasterizerState); + } + else + { + deviceContext->RSSetState(mScissorDisabledRasterizerState); + } + + // Apply shaders + deviceContext->IASetInputLayout(shader.mInputLayout); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(shader.mVertexShader, NULL, 0); + + deviceContext->PSSetShader(shader.mPixelShader, NULL, 0); + deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + ID3D11ShaderResourceView *const nullSRV = NULL; + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + // Apply render target + mRenderer->setOneTimeRenderTarget(dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + deviceContext->PSSetShaderResources(0, 1, &source); + + // Apply samplers + ID3D11SamplerState *sampler = NULL; + switch (filter) + { + case GL_NEAREST: sampler = mPointSampler; break; + case GL_LINEAR: sampler = mLinearSampler; break; + default: UNREACHABLE(); return false; + } + deviceContext->PSSetSamplers(0, 1, &sampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return true; +} + +bool Blit11::copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, + dest, destSubresource, destArea, destSize, + scissor, true); +} + +bool Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Failed to map vertex buffer for texture copy, HRESULT: 0x%X.", result); + return false; + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + Write2DVertices(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, + &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(mDepthStencilState, 0xFFFFFFFF); + + if (scissor) + { + D3D11_RECT scissorRect; + scissorRect.left = scissor->x; + scissorRect.right = scissor->x + scissor->width; + scissorRect.top = scissor->y; + scissorRect.bottom = scissor->y + scissor->height; + + deviceContext->RSSetScissorRects(1, &scissorRect); + deviceContext->RSSetState(mScissorEnabledRasterizerState); + } + else + { + deviceContext->RSSetState(mScissorDisabledRasterizerState); + } + + // Apply shaders + deviceContext->IASetInputLayout(mQuad2DIL); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(mQuad2DVS, NULL, 0); + + deviceContext->PSSetShader(mDepthPS, NULL, 0); + deviceContext->GSSetShader(NULL, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + ID3D11ShaderResourceView *const nullSRV = NULL; + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + // Apply render target + deviceContext->OMSetRenderTargets(0, NULL, dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + deviceContext->PSSetShaderResources(0, 1, &source); + + // Apply samplers + deviceContext->PSSetSamplers(0, 1, &mPointSampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return true; +} + +bool Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, + dest, destSubresource, destArea, destSize, + scissor, false); +} + +bool Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, bool stencilOnly) +{ + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ID3D11Resource *sourceStaging = CreateStagingTexture(device, deviceContext, source, sourceSubresource, sourceSize, D3D11_CPU_ACCESS_READ); + // HACK: Create the destination staging buffer as a read/write texture so ID3D11DevicContext::UpdateSubresource can be called + // using it's mapped data as a source + ID3D11Resource *destStaging = CreateStagingTexture(device, deviceContext, dest, destSubresource, destSize, D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE); + + if (!sourceStaging || !destStaging) + { + SafeRelease(sourceStaging); + SafeRelease(destStaging); + return false; + } + + DXGI_FORMAT format = GetTextureFormat(source); + ASSERT(format == GetTextureFormat(dest)); + + unsigned int pixelSize = d3d11::GetFormatPixelBytes(format); + unsigned int copyOffset = 0; + unsigned int copySize = pixelSize; + if (stencilOnly) + { + copyOffset = d3d11::GetStencilOffset(format) / 8; + copySize = d3d11::GetStencilBits(format) / 8; + + // It would be expensive to have non-byte sized stencil sizes since it would + // require reading from the destination, currently there aren't any though. + ASSERT(d3d11::GetStencilBits(format) % 8 == 0 && + d3d11::GetStencilOffset(format) % 8 == 0); + } + + D3D11_MAPPED_SUBRESOURCE sourceMapping, destMapping; + deviceContext->Map(sourceStaging, 0, D3D11_MAP_READ, 0, &sourceMapping); + deviceContext->Map(destStaging, 0, D3D11_MAP_WRITE, 0, &destMapping); + + if (!sourceMapping.pData || !destMapping.pData) + { + if (!sourceMapping.pData) + { + deviceContext->Unmap(sourceStaging, 0); + } + if (!destMapping.pData) + { + deviceContext->Unmap(destStaging, 0); + } + SafeRelease(sourceStaging); + SafeRelease(destStaging); + return false; + } + + gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height); + + // Clip dest area to the destination size + gl::ClipRectangle(clippedDestArea, gl::Rectangle(0, 0, destSize.width, destSize.height), &clippedDestArea); + + // Clip dest area to the scissor + if (scissor) + { + gl::ClipRectangle(clippedDestArea, *scissor, &clippedDestArea); + } + + // Determine if entire rows can be copied at once instead of each individual pixel, requires that there is + // no out of bounds lookups required, the entire pixel is copied and no stretching + bool wholeRowCopy = sourceArea.width == clippedDestArea.width && + sourceArea.x >= 0 && sourceArea.x + sourceArea.width <= sourceSize.width && + copySize == pixelSize; + + for (int y = clippedDestArea.y; y < clippedDestArea.y + clippedDestArea.height; y++) + { + float yPerc = static_cast<float>(y - destArea.y) / (destArea.height - 1); + + // Interpolate using the original source rectangle to determine which row to sample from while clamping to the edges + unsigned int readRow = gl::clamp(sourceArea.y + floor(yPerc * (sourceArea.height - 1) + 0.5f), 0, sourceSize.height - 1); + unsigned int writeRow = y; + + if (wholeRowCopy) + { + void *sourceRow = reinterpret_cast<char*>(sourceMapping.pData) + + readRow * sourceMapping.RowPitch + + sourceArea.x * pixelSize; + + void *destRow = reinterpret_cast<char*>(destMapping.pData) + + writeRow * destMapping.RowPitch + + destArea.x * pixelSize; + + memcpy(destRow, sourceRow, pixelSize * destArea.width); + } + else + { + for (int x = clippedDestArea.x; x < clippedDestArea.x + clippedDestArea.width; x++) + { + float xPerc = static_cast<float>(x - destArea.x) / (destArea.width - 1); + + // Interpolate the original source rectangle to determine which column to sample from while clamping to the edges + unsigned int readColumn = gl::clamp(sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f), 0, sourceSize.width - 1); + unsigned int writeColumn = x; + + void *sourcePixel = reinterpret_cast<char*>(sourceMapping.pData) + + readRow * sourceMapping.RowPitch + + readColumn * pixelSize + + copyOffset; + + void *destPixel = reinterpret_cast<char*>(destMapping.pData) + + writeRow * destMapping.RowPitch + + writeColumn * pixelSize + + copyOffset; + + memcpy(destPixel, sourcePixel, copySize); + } + } + } + + // HACK: Use ID3D11DevicContext::UpdateSubresource which causes an extra copy compared to ID3D11DevicContext::CopySubresourceRegion + // according to MSDN. + deviceContext->UpdateSubresource(dest, destSubresource, NULL, destMapping.pData, destMapping.RowPitch, destMapping.DepthPitch); + + deviceContext->Unmap(sourceStaging, 0); + deviceContext->Unmap(destStaging, 0); + + // TODO: Determine why this call to ID3D11DevicContext::CopySubresourceRegion causes a TDR timeout on some + // systems when called repeatedly. + // deviceContext->CopySubresourceRegion(dest, destSubresource, 0, 0, 0, destStaging, 0, NULL); + + SafeRelease(sourceStaging); + SafeRelease(destStaging); + + return true; +} + +bool Blit11::compareBlitParameters(const Blit11::BlitParameters &a, const Blit11::BlitParameters &b) +{ + return memcmp(&a, &b, sizeof(Blit11::BlitParameters)) < 0; +} + +bool Blit11::compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b) +{ + return memcmp(&a, &b, sizeof(Blit11::SwizzleParameters)) < 0; +} + +void Blit11::add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps) +{ + BlitParameters params = { 0 }; + params.mDestinationFormat = destFormat; + params.mSignedInteger = signedInteger; + params.m3DBlit = false; + + ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end()); + ASSERT(ps); + + Shader shader; + shader.mVertexWriteFunction = Write2DVertices; + shader.mInputLayout = mQuad2DIL; + shader.mVertexShader = mQuad2DVS; + shader.mGeometryShader = NULL; + shader.mPixelShader = ps; + + mBlitShaderMap[params] = shader; +} + +void Blit11::add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps) +{ + BlitParameters params = { 0 }; + params.mDestinationFormat = destFormat; + params.mSignedInteger = signedInteger; + params.m3DBlit = true; + + ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end()); + ASSERT(ps); + + Shader shader; + shader.mVertexWriteFunction = Write3DVertices; + shader.mInputLayout = mQuad3DIL; + shader.mVertexShader = mQuad3DVS; + shader.mGeometryShader = mQuad3DGS; + shader.mPixelShader = ps; + + mBlitShaderMap[params] = shader; +} + +void Blit11::addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps) +{ + SwizzleParameters params = { 0 }; + params.mDestinationType = destType; + params.mViewDimension = viewDimension; + + ASSERT(mSwizzleShaderMap.find(params) == mSwizzleShaderMap.end()); + ASSERT(ps); + + Shader shader; + switch (viewDimension) + { + case D3D_SRV_DIMENSION_TEXTURE2D: + shader.mVertexWriteFunction = Write2DVertices; + shader.mInputLayout = mQuad2DIL; + shader.mVertexShader = mQuad2DVS; + shader.mGeometryShader = NULL; + break; + + case D3D_SRV_DIMENSION_TEXTURE3D: + case D3D_SRV_DIMENSION_TEXTURE2DARRAY: + case D3D_SRV_DIMENSION_TEXTURECUBE: + shader.mVertexWriteFunction = Write3DVertices; + shader.mInputLayout = mQuad3DIL; + shader.mVertexShader = mQuad3DVS; + shader.mGeometryShader = mQuad3DGS; + break; + + default: + UNREACHABLE(); + break; + } + shader.mPixelShader = ps; + + mSwizzleShaderMap[params] = shader; +} + +void Blit11::buildShaderMap() +{ + ID3D11Device *device = mRenderer->getDevice(); + + add2DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D RGBA pixel shader" )); + add2DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D BGRA pixel shader" )); + add2DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2D, "Blit11 2D RGB pixel shader" )); + add2DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG2D, "Blit11 2D RG pixel shader" )); + add2DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR2D, "Blit11 2D R pixel shader" )); + add2DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D alpha pixel shader" )); + add2DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum2D, "Blit11 2D lum pixel shader" )); + add2DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha2D, "Blit11 2D luminance alpha pixel shader")); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleF2D, "Blit11 2D F swizzle pixel shader" )); + + if (mRenderer->isLevel9()) + return; + + add2DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DUI, "Blit11 2D RGBA UI pixel shader" )); + add2DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DI, "Blit11 2D RGBA I pixel shader" )); + add2DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2DUI, "Blit11 2D RGB UI pixel shader" )); + add2DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB2DI, "Blit11 2D RGB I pixel shader" )); + add2DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG2DUI, "Blit11 2D RG UI pixel shader" )); + add2DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG2DI, "Blit11 2D RG I pixel shader" )); + add2DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR2DUI, "Blit11 2D R UI pixel shader" )); + add2DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR2DI, "Blit11 2D R I pixel shader" )); + + add3DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D RGBA pixel shader" )); + add3DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DUI, "Blit11 3D UI RGBA pixel shader" )); + add3DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader" )); + add3DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D BGRA pixel shader" )); + add3DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3D, "Blit11 3D RGB pixel shader" )); + add3DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3DUI, "Blit11 3D RGB UI pixel shader" )); + add3DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB3DI, "Blit11 3D RGB I pixel shader" )); + add3DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader" )); + add3DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG3DUI, "Blit11 3D RG UI pixel shader" )); + add3DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG3DI, "Blit11 3D RG I pixel shader" )); + add3DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader" )); + add3DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR3DUI, "Blit11 3D R UI pixel shader" )); + add3DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR3DI, "Blit11 3D R I pixel shader" )); + add3DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D alpha pixel shader" )); + add3DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum3D, "Blit11 3D luminance pixel shader" )); + add3DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha3D, "Blit11 3D luminance alpha pixel shader")); + + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleUI2D, "Blit11 2D UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleI2D, "Blit11 2D I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Cube F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Cube UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Cube I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleF3D, "Blit11 3D F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleUI3D, "Blit11 3D UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleI3D, "Blit11 3D I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Array F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Array UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Array I swizzle pixel shader" )); +} + +void Blit11::clearShaderMap() +{ + for (BlitShaderMap::iterator i = mBlitShaderMap.begin(); i != mBlitShaderMap.end(); ++i) + { + Shader &shader = i->second; + SafeRelease(shader.mPixelShader); + } + mBlitShaderMap.clear(); + + for (SwizzleShaderMap::iterator i = mSwizzleShaderMap.begin(); i != mSwizzleShaderMap.end(); ++i) + { + Shader &shader = i->second; + SafeRelease(shader.mPixelShader); + } + mSwizzleShaderMap.clear(); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h new file mode 100644 index 0000000000..fba89e20ba --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h @@ -0,0 +1,126 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Blit11.cpp: Texture copy utility class. + +#ifndef LIBGLESV2_BLIT11_H_ +#define LIBGLESV2_BLIT11_H_ + +#include "common/angleutils.h" +#include "libGLESv2/angletypes.h" + +namespace rx +{ +class Renderer11; + +enum Filter +{ + Point, + Linear, +}; + +class Blit11 +{ + public: + explicit Blit11(Renderer11 *renderer); + ~Blit11(); + + bool swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, + GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + + bool copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, GLenum destFormat, GLenum filter); + + bool copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + bool copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + bool copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + private: + rx::Renderer11 *mRenderer; + + struct BlitParameters + { + GLenum mDestinationFormat; + bool mSignedInteger; + bool m3DBlit; + }; + + bool copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, bool stencilOnly); + + static bool compareBlitParameters(const BlitParameters &a, const BlitParameters &b); + + typedef void (*WriteVertexFunction)(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology); + + struct Shader + { + WriteVertexFunction mVertexWriteFunction; + ID3D11InputLayout *mInputLayout; + ID3D11VertexShader *mVertexShader; + ID3D11GeometryShader *mGeometryShader; + ID3D11PixelShader *mPixelShader; + }; + + typedef bool (*BlitParametersComparisonFunction)(const BlitParameters&, const BlitParameters &); + typedef std::map<BlitParameters, Shader, BlitParametersComparisonFunction> BlitShaderMap; + BlitShaderMap mBlitShaderMap; + + void add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps); + void add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps); + + struct SwizzleParameters + { + GLenum mDestinationType; + D3D11_SRV_DIMENSION mViewDimension; + }; + + static bool compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b); + + typedef bool (*SwizzleParametersComparisonFunction)(const SwizzleParameters&, const SwizzleParameters &); + typedef std::map<SwizzleParameters, Shader, SwizzleParametersComparisonFunction> SwizzleShaderMap; + SwizzleShaderMap mSwizzleShaderMap; + + void addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps); + + void buildShaderMap(); + void clearShaderMap(); + + ID3D11Buffer *mVertexBuffer; + ID3D11SamplerState *mPointSampler; + ID3D11SamplerState *mLinearSampler; + ID3D11RasterizerState *mScissorEnabledRasterizerState; + ID3D11RasterizerState *mScissorDisabledRasterizerState; + ID3D11DepthStencilState *mDepthStencilState; + + ID3D11InputLayout *mQuad2DIL; + ID3D11VertexShader *mQuad2DVS; + ID3D11PixelShader *mDepthPS; + + ID3D11InputLayout *mQuad3DIL; + ID3D11VertexShader *mQuad3DVS; + ID3D11GeometryShader *mQuad3DGS; + + ID3D11Buffer *mSwizzleCB; + + DISALLOW_COPY_AND_ASSIGN(Blit11); +}; + +} + +#endif // LIBGLESV2_BLIT11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp new file mode 100644 index 0000000000..352da9654a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp @@ -0,0 +1,900 @@ +#include "precompiled.h" +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer11.cpp Defines the Buffer11 class. + +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" + +namespace rx +{ + +PackPixelsParams::PackPixelsParams() + : format(GL_NONE), + type(GL_NONE), + outputPitch(0), + packBuffer(NULL), + offset(0) +{} + +PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, GLenum formatIn, GLenum typeIn, GLuint outputPitchIn, + const gl::PixelPackState &packIn, ptrdiff_t offsetIn) + : area(areaIn), + format(formatIn), + type(typeIn), + outputPitch(outputPitchIn), + packBuffer(packIn.pixelBuffer.get()), + pack(packIn.alignment, packIn.reverseRowOrder), + offset(offsetIn) +{} + +namespace gl_d3d11 +{ + +D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) +{ + bool readBit = ((access & GL_MAP_READ_BIT) != 0); + bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0); + + ASSERT(readBit || writeBit); + + // Note : we ignore the discard bit, because in D3D11, staging buffers + // don't accept the map-discard flag (discard only works for DYNAMIC usage) + + if (readBit && !writeBit) + { + return D3D11_MAP_READ; + } + else if (writeBit && !readBit) + { + return D3D11_MAP_WRITE; + } + else if (writeBit && readBit) + { + return D3D11_MAP_READ_WRITE; + } + else + { + UNREACHABLE(); + return D3D11_MAP_READ; + } +} + +} + +// Each instance of Buffer11::BufferStorage11 is specialized for a class of D3D binding points +// - vertex/transform feedback buffers +// - index buffers +// - pixel unpack buffers +// - uniform buffers +class Buffer11::BufferStorage11 +{ + public: + virtual ~BufferStorage11() {} + + DataRevision getDataRevision() const { return mRevision; } + BufferUsage getUsage() const { return mUsage; } + size_t getSize() const { return mBufferSize; } + bool isMappable() const { return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_PIXEL_PACK); } + + void setDataRevision(DataRevision rev) { mRevision = rev; } + + virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, + size_t size, size_t destOffset) = 0; + virtual bool resize(size_t size, bool preserveData) = 0; + + virtual void *map(size_t offset, size_t length, GLbitfield access) = 0; + virtual void unmap() = 0; + + protected: + BufferStorage11(Renderer11 *renderer, BufferUsage usage); + + Renderer11 *mRenderer; + DataRevision mRevision; + const BufferUsage mUsage; + size_t mBufferSize; +}; + +// A native buffer storage represents an underlying D3D11 buffer for a particular +// type of storage. +class Buffer11::NativeBuffer11 : public Buffer11::BufferStorage11 +{ + public: + NativeBuffer11(Renderer11 *renderer, BufferUsage usage); + ~NativeBuffer11(); + + ID3D11Buffer *getNativeBuffer() const { return mNativeBuffer; } + + virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, + size_t size, size_t destOffset); + virtual bool resize(size_t size, bool preserveData); + + virtual void *map(size_t offset, size_t length, GLbitfield access); + virtual void unmap(); + + private: + ID3D11Buffer *mNativeBuffer; + + static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, BufferUsage usage, unsigned int bufferSize); +}; + +// Pack storage represents internal storage for pack buffers. We implement pack buffers +// as CPU memory, tied to a staging texture, for asynchronous texture readback. +class Buffer11::PackStorage11 : public Buffer11::BufferStorage11 +{ + public: + PackStorage11(Renderer11 *renderer); + ~PackStorage11(); + + virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, + size_t size, size_t destOffset); + virtual bool resize(size_t size, bool preserveData); + + virtual void *map(size_t offset, size_t length, GLbitfield access); + virtual void unmap(); + + void packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms); + + private: + + void flushQueuedPackCommand(); + + ID3D11Texture2D *mStagingTexture; + DXGI_FORMAT mTextureFormat; + gl::Extents mTextureSize; + MemoryBuffer mMemoryBuffer; + PackPixelsParams *mQueuedPackCommand; + PackPixelsParams mPackParams; + bool mDataModified; +}; + + +Buffer11::Buffer11(Renderer11 *renderer) + : BufferD3D(), + mRenderer(renderer), + mSize(0), + mMappedStorage(NULL), + mResolvedDataRevision(0), + mReadUsageCount(0) +{ +} + +Buffer11::~Buffer11() +{ + clear(); +} + +Buffer11 *Buffer11::makeBuffer11(BufferImpl *buffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Buffer11*, buffer)); + return static_cast<Buffer11*>(buffer); +} + +void Buffer11::clear() +{ + for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) + { + SafeDelete(it->second); + } + + mBufferStorages.clear(); + + mSize = 0; + mResolvedDataRevision = 0; +} + +void Buffer11::setData(const void* data, size_t size, GLenum usage) +{ + mIndexRangeCache.clear(); + + setSubData(data, size, 0); + + if (usage == GL_STATIC_DRAW) + { + initializeStaticData(); + } +} + +void *Buffer11::getData() +{ + NativeBuffer11 *stagingBuffer = getStagingBuffer(); + + if (!stagingBuffer) + { + // Out-of-memory + return NULL; + } + + if (stagingBuffer->getDataRevision() > mResolvedDataRevision) + { + if (stagingBuffer->getSize() > mResolvedData.size()) + { + if (!mResolvedData.resize(stagingBuffer->getSize())) + { + return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); + } + } + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = context->Map(stagingBuffer->getNativeBuffer(), 0, D3D11_MAP_READ, 0, &mappedResource); + if (FAILED(result)) + { + return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); + } + + memcpy(mResolvedData.data(), mappedResource.pData, stagingBuffer->getSize()); + + context->Unmap(stagingBuffer->getNativeBuffer(), 0); + + mResolvedDataRevision = stagingBuffer->getDataRevision(); + } + + mReadUsageCount = 0; + + return mResolvedData.data(); +} + +void Buffer11::setSubData(const void* data, size_t size, size_t offset) +{ + size_t requiredSize = size + offset; + mSize = std::max(mSize, requiredSize); + + mIndexRangeCache.invalidateRange(offset, size); + invalidateStaticData(); + + if (data && size > 0) + { + NativeBuffer11 *stagingBuffer = getStagingBuffer(); + + if (!stagingBuffer) + { + // Out-of-memory + return; + } + + // Explicitly resize the staging buffer, preserving data if the new data will not + // completely fill the buffer + if (stagingBuffer->getSize() < requiredSize) + { + bool preserveData = (offset > 0); + if (!stagingBuffer->resize(requiredSize, preserveData)) + { + // Out-of-memory + return; + } + } + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = context->Map(stagingBuffer->getNativeBuffer(), 0, D3D11_MAP_WRITE, 0, &mappedResource); + if (FAILED(result)) + { + return gl::error(GL_OUT_OF_MEMORY); + } + + unsigned char *offsetBufferPointer = reinterpret_cast<unsigned char *>(mappedResource.pData) + offset; + memcpy(offsetBufferPointer, data, size); + + context->Unmap(stagingBuffer->getNativeBuffer(), 0); + + stagingBuffer->setDataRevision(stagingBuffer->getDataRevision() + 1); + } +} + +void Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +{ + Buffer11 *sourceBuffer = makeBuffer11(source); + if (sourceBuffer) + { + BufferStorage11 *dest = getLatestBufferStorage(); + if (!dest) + { + dest = getStagingBuffer(); + } + + BufferStorage11 *source = sourceBuffer->getLatestBufferStorage(); + if (source && dest) + { + // If copying to/from a pixel pack buffer, we must have a staging or + // pack buffer partner, because other native buffers can't be mapped + if (dest->getUsage() == BUFFER_USAGE_PIXEL_PACK && !source->isMappable()) + { + source = sourceBuffer->getStagingBuffer(); + } + else if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK && !dest->isMappable()) + { + dest = getStagingBuffer(); + } + + dest->copyFromStorage(source, sourceOffset, size, destOffset); + dest->setDataRevision(dest->getDataRevision() + 1); + } + + mSize = std::max<size_t>(mSize, destOffset + size); + } + + invalidateStaticData(); +} + +GLvoid *Buffer11::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(!mMappedStorage); + + BufferStorage11 *latestStorage = getLatestBufferStorage(); + if (latestStorage && + (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK || + latestStorage->getUsage() == BUFFER_USAGE_STAGING)) + { + // Latest storage is mappable. + mMappedStorage = latestStorage; + } + else + { + // Fall back to using the staging buffer if the latest storage does + // not exist or is not CPU-accessible. + mMappedStorage = getStagingBuffer(); + } + + if (!mMappedStorage) + { + // Out-of-memory + return NULL; + } + + if ((access & GL_MAP_WRITE_BIT) > 0) + { + // Update the data revision immediately, since the data might be changed at any time + mMappedStorage->setDataRevision(mMappedStorage->getDataRevision() + 1); + } + + return mMappedStorage->map(offset, length, access); +} + +void Buffer11::unmap() +{ + ASSERT(mMappedStorage); + mMappedStorage->unmap(); + mMappedStorage = NULL; +} + +void Buffer11::markTransformFeedbackUsage() +{ + BufferStorage11 *transformFeedbackStorage = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + + if (transformFeedbackStorage) + { + transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1); + } + + invalidateStaticData(); +} + +void Buffer11::markBufferUsage() +{ + mReadUsageCount++; + + const unsigned int usageLimit = 5; + + if (mReadUsageCount > usageLimit && mResolvedData.size() > 0) + { + mResolvedData.resize(0); + mResolvedDataRevision = 0; + } +} + +Renderer* Buffer11::getRenderer() +{ + return mRenderer; +} + +ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage) +{ + markBufferUsage(); + + BufferStorage11 *bufferStorage = getBufferStorage(usage); + + if (!bufferStorage) + { + // Storage out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, bufferStorage)); + + return static_cast<NativeBuffer11*>(bufferStorage)->getNativeBuffer(); +} + +ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat) +{ + BufferStorage11 *storage = getBufferStorage(BUFFER_USAGE_PIXEL_UNPACK); + + if (!storage) + { + // Storage out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, storage)); + ID3D11Buffer *buffer = static_cast<NativeBuffer11*>(storage)->getNativeBuffer(); + + auto bufferSRVIt = mBufferResourceViews.find(srvFormat); + + if (bufferSRVIt != mBufferResourceViews.end()) + { + if (bufferSRVIt->second.first == buffer) + { + return bufferSRVIt->second.second; + } + else + { + // The underlying buffer has changed since the SRV was created: recreate the SRV. + SafeRelease(bufferSRVIt->second.second); + } + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11ShaderResourceView *bufferSRV = NULL; + + D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; + bufferSRVDesc.Buffer.ElementOffset = 0; + bufferSRVDesc.Buffer.ElementWidth = mSize / d3d11::GetFormatPixelBytes(srvFormat); + bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + bufferSRVDesc.Format = srvFormat; + + HRESULT result = device->CreateShaderResourceView(buffer, &bufferSRVDesc, &bufferSRV); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + mBufferResourceViews[srvFormat] = BufferSRVPair(buffer, bufferSRV); + + return bufferSRV; +} + +void Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource, const PackPixelsParams ¶ms) +{ + PackStorage11 *packStorage = getPackStorage(); + + BufferStorage11 *latestStorage = getLatestBufferStorage(); + + if (packStorage) + { + packStorage->packPixels(srcTexture, srcSubresource, params); + packStorage->setDataRevision(latestStorage ? latestStorage->getDataRevision() + 1 : 1); + } +} + +Buffer11::BufferStorage11 *Buffer11::getBufferStorage(BufferUsage usage) +{ + BufferStorage11 *directBuffer = NULL; + auto directBufferIt = mBufferStorages.find(usage); + if (directBufferIt != mBufferStorages.end()) + { + directBuffer = directBufferIt->second; + } + + if (!directBuffer) + { + if (usage == BUFFER_USAGE_PIXEL_PACK) + { + directBuffer = new PackStorage11(mRenderer); + } + else + { + // buffer is not allocated, create it + directBuffer = new NativeBuffer11(mRenderer, usage); + } + + mBufferStorages.insert(std::make_pair(usage, directBuffer)); + } + + // resize buffer + if (directBuffer->getSize() < mSize) + { + if (!directBuffer->resize(mSize, true)) + { + // Out of memory error + return NULL; + } + } + + BufferStorage11 *latestBuffer = getLatestBufferStorage(); + if (latestBuffer && latestBuffer->getDataRevision() > directBuffer->getDataRevision()) + { + // if copying from a pack buffer to a non-staging native buffer, we must first + // copy through the staging buffer, because other native buffers can't be mapped + if (latestBuffer->getUsage() == BUFFER_USAGE_PIXEL_PACK && !directBuffer->isMappable()) + { + NativeBuffer11 *stagingBuffer = getStagingBuffer(); + + stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); + directBuffer->setDataRevision(latestBuffer->getDataRevision()); + + latestBuffer = stagingBuffer; + } + + // if copyFromStorage returns true, the D3D buffer has been recreated + // and we should update our serial + if (directBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0)) + { + updateSerial(); + } + directBuffer->setDataRevision(latestBuffer->getDataRevision()); + } + + return directBuffer; +} + +Buffer11::BufferStorage11 *Buffer11::getLatestBufferStorage() const +{ + // Even though we iterate over all the direct buffers, it is expected that only + // 1 or 2 will be present. + BufferStorage11 *latestStorage = NULL; + DataRevision latestRevision = 0; + for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) + { + BufferStorage11 *storage = it->second; + if (!latestStorage || storage->getDataRevision() > latestRevision) + { + latestStorage = storage; + latestRevision = storage->getDataRevision(); + } + } + + return latestStorage; +} + +Buffer11::NativeBuffer11 *Buffer11::getStagingBuffer() +{ + BufferStorage11 *stagingStorage = getBufferStorage(BUFFER_USAGE_STAGING); + + if (!stagingStorage) + { + // Out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, stagingStorage)); + return static_cast<NativeBuffer11*>(stagingStorage); +} + +Buffer11::PackStorage11 *Buffer11::getPackStorage() +{ + BufferStorage11 *packStorage = getBufferStorage(BUFFER_USAGE_PIXEL_PACK); + + if (!packStorage) + { + // Out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(PackStorage11*, packStorage)); + return static_cast<PackStorage11*>(packStorage); +} + +Buffer11::BufferStorage11::BufferStorage11(Renderer11 *renderer, BufferUsage usage) + : mRenderer(renderer), + mUsage(usage), + mRevision(0), + mBufferSize(0) +{ +} + +Buffer11::NativeBuffer11::NativeBuffer11(Renderer11 *renderer, BufferUsage usage) + : BufferStorage11(renderer, usage), + mNativeBuffer(NULL) +{ +} + +Buffer11::NativeBuffer11::~NativeBuffer11() +{ + SafeRelease(mNativeBuffer); +} + +// Returns true if it recreates the direct buffer +bool Buffer11::NativeBuffer11::copyFromStorage(BufferStorage11 *source, size_t sourceOffset, + size_t size, size_t destOffset) +{ + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + size_t requiredSize = sourceOffset + size; + bool createBuffer = !mNativeBuffer || mBufferSize < requiredSize; + + // (Re)initialize D3D buffer if needed + if (createBuffer) + { + bool preserveData = (destOffset > 0); + resize(source->getSize(), preserveData); + } + + if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK) + { + ASSERT(HAS_DYNAMIC_TYPE(PackStorage11*, source)); + + void *sourcePointer = source->map(sourceOffset, size, GL_MAP_READ_BIT); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT hr = context->Map(mNativeBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource); + UNUSED_ASSERTION_VARIABLE(hr); + ASSERT(SUCCEEDED(hr)); + + unsigned char *destPointer = static_cast<unsigned char *>(mappedResource.pData) + destOffset; + + // Offset bounds are validated at the API layer + ASSERT(sourceOffset + size <= destOffset + mBufferSize); + memcpy(destPointer, sourcePointer, size); + } + else + { + ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, source)); + + D3D11_BOX srcBox; + srcBox.left = sourceOffset; + srcBox.right = sourceOffset + size; + srcBox.top = 0; + srcBox.bottom = 1; + srcBox.front = 0; + srcBox.back = 1; + + ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, source)); + ID3D11Buffer *sourceBuffer = static_cast<NativeBuffer11*>(source)->getNativeBuffer(); + + context->CopySubresourceRegion(mNativeBuffer, 0, destOffset, 0, 0, sourceBuffer, 0, &srcBox); + } + + return createBuffer; +} + +bool Buffer11::NativeBuffer11::resize(size_t size, bool preserveData) +{ + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + D3D11_BUFFER_DESC bufferDesc; + fillBufferDesc(&bufferDesc, mRenderer, mUsage, size); + + ID3D11Buffer *newBuffer; + HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer); + + if (FAILED(result)) + { + return gl::error(GL_OUT_OF_MEMORY, false); + } + + if (mNativeBuffer && preserveData) + { + // We don't call resize if the buffer is big enough already. + ASSERT(mBufferSize <= size); + + D3D11_BOX srcBox; + srcBox.left = 0; + srcBox.right = mBufferSize; + srcBox.top = 0; + srcBox.bottom = 1; + srcBox.front = 0; + srcBox.back = 1; + + context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeBuffer, 0, &srcBox); + } + + // No longer need the old buffer + SafeRelease(mNativeBuffer); + mNativeBuffer = newBuffer; + + mBufferSize = bufferDesc.ByteWidth; + + return true; +} + +void Buffer11::NativeBuffer11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, + BufferUsage usage, unsigned int bufferSize) +{ + bufferDesc->ByteWidth = bufferSize; + bufferDesc->MiscFlags = 0; + bufferDesc->StructureByteStride = 0; + + switch (usage) + { + case BUFFER_USAGE_STAGING: + bufferDesc->Usage = D3D11_USAGE_STAGING; + bufferDesc->BindFlags = 0; + bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + break; + + case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER; + if (renderer->getMaxTransformFeedbackBuffers() > 0) + bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT; + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_INDEX: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER; + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_PIXEL_UNPACK: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE; + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_UNIFORM: + bufferDesc->Usage = D3D11_USAGE_DYNAMIC; + bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + // Constant buffers must be of a limited size, and aligned to 16 byte boundaries + // For our purposes we ignore any buffer data past the maximum constant buffer size + bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u); + bufferDesc->ByteWidth = std::min(bufferDesc->ByteWidth, renderer->getMaxUniformBufferSize()); + break; + + default: + UNREACHABLE(); + } +} + +void *Buffer11::NativeBuffer11::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(mUsage == BUFFER_USAGE_STAGING); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(access); + UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0); + + HRESULT result = context->Map(mNativeBuffer, 0, d3dMapType, d3dMapFlag, &mappedResource); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + return static_cast<GLubyte*>(mappedResource.pData) + offset; +} + +void Buffer11::NativeBuffer11::unmap() +{ + ASSERT(mUsage == BUFFER_USAGE_STAGING); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + context->Unmap(mNativeBuffer, 0); +} + +Buffer11::PackStorage11::PackStorage11(Renderer11 *renderer) + : BufferStorage11(renderer, BUFFER_USAGE_PIXEL_PACK), + mStagingTexture(NULL), + mTextureFormat(DXGI_FORMAT_UNKNOWN), + mQueuedPackCommand(NULL), + mDataModified(false) +{ +} + +Buffer11::PackStorage11::~PackStorage11() +{ + SafeRelease(mStagingTexture); + SafeDelete(mQueuedPackCommand); +} + +bool Buffer11::PackStorage11::copyFromStorage(BufferStorage11 *source, size_t sourceOffset, + size_t size, size_t destOffset) +{ + UNIMPLEMENTED(); + return false; +} + +bool Buffer11::PackStorage11::resize(size_t size, bool preserveData) +{ + if (size != mBufferSize) + { + if (!mMemoryBuffer.resize(size)) + { + return false; + } + mBufferSize = size; + } + + return true; +} + +void *Buffer11::PackStorage11::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(offset + length <= getSize()); + // TODO: fast path + // We might be able to optimize out one or more memcpy calls by detecting when + // and if D3D packs the staging texture memory identically to how we would fill + // the pack buffer according to the current pack state. + + flushQueuedPackCommand(); + mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0); + + return mMemoryBuffer.data() + offset; +} + +void Buffer11::PackStorage11::unmap() +{ + // No-op +} + +void Buffer11::PackStorage11::packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms) +{ + flushQueuedPackCommand(); + mQueuedPackCommand = new PackPixelsParams(params); + + D3D11_TEXTURE2D_DESC textureDesc; + srcTexure->GetDesc(&textureDesc); + + if (mStagingTexture != NULL && + (mTextureFormat != textureDesc.Format || + mTextureSize.width != params.area.width || + mTextureSize.height != params.area.height)) + { + SafeRelease(mStagingTexture); + mTextureSize.width = 0; + mTextureSize.height = 0; + mTextureFormat = DXGI_FORMAT_UNKNOWN; + } + + if (mStagingTexture == NULL) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT hr; + + mTextureSize.width = params.area.width; + mTextureSize.height = params.area.height; + mTextureFormat = textureDesc.Format; + + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = params.area.width; + stagingDesc.Height = params.area.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = mTextureFormat; + stagingDesc.SampleDesc.Count = 1; + stagingDesc.SampleDesc.Quality = 0; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.BindFlags = 0; + stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stagingDesc.MiscFlags = 0; + + hr = device->CreateTexture2D(&stagingDesc, NULL, &mStagingTexture); + ASSERT(SUCCEEDED(hr)); + } + + if (textureDesc.SampleDesc.Count > 1) + { + UNIMPLEMENTED(); + } + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + D3D11_BOX srcBox; + srcBox.left = params.area.x; + srcBox.right = params.area.x + params.area.width; + srcBox.top = params.area.y; + srcBox.bottom = params.area.y + params.area.height; + srcBox.front = 0; + srcBox.back = 1; + + // Asynchronous copy + immediateContext->CopySubresourceRegion(mStagingTexture, 0, 0, 0, 0, srcTexure, srcSubresource, &srcBox); +} + +void Buffer11::PackStorage11::flushQueuedPackCommand() +{ + ASSERT(mMemoryBuffer.size() > 0); + + if (mQueuedPackCommand) + { + mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()); + SafeDelete(mQueuedPackCommand); + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h new file mode 100644 index 0000000000..e56be247c4 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h @@ -0,0 +1,106 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer11.h: Defines the rx::Buffer11 class which implements rx::BufferImpl via rx::BufferD3D. + +#ifndef LIBGLESV2_RENDERER_BUFFER11_H_ +#define LIBGLESV2_RENDERER_BUFFER11_H_ + +#include "libGLESv2/renderer/d3d/BufferD3D.h" +#include "libGLESv2/renderer/d3d/MemoryBuffer.h" +#include "libGLESv2/angletypes.h" + +namespace rx +{ +class Renderer11; + +enum BufferUsage +{ + BUFFER_USAGE_STAGING, + BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK, + BUFFER_USAGE_INDEX, + BUFFER_USAGE_PIXEL_UNPACK, + BUFFER_USAGE_PIXEL_PACK, + BUFFER_USAGE_UNIFORM, +}; + +struct PackPixelsParams +{ + PackPixelsParams(); + PackPixelsParams(const gl::Rectangle &area, GLenum format, GLenum type, GLuint outputPitch, + const gl::PixelPackState &pack, ptrdiff_t offset); + + gl::Rectangle area; + GLenum format; + GLenum type; + GLuint outputPitch; + gl::Buffer *packBuffer; + gl::PixelPackState pack; + ptrdiff_t offset; +}; + +typedef size_t DataRevision; + +class Buffer11 : public BufferD3D +{ + public: + Buffer11(rx::Renderer11 *renderer); + virtual ~Buffer11(); + + static Buffer11 *makeBuffer11(BufferImpl *buffer); + + ID3D11Buffer *getBuffer(BufferUsage usage); + ID3D11ShaderResourceView *getSRV(DXGI_FORMAT srvFormat); + bool isMapped() const { return mMappedStorage != NULL; } + void packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms); + + // BufferD3D implementation + virtual size_t getSize() const { return mSize; } + virtual void clear(); + virtual bool supportsDirectBinding() const { return true; } + virtual Renderer* getRenderer(); + + // BufferImpl implementation + virtual void setData(const void* data, size_t size, GLenum usage); + virtual void *getData(); + virtual void setSubData(const void* data, size_t size, size_t offset); + virtual void copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + virtual GLvoid* map(size_t offset, size_t length, GLbitfield access); + virtual void unmap(); + virtual void markTransformFeedbackUsage(); + + private: + DISALLOW_COPY_AND_ASSIGN(Buffer11); + + class BufferStorage11; + class NativeBuffer11; + class PackStorage11; + + rx::Renderer11 *mRenderer; + size_t mSize; + + BufferStorage11 *mMappedStorage; + + std::map<BufferUsage, BufferStorage11*> mBufferStorages; + + typedef std::pair<ID3D11Buffer *, ID3D11ShaderResourceView *> BufferSRVPair; + std::map<DXGI_FORMAT, BufferSRVPair> mBufferResourceViews; + + MemoryBuffer mResolvedData; + DataRevision mResolvedDataRevision; + unsigned int mReadUsageCount; + + void markBufferUsage(); + NativeBuffer11 *getStagingBuffer(); + PackStorage11 *getPackStorage(); + + BufferStorage11 *getBufferStorage(BufferUsage usage); + BufferStorage11 *getLatestBufferStorage() const; +}; + +} + +#endif // LIBGLESV2_RENDERER_BUFFER11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp new file mode 100644 index 0000000000..8db5ea27c1 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp @@ -0,0 +1,568 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Clear11.cpp: Framebuffer clear utility class. + +#include "libGLESv2/renderer/d3d/d3d11/Clear11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" + +#include "libGLESv2/formatutils.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearfloatvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearfloatps.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearuintvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearuintps.h" + +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearsintvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearsintps.h" + +namespace rx +{ + +template <typename T> +static void ApplyVertices(const gl::Extents &framebufferSize, const gl::Rectangle *scissor, const gl::Color<T> &color, float depth, void *buffer) +{ + d3d11::PositionDepthColorVertex<T> *vertices = reinterpret_cast<d3d11::PositionDepthColorVertex<T>*>(buffer); + + float depthClear = gl::clamp01(depth); + float left = -1.0f; + float right = 1.0f; + float top = -1.0f; + float bottom = 1.0f; + + // Clip the quad coordinates to the scissor if needed + if (scissor != NULL) + { + left = std::max(left, (scissor->x / float(framebufferSize.width)) * 2.0f - 1.0f); + right = std::min(right, ((scissor->x + scissor->width) / float(framebufferSize.width)) * 2.0f - 1.0f); + top = std::max(top, ((framebufferSize.height - scissor->y - scissor->height) / float(framebufferSize.height)) * 2.0f - 1.0f); + bottom = std::min(bottom, ((framebufferSize.height - scissor->y) / float(framebufferSize.height)) * 2.0f - 1.0f); + } + + d3d11::SetPositionDepthColorVertex<T>(vertices + 0, left, bottom, depthClear, color); + d3d11::SetPositionDepthColorVertex<T>(vertices + 1, left, top, depthClear, color); + d3d11::SetPositionDepthColorVertex<T>(vertices + 2, right, bottom, depthClear, color); + d3d11::SetPositionDepthColorVertex<T>(vertices + 3, right, top, depthClear, color); +} + +template <unsigned int vsSize, unsigned int psSize> +Clear11::ClearShader Clear11::CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE (&vsByteCode)[vsSize], const BYTE (&psByteCode)[psSize]) +{ + HRESULT result; + + ClearShader shader = { 0 }; + + D3D11_INPUT_ELEMENT_DESC quadLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, colorType, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quadLayout, ArraySize(quadLayout), vsByteCode, vsSize, &shader.inputLayout); + ASSERT(SUCCEEDED(result)); + + result = device->CreateVertexShader(vsByteCode, vsSize, NULL, &shader.vertexShader); + ASSERT(SUCCEEDED(result)); + + result = device->CreatePixelShader(psByteCode, psSize, NULL, &shader.pixelShader); + ASSERT(SUCCEEDED(result)); + + return shader; +} + +Clear11::Clear11(Renderer11 *renderer) + : mRenderer(renderer), mClearBlendStates(StructLessThan<ClearBlendInfo>), mClearDepthStencilStates(StructLessThan<ClearDepthStencilInfo>), + mVertexBuffer(NULL), mRasterizerState(NULL) +{ + HRESULT result; + ID3D11Device *device = renderer->getDevice(); + + D3D11_BUFFER_DESC vbDesc; + vbDesc.ByteWidth = sizeof(d3d11::PositionDepthColorVertex<float>) * 4; + vbDesc.Usage = D3D11_USAGE_DYNAMIC; + vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbDesc.MiscFlags = 0; + vbDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mVertexBuffer, "Clear11 masked clear vertex buffer"); + + D3D11_RASTERIZER_DESC rsDesc; + rsDesc.FillMode = D3D11_FILL_SOLID; + rsDesc.CullMode = D3D11_CULL_NONE; + rsDesc.FrontCounterClockwise = FALSE; + rsDesc.DepthBias = 0; + rsDesc.DepthBiasClamp = 0.0f; + rsDesc.SlopeScaledDepthBias = 0.0f; + rsDesc.DepthClipEnable = mRenderer->isLevel9(); + rsDesc.ScissorEnable = FALSE; + rsDesc.MultisampleEnable = FALSE; + rsDesc.AntialiasedLineEnable = FALSE; + + result = device->CreateRasterizerState(&rsDesc, &mRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mRasterizerState, "Clear11 masked clear rasterizer state"); + + mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat); + if (mRenderer->isLevel9()) { + mUintClearShader = { 0 }; + mIntClearShader = { 0 }; + return; + } + + mUintClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_UINT, g_VS_ClearUint, g_PS_ClearUint ); + mIntClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_SINT, g_VS_ClearSint, g_PS_ClearSint ); +} + +Clear11::~Clear11() +{ + for (ClearBlendStateMap::iterator i = mClearBlendStates.begin(); i != mClearBlendStates.end(); i++) + { + SafeRelease(i->second); + } + mClearBlendStates.clear(); + + SafeRelease(mFloatClearShader.inputLayout); + SafeRelease(mFloatClearShader.vertexShader); + SafeRelease(mFloatClearShader.pixelShader); + + SafeRelease(mUintClearShader.inputLayout); + SafeRelease(mUintClearShader.vertexShader); + SafeRelease(mUintClearShader.pixelShader); + + SafeRelease(mIntClearShader.inputLayout); + SafeRelease(mIntClearShader.vertexShader); + SafeRelease(mIntClearShader.pixelShader); + + for (ClearDepthStencilStateMap::iterator i = mClearDepthStencilStates.begin(); i != mClearDepthStencilStates.end(); i++) + { + SafeRelease(i->second); + } + mClearDepthStencilStates.clear(); + + SafeRelease(mVertexBuffer); + SafeRelease(mRasterizerState); +} + +void Clear11::clearFramebuffer(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) +{ + // First determine if a scissored clear is needed, this will always require drawing a quad. + // + // Otherwise, iterate over the color buffers which require clearing and determine if they can be + // cleared with ID3D11DeviceContext::ClearRenderTargetView... This requires: + // 1) The render target is being cleared to a float value (will be cast to integer when clearing integer + // render targets as expected but does not work the other way around) + // 2) The format of the render target has no color channels that are currently masked out. + // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special work. + // + // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView + // by checking if the stencil write mask covers the entire stencil. + // + // To clear the remaining buffers, quads must be drawn containing an int, uint or float vertex color + // attribute. + + gl::Extents framebufferSize; + if (frameBuffer->getFirstColorbuffer() != NULL) + { + gl::FramebufferAttachment *attachment = frameBuffer->getFirstColorbuffer(); + framebufferSize.width = attachment->getWidth(); + framebufferSize.height = attachment->getHeight(); + framebufferSize.depth = 1; + } + else if (frameBuffer->getDepthOrStencilbuffer() != NULL) + { + gl::FramebufferAttachment *attachment = frameBuffer->getDepthOrStencilbuffer(); + framebufferSize.width = attachment->getWidth(); + framebufferSize.height = attachment->getHeight(); + framebufferSize.depth = 1; + } + else + { + UNREACHABLE(); + return; + } + + if (clearParams.scissorEnabled && (clearParams.scissor.x >= framebufferSize.width || + clearParams.scissor.y >= framebufferSize.height || + clearParams.scissor.x + clearParams.scissor.width <= 0 || + clearParams.scissor.y + clearParams.scissor.height <= 0)) + { + // Scissor is enabled and the scissor rectangle is outside the renderbuffer + return; + } + + bool needScissoredClear = clearParams.scissorEnabled && (clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || + clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || + clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height); + + std::vector<MaskedRenderTarget> maskedClearRenderTargets; + RenderTarget11* maskedClearDepthStencil = NULL; + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) + { + if (clearParams.clearColor[colorAttachment] && frameBuffer->isEnabledColorAttachment(colorAttachment)) + { + gl::FramebufferAttachment *attachment = frameBuffer->getColorbuffer(colorAttachment); + if (attachment) + { + RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(attachment->getRenderTarget()); + if (!renderTarget) + { + ERR("Render target pointer unexpectedly null."); + return; + } + + GLenum internalFormat = attachment->getInternalFormat(); + GLenum actualFormat = attachment->getActualFormat(); + GLenum componentType = gl::GetComponentType(internalFormat); + if (clearParams.colorClearType == GL_FLOAT && + !(componentType == GL_FLOAT || componentType == GL_UNSIGNED_NORMALIZED || componentType == GL_SIGNED_NORMALIZED)) + { + ERR("It is undefined behaviour to clear a render buffer which is not normalized fixed point or floating-" + "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment, internalFormat); + } + + GLuint internalRedBits = gl::GetRedBits(internalFormat); + GLuint internalGreenBits = gl::GetGreenBits(internalFormat); + GLuint internalBlueBits = gl::GetBlueBits(internalFormat); + GLuint internalAlphaBits = gl::GetAlphaBits(internalFormat); + + if ((internalRedBits == 0 || !clearParams.colorMaskRed) && + (internalGreenBits == 0 || !clearParams.colorMaskGreen) && + (internalBlueBits == 0 || !clearParams.colorMaskBlue) && + (internalAlphaBits == 0 || !clearParams.colorMaskAlpha)) + { + // Every channel either does not exist in the render target or is masked out + continue; + } + else if (needScissoredClear || clearParams.colorClearType != GL_FLOAT || + (internalRedBits > 0 && !clearParams.colorMaskRed) || + (internalGreenBits > 0 && !clearParams.colorMaskGreen) || + (internalBlueBits > 0 && !clearParams.colorMaskBlue) || + (internalAlphaBits > 0 && !clearParams.colorMaskAlpha)) + { + // A scissored or masked clear is required + MaskedRenderTarget maskAndRt; + bool clearColor = clearParams.clearColor[colorAttachment]; + maskAndRt.colorMask[0] = (clearColor && clearParams.colorMaskRed); + maskAndRt.colorMask[1] = (clearColor && clearParams.colorMaskGreen); + maskAndRt.colorMask[2] = (clearColor && clearParams.colorMaskBlue); + maskAndRt.colorMask[3] = (clearColor && clearParams.colorMaskAlpha); + maskAndRt.renderTarget = renderTarget; + maskedClearRenderTargets.push_back(maskAndRt); + } + else + { + // ID3D11DeviceContext::ClearRenderTargetView is possible + + ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView(); + if (!framebufferRTV) + { + ERR("Render target view pointer unexpectedly null."); + return; + } + + // Check if the actual format has a channel that the internal format does not and set them to the + // default values + GLuint actualRedBits = gl::GetRedBits(actualFormat); + GLuint actualGreenBits = gl::GetGreenBits(actualFormat); + GLuint actualBlueBits = gl::GetBlueBits(actualFormat); + GLuint actualAlphaBits = gl::GetAlphaBits(actualFormat); + + const float clearValues[4] = + { + ((internalRedBits == 0 && actualRedBits > 0) ? 0.0f : clearParams.colorFClearValue.red), + ((internalGreenBits == 0 && actualGreenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), + ((internalBlueBits == 0 && actualBlueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue), + ((internalAlphaBits == 0 && actualAlphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), + }; + + deviceContext->ClearRenderTargetView(framebufferRTV, clearValues); + } + } + } + } + + if (clearParams.clearDepth || clearParams.clearStencil) + { + gl::FramebufferAttachment *attachment = frameBuffer->getDepthOrStencilbuffer(); + if (attachment) + { + RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(attachment->getDepthStencil()); + if (!renderTarget) + { + ERR("Depth stencil render target pointer unexpectedly null."); + return; + } + + GLenum actualFormat = attachment->getActualFormat(); + + unsigned int stencilUnmasked = frameBuffer->hasStencil() ? (1 << gl::GetStencilBits(actualFormat)) - 1 : 0; + bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + + if (needScissoredClear || needMaskedStencilClear) + { + maskedClearDepthStencil = renderTarget; + } + else + { + ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView(); + if (!framebufferDSV) + { + ERR("Depth stencil view pointer unexpectedly null."); + return; + } + + UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) | + (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0); + FLOAT depthClear = gl::clamp01(clearParams.depthClearValue); + UINT8 stencilClear = clearParams.stencilClearValue & 0xFF; + + deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear); + } + } + } + + if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil) + { + // To clear the render targets and depth stencil in one pass: + // + // Render a quad clipped to the scissor rectangle which draws the clear color and a blend + // state that will perform the required color masking. + // + // The quad's depth is equal to the depth clear value with a depth stencil state that + // will enable or disable depth test/writes if the depth buffer should be cleared or not. + // + // The rasterizer state's stencil is set to always pass or fail based on if the stencil + // should be cleared or not with a stencil write mask of the stencil clear value. + // + // ====================================================================================== + // + // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render- + // buffer that is not normalized fixed point or floating point with floating point values + // are undefined so we can just write floats to them and D3D11 will bit cast them to + // integers. + // + // Also, we don't have to worry about attempting to clear a normalized fixed/floating point + // buffer with integer values because there is no gl API call which would allow it, + // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to + // be a compatible clear type. + + // Bind all the render targets which need clearing + ASSERT(maskedClearRenderTargets.size() <= mRenderer->getRendererCaps().maxDrawBuffers); + std::vector<ID3D11RenderTargetView*> rtvs(maskedClearRenderTargets.size()); + for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++) + { + RenderTarget11 *renderTarget = maskedClearRenderTargets[i].renderTarget; + ID3D11RenderTargetView *rtv = renderTarget->getRenderTargetView(); + if (!rtv) + { + ERR("Render target view unexpectedly null."); + return; + } + + rtvs[i] = rtv; + } + ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : NULL; + + ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets); + const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + const UINT sampleMask = 0xFFFFFFFF; + + ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams); + const UINT stencilClear = clearParams.stencilClearValue & 0xFF; + + // Set the vertices + UINT vertexStride = 0; + const UINT startIdx = 0; + const ClearShader* shader = NULL; + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Failed to map masked clear vertex buffer, HRESULT: 0x%X.", result); + return; + } + + const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : NULL; + switch (clearParams.colorClearType) + { + case GL_FLOAT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex<float>); + shader = &mFloatClearShader; + break; + + case GL_UNSIGNED_INT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex<unsigned int>); + shader = &mUintClearShader; + break; + + case GL_INT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex<int>); + shader = &mIntClearShader; + break; + + default: + UNREACHABLE(); + break; + } + + deviceContext->Unmap(mVertexBuffer, 0); + + // Set the viewport to be the same size as the framebuffer + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = framebufferSize.width; + viewport.Height = framebufferSize.height; + viewport.MinDepth = 0; + viewport.MaxDepth = 1; + deviceContext->RSSetViewports(1, &viewport); + + // Apply state + deviceContext->OMSetBlendState(blendState, blendFactors, sampleMask); + deviceContext->OMSetDepthStencilState(dsState, stencilClear); + deviceContext->RSSetState(mRasterizerState); + + // Apply shaders + deviceContext->IASetInputLayout(shader->inputLayout); + deviceContext->VSSetShader(shader->vertexShader, NULL, 0); + deviceContext->PSSetShader(shader->pixelShader, NULL, 0); + deviceContext->GSSetShader(NULL, NULL, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx); + deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + // Apply render targets + deviceContext->OMSetRenderTargets(rtvs.size(), (rtvs.empty() ? NULL : &rtvs[0]), dsv); + + // Draw the clear quad + deviceContext->Draw(4, 0); + + // Clean up + mRenderer->markAllStateDirty(); + } +} + +ID3D11BlendState *Clear11::getBlendState(const std::vector<MaskedRenderTarget>& rts) +{ + ClearBlendInfo blendKey = { 0 }; + for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + if (i < rts.size()) + { + RenderTarget11 *rt = rts[i].renderTarget; + GLint internalFormat = rt->getInternalFormat(); + + blendKey.maskChannels[i][0] = (rts[i].colorMask[0] && gl::GetRedBits(internalFormat) > 0); + blendKey.maskChannels[i][1] = (rts[i].colorMask[1] && gl::GetGreenBits(internalFormat) > 0); + blendKey.maskChannels[i][2] = (rts[i].colorMask[2] && gl::GetBlueBits(internalFormat) > 0); + blendKey.maskChannels[i][3] = (rts[i].colorMask[3] && gl::GetAlphaBits(internalFormat) > 0); + } + else + { + blendKey.maskChannels[i][0] = false; + blendKey.maskChannels[i][1] = false; + blendKey.maskChannels[i][2] = false; + blendKey.maskChannels[i][3] = false; + } + } + + ClearBlendStateMap::const_iterator i = mClearBlendStates.find(blendKey); + if (i != mClearBlendStates.end()) + { + return i->second; + } + else + { + D3D11_BLEND_DESC blendDesc = { 0 }; + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = (rts.size() > 1) ? TRUE : FALSE; + + for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + blendDesc.RenderTarget[i].BlendEnable = FALSE; + blendDesc.RenderTarget[i].RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendKey.maskChannels[i][0], + blendKey.maskChannels[i][1], + blendKey.maskChannels[i][2], + blendKey.maskChannels[i][3]); + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11BlendState* blendState = NULL; + HRESULT result = device->CreateBlendState(&blendDesc, &blendState); + if (FAILED(result) || !blendState) + { + ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); + return NULL; + } + + mClearBlendStates[blendKey] = blendState; + + return blendState; + } +} + +ID3D11DepthStencilState *Clear11::getDepthStencilState(const gl::ClearParameters &clearParams) +{ + ClearDepthStencilInfo dsKey = { 0 }; + dsKey.clearDepth = clearParams.clearDepth; + dsKey.clearStencil = clearParams.clearStencil; + dsKey.stencilWriteMask = clearParams.stencilWriteMask & 0xFF; + + ClearDepthStencilStateMap::const_iterator i = mClearDepthStencilStates.find(dsKey); + if (i != mClearDepthStencilStates.end()) + { + return i->second; + } + else + { + D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; + dsDesc.DepthEnable = dsKey.clearDepth ? TRUE : FALSE; + dsDesc.DepthWriteMask = dsKey.clearDepth ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.StencilEnable = dsKey.clearStencil ? TRUE : FALSE; + dsDesc.StencilReadMask = 0; + dsDesc.StencilWriteMask = dsKey.stencilWriteMask; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DepthStencilState* dsState = NULL; + HRESULT result = device->CreateDepthStencilState(&dsDesc, &dsState); + if (FAILED(result) || !dsState) + { + ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); + return NULL; + } + + mClearDepthStencilStates[dsKey] = dsState; + + return dsState; + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h new file mode 100644 index 0000000000..0cb9a85a6d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h @@ -0,0 +1,83 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Clear11.h: Framebuffer clear utility class. + +#ifndef LIBGLESV2_RENDERER_CLEAR11_H_ +#define LIBGLESV2_RENDERER_CLEAR11_H_ + +#include "libGLESv2/angletypes.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer11; +class RenderTarget11; + +class Clear11 +{ + public: + explicit Clear11(Renderer11 *renderer); + ~Clear11(); + + // Clears the framebuffer with the supplied clear parameters, assumes that the framebuffer is currently applied. + void clearFramebuffer(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); + + private: + Renderer11 *mRenderer; + + struct ClearBlendInfo + { + bool maskChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; + }; + typedef bool (*ClearBlendInfoComparisonFunction)(const ClearBlendInfo&, const ClearBlendInfo &); + typedef std::map<ClearBlendInfo, ID3D11BlendState*, ClearBlendInfoComparisonFunction> ClearBlendStateMap; + ClearBlendStateMap mClearBlendStates; + + struct MaskedRenderTarget + { + bool colorMask[4]; + RenderTarget11 *renderTarget; + }; + + ID3D11BlendState *getBlendState(const std::vector<MaskedRenderTarget> &rts); + + struct ClearShader + { + ID3D11InputLayout *inputLayout; + ID3D11VertexShader *vertexShader; + ID3D11PixelShader *pixelShader; + }; + ClearShader mFloatClearShader; + ClearShader mUintClearShader; + ClearShader mIntClearShader; + + template <unsigned int vsSize, unsigned int psSize> + static ClearShader CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE (&vsByteCode)[vsSize], const BYTE (&psByteCode)[psSize]); + + struct ClearDepthStencilInfo + { + bool clearDepth; + bool clearStencil; + UINT8 stencilWriteMask; + }; + typedef bool (*ClearDepthStencilInfoComparisonFunction)(const ClearDepthStencilInfo&, const ClearDepthStencilInfo &); + typedef std::map<ClearDepthStencilInfo, ID3D11DepthStencilState*, ClearDepthStencilInfoComparisonFunction> ClearDepthStencilStateMap; + ClearDepthStencilStateMap mClearDepthStencilStates; + + ID3D11DepthStencilState *getDepthStencilState(const gl::ClearParameters &clearParams); + + ID3D11Buffer *mVertexBuffer; + ID3D11RasterizerState *mRasterizerState; +}; + +} + +#endif // LIBGLESV2_RENDERER_CLEAR11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp new file mode 100644 index 0000000000..8698776650 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp @@ -0,0 +1,71 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence11.cpp: Defines the rx::Fence11 class which implements rx::FenceImpl. + +#include "libGLESv2/renderer/d3d/d3d11/Fence11.h" +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +Fence11::Fence11(rx::Renderer11 *renderer) +{ + mRenderer = renderer; + mQuery = NULL; +} + +Fence11::~Fence11() +{ + SafeRelease(mQuery); +} + +bool Fence11::isSet() const +{ + return mQuery != NULL; +} + +void Fence11::set() +{ + if (!mQuery) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + + if (FAILED(mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery))) + { + return gl::error(GL_OUT_OF_MEMORY); + } + } + + mRenderer->getDeviceContext()->End(mQuery); +} + +bool Fence11::test(bool flushCommandBuffer) +{ + ASSERT(mQuery); + + UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH); + HRESULT result = mRenderer->getDeviceContext()->GetData(mQuery, NULL, 0, getDataFlags); + + if (mRenderer->isDeviceLost()) + { + return gl::error(GL_OUT_OF_MEMORY, true); + } + + ASSERT(result == S_OK || result == S_FALSE); + return (result == S_OK); +} + +bool Fence11::hasError() const +{ + return mRenderer->isDeviceLost(); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Fence11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h index a5398bca14..50c7621776 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Fence11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h @@ -21,11 +21,10 @@ class Fence11 : public FenceImpl explicit Fence11(rx::Renderer11 *renderer); virtual ~Fence11(); - GLboolean isFence(); - void setFence(GLenum condition); - GLboolean testFence(); - void finishFence(); - void getFenceiv(GLenum pname, GLint *params); + bool isSet() const; + void set(); + bool test(bool flushCommandBuffer); + bool hasError() const; private: DISALLOW_COPY_AND_ASSIGN(Fence11); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp new file mode 100644 index 0000000000..2165bec305 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp @@ -0,0 +1,460 @@ +#include "precompiled.h" +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Image11.h: Implements the rx::Image11 class, which acts as the interface to +// the actual underlying resources of a Texture + +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/Image11.h" +#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" + +#include "libGLESv2/main.h" +#include "common/utilities.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" + +namespace rx +{ + +Image11::Image11() +{ + mStagingTexture = NULL; + mRenderer = NULL; + mDXGIFormat = DXGI_FORMAT_UNKNOWN; +} + +Image11::~Image11() +{ + SafeRelease(mStagingTexture); +} + +Image11 *Image11::makeImage11(Image *img) +{ + ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img)); + return static_cast<rx::Image11*>(img); +} + +void Image11::generateMipmap(Image11 *dest, Image11 *src) +{ + ASSERT(src->getDXGIFormat() == dest->getDXGIFormat()); + ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth()); + ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight()); + + MipGenerationFunction mipFunction = d3d11::GetMipGenerationFunction(src->getDXGIFormat()); + ASSERT(mipFunction != NULL); + + D3D11_MAPPED_SUBRESOURCE destMapped; + HRESULT destMapResult = dest->map(D3D11_MAP_WRITE, &destMapped); + if (FAILED(destMapResult)) + { + ERR("Failed to map destination image for mip map generation. HRESULT:0x%X", destMapResult); + return; + } + + D3D11_MAPPED_SUBRESOURCE srcMapped; + HRESULT srcMapResult = src->map(D3D11_MAP_READ, &srcMapped); + if (FAILED(srcMapResult)) + { + ERR("Failed to map source image for mip map generation. HRESULT:0x%X", srcMapResult); + + dest->unmap(); + return; + } + + const uint8_t *sourceData = reinterpret_cast<const uint8_t*>(srcMapped.pData); + uint8_t *destData = reinterpret_cast<uint8_t*>(destMapped.pData); + + mipFunction(src->getWidth(), src->getHeight(), src->getDepth(), sourceData, srcMapped.RowPitch, srcMapped.DepthPitch, + destData, destMapped.RowPitch, destMapped.DepthPitch); + + dest->unmap(); + src->unmap(); + + dest->markDirty(); +} + +bool Image11::isDirty() const +{ + // Make sure that this image is marked as dirty even if the staging texture hasn't been created yet + // if initialization is required before use. + return (mDirty && (mStagingTexture || gl_d3d11::RequiresTextureDataInitialization(mInternalFormat))); +} + +bool Image11::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance()); + return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, 0, width, height, 1); +} + +bool Image11::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance()); + return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, 0, width, height, 1); +} + +bool Image11::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) +{ + TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage->getStorageInstance()); + return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, zoffset, width, height, depth); +} + +bool Image11::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height) +{ + TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage->getStorageInstance()); + return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, arrayLayer, xoffset, yoffset, 0, width, height, 1); +} + +bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) +{ + if (mWidth != width || + mHeight != height || + mInternalFormat != internalformat || + forceRelease) + { + mRenderer = Renderer11::makeRenderer11(renderer); + + mWidth = width; + mHeight = height; + mDepth = depth; + mInternalFormat = internalformat; + mTarget = target; + + // compute the d3d format that will be used + mDXGIFormat = gl_d3d11::GetTexFormat(internalformat); + mActualFormat = d3d11_gl::GetInternalFormat(mDXGIFormat); + mRenderable = gl_d3d11::GetRTVFormat(internalformat) != DXGI_FORMAT_UNKNOWN; + + SafeRelease(mStagingTexture); + mDirty = gl_d3d11::RequiresTextureDataInitialization(mInternalFormat); + + return true; + } + + return false; +} + +DXGI_FORMAT Image11::getDXGIFormat() const +{ + // this should only happen if the image hasn't been redefined first + // which would be a bug by the caller + ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN); + + return mDXGIFormat; +} + +// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input +// into the target pixel rectangle. +void Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input) +{ + GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, type, width, unpackAlignment); + GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, type, width, height, unpackAlignment); + GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat); + + LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, type); + ASSERT(loadFunction != NULL); + + D3D11_MAPPED_SUBRESOURCE mappedImage; + HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); + if (FAILED(result)) + { + ERR("Could not map image for loading."); + return; + } + + uint8_t* offsetMappedData = (reinterpret_cast<uint8_t*>(mappedImage.pData) + (yoffset * mappedImage.RowPitch + xoffset * outputPixelSize + zoffset * mappedImage.DepthPitch)); + loadFunction(width, height, depth, + reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch, + offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); + + unmap(); +} + +void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + const void *input) +{ + GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, 1); + GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, height, 1); + + GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat); + GLuint outputBlockWidth = d3d11::GetBlockWidth(mDXGIFormat); + GLuint outputBlockHeight = d3d11::GetBlockHeight(mDXGIFormat); + + ASSERT(xoffset % outputBlockWidth == 0); + ASSERT(yoffset % outputBlockHeight == 0); + + LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, GL_UNSIGNED_BYTE); + ASSERT(loadFunction != NULL); + + D3D11_MAPPED_SUBRESOURCE mappedImage; + HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); + if (FAILED(result)) + { + ERR("Could not map image for loading."); + return; + } + + uint8_t* offsetMappedData = reinterpret_cast<uint8_t*>(mappedImage.pData) + ((yoffset / outputBlockHeight) * mappedImage.RowPitch + + (xoffset / outputBlockWidth) * outputPixelSize + + zoffset * mappedImage.DepthPitch); + + loadFunction(width, height, depth, + reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch, + offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); + + unmap(); +} + +void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +{ + gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer(); + + if (colorbuffer && colorbuffer->getActualFormat() == mActualFormat) + { + // No conversion needed-- use copyback fastpath + ID3D11Texture2D *colorBufferTexture = NULL; + unsigned int subresourceIndex = 0; + + if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture)) + { + D3D11_TEXTURE2D_DESC textureDesc; + colorBufferTexture->GetDesc(&textureDesc); + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ID3D11Texture2D* srcTex = NULL; + if (textureDesc.SampleDesc.Count > 1) + { + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = textureDesc.Width; + resolveDesc.Height = textureDesc.Height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = textureDesc.Format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex); + if (FAILED(result)) + { + ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); + return; + } + + deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format); + subresourceIndex = 0; + } + else + { + srcTex = colorBufferTexture; + srcTex->AddRef(); + } + + D3D11_BOX srcBox; + srcBox.left = x; + srcBox.right = x + width; + srcBox.top = y; + srcBox.bottom = y + height; + srcBox.front = 0; + srcBox.back = 1; + + deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, zoffset, srcTex, subresourceIndex, &srcBox); + + SafeRelease(srcTex); + SafeRelease(colorBufferTexture); + } + } + else + { + // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels + D3D11_MAPPED_SUBRESOURCE mappedImage; + HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); + if (FAILED(result)) + { + ERR("Failed to map texture for Image11::copy, HRESULT: 0x%X.", result); + return; + } + + // determine the offset coordinate into the destination buffer + GLsizei rowOffset = gl::GetPixelBytes(mActualFormat) * xoffset; + void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch; + + GLenum format = gl::GetFormat(mInternalFormat); + GLenum type = gl::GetType(mInternalFormat); + + mRenderer->readPixels(source, x, y, width, height, format, type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); + + unmap(); + } +} + +ID3D11Resource *Image11::getStagingTexture() +{ + createStagingTexture(); + + return mStagingTexture; +} + +unsigned int Image11::getStagingSubresource() +{ + createStagingTexture(); + + return mStagingSubresource; +} + +void Image11::createStagingTexture() +{ + if (mStagingTexture) + { + return; + } + + const DXGI_FORMAT dxgiFormat = getDXGIFormat(); + + if (mWidth > 0 && mHeight > 0 && mDepth > 0) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + int lodOffset = 1; + GLsizei width = mWidth; + GLsizei height = mHeight; + + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset); + + if (mTarget == GL_TEXTURE_3D) + { + ID3D11Texture3D *newTexture = NULL; + + D3D11_TEXTURE3D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.Depth = mDepth; + desc.MipLevels = lodOffset + 1; + desc.Format = dxgiFormat; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + + if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat)) + { + std::vector<D3D11_SUBRESOURCE_DATA> initialData; + std::vector< std::vector<BYTE> > textureData; + d3d11::GenerateInitialTextureData(mInternalFormat, width, height, mDepth, + lodOffset + 1, &initialData, &textureData); + + result = device->CreateTexture3D(&desc, initialData.data(), &newTexture); + } + else + { + result = device->CreateTexture3D(&desc, NULL, &newTexture); + } + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + return gl::error(GL_OUT_OF_MEMORY); + } + + mStagingTexture = newTexture; + mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); + } + else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP) + { + ID3D11Texture2D *newTexture = NULL; + + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = lodOffset + 1; + desc.ArraySize = 1; + desc.Format = dxgiFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + + if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat)) + { + std::vector<D3D11_SUBRESOURCE_DATA> initialData; + std::vector< std::vector<BYTE> > textureData; + d3d11::GenerateInitialTextureData(mInternalFormat, width, height, 1, + lodOffset + 1, &initialData, &textureData); + + result = device->CreateTexture2D(&desc, initialData.data(), &newTexture); + } + else + { + result = device->CreateTexture2D(&desc, NULL, &newTexture); + } + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + return gl::error(GL_OUT_OF_MEMORY); + } + + mStagingTexture = newTexture; + mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); + } + else + { + UNREACHABLE(); + } + } + + mDirty = false; +} + +HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) +{ + createStagingTexture(); + + HRESULT result = E_FAIL; + + if (mStagingTexture) + { + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map); + + // this can fail if the device is removed (from TDR) + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + } + else if (SUCCEEDED(result)) + { + mDirty = true; + } + } + + return result; +} + +void Image11::unmap() +{ + if (mStagingTexture) + { + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->Unmap(mStagingTexture, mStagingSubresource); + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Image11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h index 11a6492dc8..7d873a2794 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Image11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h @@ -10,7 +10,7 @@ #ifndef LIBGLESV2_RENDERER_IMAGE11_H_ #define LIBGLESV2_RENDERER_IMAGE11_H_ -#include "libGLESv2/renderer/Image.h" +#include "libGLESv2/renderer/d3d/ImageD3D.h" #include "common/debug.h" @@ -26,7 +26,7 @@ class Renderer11; class TextureStorageInterface2D; class TextureStorageInterfaceCube; -class Image11 : public Image +class Image11 : public ImageD3D { public: Image11(); @@ -38,20 +38,21 @@ class Image11 : public Image virtual bool isDirty() const; - virtual bool updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - virtual bool updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + virtual bool copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + virtual bool copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + virtual bool copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); + virtual bool copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height); - virtual bool redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease); + virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease); - virtual bool isRenderableFormat() const; DXGI_FORMAT getDXGIFormat() const; - virtual void loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLint unpackAlignment, const void *input); - virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + virtual void loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input); + virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, const void *input); - virtual void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); protected: HRESULT map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); @@ -60,14 +61,14 @@ class Image11 : public Image private: DISALLOW_COPY_AND_ASSIGN(Image11); - ID3D11Texture2D *getStagingTexture(); + ID3D11Resource *getStagingTexture(); unsigned int getStagingSubresource(); void createStagingTexture(); Renderer11 *mRenderer; DXGI_FORMAT mDXGIFormat; - ID3D11Texture2D *mStagingTexture; + ID3D11Resource *mStagingTexture; unsigned int mStagingSubresource; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/IndexBuffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.cpp index 44f9976d43..03e4e6611b 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/IndexBuffer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.cpp @@ -7,8 +7,8 @@ // IndexBuffer11.cpp: Defines the D3D11 IndexBuffer implementation. -#include "libGLESv2/renderer/d3d11/IndexBuffer11.h" -#include "libGLESv2/renderer/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" namespace rx { @@ -22,20 +22,12 @@ IndexBuffer11::IndexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) IndexBuffer11::~IndexBuffer11() { - if (mBuffer) - { - mBuffer->Release(); - mBuffer = NULL; - } + SafeRelease(mBuffer); } bool IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) { - if (mBuffer) - { - mBuffer->Release(); - mBuffer = NULL; - } + SafeRelease(mBuffer); updateSerial(); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/IndexBuffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h index 39a61946ad..e821b7f3d1 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/IndexBuffer11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h @@ -9,7 +9,7 @@ #ifndef LIBGLESV2_RENDERER_INDEXBUFFER11_H_ #define LIBGLESV2_RENDERER_INDEXBUFFER11_H_ -#include "libGLESv2/renderer/IndexBuffer.h" +#include "libGLESv2/renderer/d3d/IndexBuffer.h" namespace rx { diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/InputLayoutCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp index 4940b8c638..3536fafac9 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/InputLayoutCache.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp @@ -8,19 +8,35 @@ // InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches // D3D11 input layouts. -#include "libGLESv2/renderer/d3d11/InputLayoutCache.h" -#include "libGLESv2/renderer/d3d11/VertexBuffer11.h" -#include "libGLESv2/renderer/d3d11/BufferStorage11.h" -#include "libGLESv2/renderer/d3d11/ShaderExecutable11.h" +#include "libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h" +#include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h" #include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/renderer/VertexDataManager.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/renderer/d3d/VertexDataManager.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" #include "third_party/murmurhash/MurmurHash3.h" namespace rx { +static void GetInputLayout(const TranslatedAttribute translatedAttributes[gl::MAX_VERTEX_ATTRIBS], + gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]) +{ + for (unsigned int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const TranslatedAttribute &translatedAttribute = translatedAttributes[attributeIndex]; + + if (translatedAttributes[attributeIndex].active) + { + inputLayout[attributeIndex] = gl::VertexFormat(*translatedAttribute.attribute, + translatedAttribute.currentValueType); + } + } +} + const unsigned int InputLayoutCache::kMaxInputLayouts = 1024; InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts) @@ -31,7 +47,7 @@ InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInp mCurrentIL = NULL; for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { - mCurrentBuffers[i] = -1; + mCurrentBuffers[i] = NULL; mCurrentVertexStrides[i] = -1; mCurrentVertexOffsets[i] = -1; } @@ -53,7 +69,7 @@ void InputLayoutCache::clear() { for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++) { - i->second.inputLayout->Release(); + SafeRelease(i->second.inputLayout); } mInputLayoutMap.clear(); markDirty(); @@ -64,7 +80,7 @@ void InputLayoutCache::markDirty() mCurrentIL = NULL; for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { - mCurrentBuffers[i] = -1; + mCurrentBuffers[i] = NULL; mCurrentVertexStrides[i] = -1; mCurrentVertexOffsets[i] = -1; } @@ -84,22 +100,17 @@ GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::M InputLayoutKey ilKey = { 0 }; - ID3D11Buffer *vertexBuffers[gl::MAX_VERTEX_ATTRIBS] = { NULL }; - unsigned int vertexBufferSerials[gl::MAX_VERTEX_ATTRIBS] = { 0 }; - UINT vertexStrides[gl::MAX_VERTEX_ATTRIBS] = { 0 }; - UINT vertexOffsets[gl::MAX_VERTEX_ATTRIBS] = { 0 }; - static const char* semanticName = "TEXCOORD"; for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { if (attributes[i].active) { - VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer); - BufferStorage11 *bufferStorage = attributes[i].storage ? BufferStorage11::makeBufferStorage11(attributes[i].storage) : NULL; - D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA; + gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType); + DXGI_FORMAT dxgiFormat = gl_d3d11::GetNativeVertexFormat(vertexFormat); + // Record the type of the associated vertex shader vector in our key // This will prevent mismatched vertex shaders from using the same input layout GLint attributeSize; @@ -107,31 +118,28 @@ GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::M ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName; ilKey.elements[ilKey.elementCount].desc.SemanticIndex = i; - ilKey.elements[ilKey.elementCount].desc.Format = attributes[i].attribute->mArrayEnabled ? vertexBuffer->getDXGIFormat(*attributes[i].attribute) : DXGI_FORMAT_R32G32B32A32_FLOAT; + ilKey.elements[ilKey.elementCount].desc.Format = dxgiFormat; ilKey.elements[ilKey.elementCount].desc.InputSlot = i; ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0; ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass; ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor; ilKey.elementCount++; - - vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX) : vertexBuffer->getBuffer(); - vertexBufferSerials[i] = bufferStorage ? bufferStorage->getSerial() : vertexBuffer->getSerial(); - vertexStrides[i] = attributes[i].stride; - vertexOffsets[i] = attributes[i].offset; } } ID3D11InputLayout *inputLayout = NULL; - InputLayoutMap::iterator i = mInputLayoutMap.find(ilKey); - if (i != mInputLayoutMap.end()) + InputLayoutMap::iterator keyIter = mInputLayoutMap.find(ilKey); + if (keyIter != mInputLayoutMap.end()) { - inputLayout = i->second.inputLayout; - i->second.lastUsedTime = mCounter++; + inputLayout = keyIter->second.inputLayout; + keyIter->second.lastUsedTime = mCounter++; } else { - ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutable()); + gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS]; + GetInputLayout(attributes, shaderInputLayout); + ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutableForInputLayout(shaderInputLayout)); D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS]; for (unsigned int j = 0; j < ilKey.elementCount; ++j) @@ -159,7 +167,7 @@ GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::M leastRecentlyUsed = i; } } - leastRecentlyUsed->second.inputLayout->Release(); + SafeRelease(leastRecentlyUsed->second.inputLayout); mInputLayoutMap.erase(leastRecentlyUsed); } @@ -176,18 +184,45 @@ GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::M mCurrentIL = inputLayout; } + bool dirtyBuffers = false; + size_t minDiff = gl::MAX_VERTEX_ATTRIBS; + size_t maxDiff = 0; for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { - if (vertexBufferSerials[i] != mCurrentBuffers[i] || vertexStrides[i] != mCurrentVertexStrides[i] || - vertexOffsets[i] != mCurrentVertexOffsets[i]) + ID3D11Buffer *buffer = NULL; + + if (attributes[i].active) + { + VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer); + Buffer11 *bufferStorage = attributes[i].storage ? Buffer11::makeBuffer11(attributes[i].storage) : NULL; + + buffer = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK) + : vertexBuffer->getBuffer(); + } + + UINT vertexStride = attributes[i].stride; + UINT vertexOffset = attributes[i].offset; + + if (buffer != mCurrentBuffers[i] || vertexStride != mCurrentVertexStrides[i] || + vertexOffset != mCurrentVertexOffsets[i]) { - mDeviceContext->IASetVertexBuffers(i, 1, &vertexBuffers[i], &vertexStrides[i], &vertexOffsets[i]); - mCurrentBuffers[i] = vertexBufferSerials[i]; - mCurrentVertexStrides[i] = vertexStrides[i]; - mCurrentVertexOffsets[i] = vertexOffsets[i]; + dirtyBuffers = true; + minDiff = std::min(minDiff, static_cast<size_t>(i)); + maxDiff = std::max(maxDiff, static_cast<size_t>(i)); + + mCurrentBuffers[i] = buffer; + mCurrentVertexStrides[i] = vertexStride; + mCurrentVertexOffsets[i] = vertexOffset; } } + if (dirtyBuffers) + { + ASSERT(minDiff <= maxDiff && maxDiff < gl::MAX_VERTEX_ATTRIBS); + mDeviceContext->IASetVertexBuffers(minDiff, maxDiff - minDiff + 1, mCurrentBuffers + minDiff, + mCurrentVertexStrides + minDiff, mCurrentVertexOffsets + minDiff); + } + return GL_NO_ERROR; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/InputLayoutCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h index bb1a8eebcf..5d0ac60537 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/InputLayoutCache.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h @@ -67,7 +67,7 @@ class InputLayoutCache }; ID3D11InputLayout *mCurrentIL; - unsigned int mCurrentBuffers[gl::MAX_VERTEX_ATTRIBS]; + ID3D11Buffer *mCurrentBuffers[gl::MAX_VERTEX_ATTRIBS]; UINT mCurrentVertexStrides[gl::MAX_VERTEX_ATTRIBS]; UINT mCurrentVertexOffsets[gl::MAX_VERTEX_ATTRIBS]; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp new file mode 100644 index 0000000000..07040342c7 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp @@ -0,0 +1,253 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// PixelTransfer11.cpp: +// Implementation for buffer-to-texture and texture-to-buffer copies. +// Used to implement pixel transfers from unpack and to pack buffers. +// + +#include "libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" +#include "libGLESv2/Context.h" + +// Precompiled shaders +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexturevs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexturegs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4fps.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4ips.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4uips.h" + +namespace rx +{ + +PixelTransfer11::PixelTransfer11(Renderer11 *renderer) + : mRenderer(renderer), + mBufferToTextureVS(NULL), + mBufferToTextureGS(NULL), + mParamsConstantBuffer(NULL), + mCopyRasterizerState(NULL), + mCopyDepthStencilState(NULL) +{ + HRESULT result = S_OK; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = D3D11_CULL_NONE; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.ScissorEnable = FALSE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + result = device->CreateRasterizerState(&rasterDesc, &mCopyRasterizerState); + ASSERT(SUCCEEDED(result)); + + D3D11_DEPTH_STENCIL_DESC depthStencilDesc; + depthStencilDesc.DepthEnable = true; + depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.StencilEnable = FALSE; + depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + result = device->CreateDepthStencilState(&depthStencilDesc, &mCopyDepthStencilState); + ASSERT(SUCCEEDED(result)); + + D3D11_BUFFER_DESC constantBufferDesc = { 0 }; + constantBufferDesc.ByteWidth = rx::roundUp<UINT>(sizeof(CopyShaderParams), 32u); + constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + constantBufferDesc.MiscFlags = 0; + constantBufferDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&constantBufferDesc, NULL, &mParamsConstantBuffer); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mParamsConstantBuffer, "PixelTransfer11 constant buffer"); + + StructZero(&mParamsData); + + // init shaders + if (mRenderer->isLevel9()) + return; + + mBufferToTextureVS = d3d11::CompileVS(device, g_VS_BufferToTexture, "BufferToTexture VS"); + mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); + + buildShaderMap(); +} + +PixelTransfer11::~PixelTransfer11() +{ + for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) + { + SafeRelease(shaderMapIt->second); + } + + mBufferToTexturePSMap.clear(); + + SafeRelease(mBufferToTextureVS); + SafeRelease(mBufferToTextureGS); + SafeRelease(mParamsConstantBuffer); + SafeRelease(mCopyRasterizerState); + SafeRelease(mCopyDepthStencilState); +} + +void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, + const gl::PixelUnpackState &unpack, unsigned int offset, CopyShaderParams *parametersOut) +{ + StructZero(parametersOut); + + float texelCenterX = 0.5f / static_cast<float>(destSize.width - 1); + float texelCenterY = 0.5f / static_cast<float>(destSize.height - 1); + + unsigned int bytesPerPixel = gl::GetPixelBytes(internalFormat); + unsigned int alignmentBytes = static_cast<unsigned int>(unpack.alignment); + unsigned int alignmentPixels = (alignmentBytes <= bytesPerPixel ? 1 : alignmentBytes / bytesPerPixel); + + parametersOut->FirstPixelOffset = offset; + parametersOut->PixelsPerRow = static_cast<unsigned int>(destArea.width); + parametersOut->RowStride = roundUp(parametersOut->PixelsPerRow, alignmentPixels); + parametersOut->RowsPerSlice = static_cast<unsigned int>(destArea.height); + parametersOut->PositionOffset[0] = texelCenterX + (destArea.x / float(destSize.width)) * 2.0f - 1.0f; + parametersOut->PositionOffset[1] = texelCenterY + ((destSize.height - destArea.y - 1) / float(destSize.height)) * 2.0f - 1.0f; + parametersOut->PositionScale[0] = 2.0f / static_cast<float>(destSize.width); + parametersOut->PositionScale[1] = -2.0f / static_cast<float>(destSize.height); +} + +bool PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +{ + gl::Extents destSize = destRenderTarget->getExtents(); + + if (destArea.x < 0 || destArea.x + destArea.width > destSize.width || + destArea.y < 0 || destArea.y + destArea.height > destSize.height || + destArea.z < 0 || destArea.z + destArea.depth > destSize.depth ) + { + return false; + } + + const gl::Buffer &sourceBuffer = *unpack.pixelBuffer.get(); + + ASSERT(mRenderer->supportsFastCopyBufferToTexture(destinationFormat)); + + ID3D11PixelShader *pixelShader = findBufferToTexturePS(destinationFormat); + ASSERT(pixelShader); + + // The SRV must be in the proper read format, which may be different from the destination format + // EG: for half float data, we can load full precision floats with implicit conversion + GLenum unsizedFormat = gl::GetFormat(destinationFormat); + GLenum sourceFormat = gl::GetSizedInternalFormat(unsizedFormat, sourcePixelsType); + + DXGI_FORMAT srvFormat = gl_d3d11::GetSRVFormat(sourceFormat); + ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN); + Buffer11 *bufferStorage11 = Buffer11::makeBuffer11(sourceBuffer.getImplementation()); + ID3D11ShaderResourceView *bufferSRV = bufferStorage11->getSRV(srvFormat); + ASSERT(bufferSRV != NULL); + + ID3D11RenderTargetView *textureRTV = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(textureRTV != NULL); + + CopyShaderParams shaderParams; + setBufferToTextureCopyParams(destArea, destSize, sourceFormat, unpack, offset, &shaderParams); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ID3D11ShaderResourceView *nullSRV = NULL; + ID3D11Buffer *nullBuffer = NULL; + UINT zero = 0; + + // Are we doing a 2D or 3D copy? + ID3D11GeometryShader *geometryShader = ((destSize.depth > 1) ? mBufferToTextureGS : NULL); + + deviceContext->VSSetShader(mBufferToTextureVS, NULL, 0); + deviceContext->GSSetShader(geometryShader, NULL, 0); + deviceContext->PSSetShader(pixelShader, NULL, 0); + deviceContext->PSSetShaderResources(0, 1, &bufferSRV); + deviceContext->IASetInputLayout(NULL); + deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(mCopyDepthStencilState, 0xFFFFFFFF); + deviceContext->RSSetState(mCopyRasterizerState); + + mRenderer->setOneTimeRenderTarget(textureRTV); + + if (!StructEquals(mParamsData, shaderParams)) + { + d3d11::SetBufferData(deviceContext, mParamsConstantBuffer, shaderParams); + mParamsData = shaderParams; + } + + deviceContext->VSSetConstantBuffers(0, 1, &mParamsConstantBuffer); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + UINT numPixels = (destArea.width * destArea.height * destArea.depth); + deviceContext->Draw(numPixels, 0); + + // Unbind textures and render targets and vertex buffer + deviceContext->PSSetShaderResources(0, 1, &nullSRV); + deviceContext->VSSetConstantBuffers(0, 1, &nullBuffer); + + mRenderer->markAllStateDirty(); + + return true; +} + +void PixelTransfer11::buildShaderMap() +{ + ID3D11Device *device = mRenderer->getDevice(); + + mBufferToTexturePSMap[GL_FLOAT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4F, "BufferToTexture RGBA ps"); + mBufferToTexturePSMap[GL_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4I, "BufferToTexture RGBA-I ps"); + mBufferToTexturePSMap[GL_UNSIGNED_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4UI, "BufferToTexture RGBA-UI ps"); +} + +ID3D11PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const +{ + GLenum componentType = gl::GetComponentType(internalFormat); + + if (componentType == GL_SIGNED_NORMALIZED || componentType == GL_UNSIGNED_NORMALIZED) + { + componentType = GL_FLOAT; + } + + auto shaderMapIt = mBufferToTexturePSMap.find(componentType); + return (shaderMapIt == mBufferToTexturePSMap.end() ? NULL : shaderMapIt->second); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h new file mode 100644 index 0000000000..2e2fee8f50 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h @@ -0,0 +1,82 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// PixelTransfer11.h: +// Buffer-to-Texture and Texture-to-Buffer data transfers. +// Used to implement pixel unpack and pixel pack buffers in ES3. + +#ifndef LIBGLESV2_PIXELTRANSFER11_H_ +#define LIBGLESV2_PIXELTRANSFER11_H_ + +#include "common/platform.h" + +namespace gl +{ + +class Buffer; +struct Box; +struct Extents; +struct PixelUnpackState; + +} + +namespace rx +{ +class Renderer11; +class RenderTarget; + +class PixelTransfer11 +{ + public: + explicit PixelTransfer11(Renderer11 *renderer); + ~PixelTransfer11(); + + static bool supportsBufferToTextureCopy(GLenum internalFormat); + + // unpack: the source buffer is stored in the unpack state, and buffer strides + // offset: the start of the data within the unpack buffer + // destRenderTarget: individual slice/layer of a target texture + // destinationFormat/sourcePixelsType: determines shaders + shader parameters + // destArea: the sub-section of destRenderTarget to copy to + bool copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + private: + + struct CopyShaderParams + { + unsigned int FirstPixelOffset; + unsigned int PixelsPerRow; + unsigned int RowStride; + unsigned int RowsPerSlice; + float PositionOffset[2]; + float PositionScale[2]; + int TexLocationOffset[2]; + int TexLocationScale[2]; + }; + + static void setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, + const gl::PixelUnpackState &unpack, unsigned int offset, CopyShaderParams *parametersOut); + + void buildShaderMap(); + ID3D11PixelShader *findBufferToTexturePS(GLenum internalFormat) const; + + Renderer11 *mRenderer; + + std::map<GLenum, ID3D11PixelShader *> mBufferToTexturePSMap; + ID3D11VertexShader *mBufferToTextureVS; + ID3D11GeometryShader *mBufferToTextureGS; + ID3D11Buffer *mParamsConstantBuffer; + CopyShaderParams mParamsData; + + ID3D11RasterizerState *mCopyRasterizerState; + ID3D11DepthStencilState *mCopyDepthStencilState; + +}; + +} + +#endif // LIBGLESV2_PIXELTRANSFER11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp new file mode 100644 index 0000000000..17cf5cad47 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp @@ -0,0 +1,155 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl. + +#include "libGLESv2/renderer/d3d/d3d11/Query11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/main.h" + +namespace rx +{ + +static bool checkOcclusionQuery(ID3D11DeviceContext *context, ID3D11Query *query, UINT64 *numPixels) +{ + HRESULT result = context->GetData(query, numPixels, sizeof(UINT64), 0); + return (result == S_OK); +} + +static bool checkStreamOutPrimitivesWritten(ID3D11DeviceContext *context, ID3D11Query *query, UINT64 *numPrimitives) +{ + D3D11_QUERY_DATA_SO_STATISTICS soStats = { 0 }; + HRESULT result = context->GetData(query, &soStats, sizeof(D3D11_QUERY_DATA_SO_STATISTICS), 0); + *numPrimitives = soStats.NumPrimitivesWritten; + return (result == S_OK); +} + +Query11::Query11(rx::Renderer11 *renderer, GLenum type) : QueryImpl(type) +{ + mRenderer = renderer; + mQuery = NULL; +} + +Query11::~Query11() +{ + SafeRelease(mQuery); +} + +void Query11::begin() +{ + if (mQuery == NULL) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = gl_d3d11::ConvertQueryType(getType()); + queryDesc.MiscFlags = 0; + + if (FAILED(mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery))) + { + return gl::error(GL_OUT_OF_MEMORY); + } + } + + mRenderer->getDeviceContext()->Begin(mQuery); +} + +void Query11::end() +{ + ASSERT(mQuery); + mRenderer->getDeviceContext()->End(mQuery); + + mStatus = GL_FALSE; + mResult = GL_FALSE; +} + +GLuint Query11::getResult() +{ + if (mQuery != NULL) + { + while (!testQuery()) + { + Sleep(0); + // explicitly check for device loss, some drivers seem to return S_FALSE + // if the device is lost + if (mRenderer->testDeviceLost(true)) + { + return gl::error(GL_OUT_OF_MEMORY, 0); + } + } + } + + return mResult; +} + +GLboolean Query11::isResultAvailable() +{ + if (mQuery != NULL) + { + testQuery(); + } + + return mStatus; +} + +GLboolean Query11::testQuery() +{ + if (mQuery != NULL && mStatus != GL_TRUE) + { + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + bool queryFinished = false; + switch (getType()) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + { + UINT64 numPixels = 0; + queryFinished = checkOcclusionQuery(context, mQuery, &numPixels); + if (queryFinished) + { + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + } + } + break; + + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + { + UINT64 numPrimitives = 0; + queryFinished = checkStreamOutPrimitivesWritten(context, mQuery, &numPrimitives); + if (queryFinished) + { + mResult = static_cast<GLuint>(numPrimitives); + } + } + break; + + default: + UNREACHABLE(); + break; + } + + if (queryFinished) + { + mStatus = GL_TRUE; + } + else if (mRenderer->testDeviceLost(true)) + { + return gl::error(GL_OUT_OF_MEMORY, GL_TRUE); + } + + return mStatus; + } + + return GL_TRUE; // prevent blocking when query is null +} + +bool Query11::isStarted() const +{ + return (mQuery != NULL); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Query11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h index 0a03de77ca..7a3df46d4f 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Query11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h @@ -21,10 +21,11 @@ class Query11 : public QueryImpl Query11(rx::Renderer11 *renderer, GLenum type); virtual ~Query11(); - void begin(); - void end(); - GLuint getResult(); - GLboolean isResultAvailable(); + virtual void begin(); + virtual void end(); + virtual GLuint getResult(); + virtual GLboolean isResultAvailable(); + virtual bool isStarted() const; private: DISALLOW_COPY_AND_ASSIGN(Query11); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/RenderStateCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp index a1c324cd80..b185d97604 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/RenderStateCache.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -8,18 +8,28 @@ // RenderStateCache.cpp: Defines rx::RenderStateCache, a cache of Direct3D render // state objects. -#include "libGLESv2/renderer/d3d11/RenderStateCache.h" -#include "libGLESv2/renderer/d3d11/renderer11_utils.h" - +#include "libGLESv2/renderer/d3d/d3d11/RenderStateCache.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" #include "libGLESv2/Framebuffer.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/utilities.h" +#include "libGLESv2/FramebufferAttachment.h" + #include "common/debug.h" #include "third_party/murmurhash/MurmurHash3.h" namespace rx { +template <typename mapType> +static void ClearStateMap(mapType &map) +{ + for (typename mapType::iterator i = map.begin(); i != map.end(); i++) + { + SafeRelease(i->second.first); + } + map.clear(); +} + // MSDN's documentation of ID3D11Device::CreateBlendState, ID3D11Device::CreateRasterizerState, // ID3D11Device::CreateDepthStencilState and ID3D11Device::CreateSamplerState claims the maximum // number of unique states of each type an application can create is 4096 @@ -49,29 +59,10 @@ void RenderStateCache::initialize(ID3D11Device *device) void RenderStateCache::clear() { - for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++) - { - i->second.first->Release(); - } - mBlendStateCache.clear(); - - for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++) - { - i->second.first->Release(); - } - mRasterizerStateCache.clear(); - - for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++) - { - i->second.first->Release(); - } - mDepthStencilStateCache.clear(); - - for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++) - { - i->second.first->Release(); - } - mSamplerStateCache.clear(); + ClearStateMap(mBlendStateCache); + ClearStateMap(mRasterizerStateCache); + ClearStateMap(mDepthStencilStateCache); + ClearStateMap(mSamplerStateCache); } std::size_t RenderStateCache::hashBlendState(const BlendStateKey &blendState) @@ -79,16 +70,16 @@ std::size_t RenderStateCache::hashBlendState(const BlendStateKey &blendState) static const unsigned int seed = 0xABCDEF98; std::size_t hash = 0; - MurmurHash3_x86_32(&blendState, sizeof(BlendStateKey), seed, &hash); + MurmurHash3_x86_32(&blendState, sizeof(gl::BlendState), seed, &hash); return hash; } bool RenderStateCache::compareBlendStates(const BlendStateKey &a, const BlendStateKey &b) { - return memcmp(&a, &b, sizeof(gl::BlendState)) == 0; + return memcmp(&a, &b, sizeof(BlendStateKey)) == 0; } -ID3D11BlendState *RenderStateCache::getBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState) +ID3D11BlendState *RenderStateCache::getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState) { if (!mDevice) { @@ -102,19 +93,18 @@ ID3D11BlendState *RenderStateCache::getBlendState(gl::Framebuffer *framebuffer, key.blendState = blendState; for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) { - gl::Renderbuffer *renderBuffer = framebuffer->getColorbuffer(i); - if (renderBuffer) + const gl::FramebufferAttachment *attachment = framebuffer->getColorbuffer(i); + if (attachment) { if (i > 0) { mrt = true; } - GLenum internalFormat = renderBuffer->getInternalFormat(); - key.rtChannels[i][0] = gl::GetRedSize(internalFormat) > 0; - key.rtChannels[i][1] = gl::GetGreenSize(internalFormat) > 0; - key.rtChannels[i][2] = gl::GetBlueSize(internalFormat) > 0;; - key.rtChannels[i][3] = gl::GetAlphaSize(internalFormat) > 0; + key.rtChannels[i][0] = attachment->getRedSize() > 0; + key.rtChannels[i][1] = attachment->getGreenSize() > 0; + key.rtChannels[i][2] = attachment->getBlueSize() > 0; + key.rtChannels[i][3] = attachment->getAlphaSize() > 0; } else { @@ -125,10 +115,10 @@ ID3D11BlendState *RenderStateCache::getBlendState(gl::Framebuffer *framebuffer, } } - BlendStateMap::iterator i = mBlendStateCache.find(key); - if (i != mBlendStateCache.end()) + BlendStateMap::iterator keyIter = mBlendStateCache.find(key); + if (keyIter != mBlendStateCache.end()) { - BlendStateCounterPair &state = i->second; + BlendStateCounterPair &state = keyIter->second; state.second = mCounter++; return state.first; } @@ -147,7 +137,7 @@ ID3D11BlendState *RenderStateCache::getBlendState(gl::Framebuffer *framebuffer, leastRecentlyUsed = i; } } - leastRecentlyUsed->second.first->Release(); + SafeRelease(leastRecentlyUsed->second.first); mBlendStateCache.erase(leastRecentlyUsed); } @@ -206,8 +196,7 @@ bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, cons return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0; } -ID3D11RasterizerState *RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState, - bool scissorEnabled, unsigned int depthSize) +ID3D11RasterizerState *RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled) { if (!mDevice) { @@ -215,15 +204,14 @@ ID3D11RasterizerState *RenderStateCache::getRasterizerState(const gl::Rasterizer return NULL; } - RasterizerStateKey key; + RasterizerStateKey key = { 0 }; key.rasterizerState = rasterState; key.scissorEnabled = scissorEnabled; - key.depthSize = depthSize; - RasterizerStateMap::iterator i = mRasterizerStateCache.find(key); - if (i != mRasterizerStateCache.end()) + RasterizerStateMap::iterator keyIter = mRasterizerStateCache.find(key); + if (keyIter != mRasterizerStateCache.end()) { - RasterizerStateCounterPair &state = i->second; + RasterizerStateCounterPair &state = keyIter->second; state.second = mCounter++; return state.first; } @@ -242,7 +230,7 @@ ID3D11RasterizerState *RenderStateCache::getRasterizerState(const gl::Rasterizer leastRecentlyUsed = i; } } - leastRecentlyUsed->second.first->Release(); + SafeRelease(leastRecentlyUsed->second.first); mRasterizerStateCache.erase(leastRecentlyUsed); } @@ -258,14 +246,23 @@ ID3D11RasterizerState *RenderStateCache::getRasterizerState(const gl::Rasterizer rasterDesc.FillMode = D3D11_FILL_SOLID; rasterDesc.CullMode = cullMode; rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE: TRUE; - rasterDesc.DepthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast<int>(depthSize)); rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of zero will preform no clamping, must be tested though. - rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor; rasterDesc.DepthClipEnable = TRUE; rasterDesc.ScissorEnable = scissorEnabled ? TRUE : FALSE; rasterDesc.MultisampleEnable = rasterState.multiSample; rasterDesc.AntialiasedLineEnable = FALSE; + if (rasterState.polygonOffsetFill) + { + rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor; + rasterDesc.DepthBias = (INT)rasterState.polygonOffsetUnits; + } + else + { + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBias = 0; + } + ID3D11RasterizerState *dx11RasterizerState = NULL; HRESULT result = mDevice->CreateRasterizerState(&rasterDesc, &dx11RasterizerState); if (FAILED(result) || !dx11RasterizerState) @@ -302,10 +299,10 @@ ID3D11DepthStencilState *RenderStateCache::getDepthStencilState(const gl::DepthS return NULL; } - DepthStencilStateMap::iterator i = mDepthStencilStateCache.find(dsState); - if (i != mDepthStencilStateCache.end()) + DepthStencilStateMap::iterator keyIter = mDepthStencilStateCache.find(dsState); + if (keyIter != mDepthStencilStateCache.end()) { - DepthStencilStateCounterPair &state = i->second; + DepthStencilStateCounterPair &state = keyIter->second; state.second = mCounter++; return state.first; } @@ -324,7 +321,7 @@ ID3D11DepthStencilState *RenderStateCache::getDepthStencilState(const gl::DepthS leastRecentlyUsed = i; } } - leastRecentlyUsed->second.first->Release(); + SafeRelease(leastRecentlyUsed->second.first); mDepthStencilStateCache.erase(leastRecentlyUsed); } @@ -380,10 +377,10 @@ ID3D11SamplerState *RenderStateCache::getSamplerState(const gl::SamplerState &sa return NULL; } - SamplerStateMap::iterator i = mSamplerStateCache.find(samplerState); - if (i != mSamplerStateCache.end()) + SamplerStateMap::iterator keyIter = mSamplerStateCache.find(samplerState); + if (keyIter != mSamplerStateCache.end()) { - SamplerStateCounterPair &state = i->second; + SamplerStateCounterPair &state = keyIter->second; state.second = mCounter++; return state.first; } @@ -402,25 +399,25 @@ ID3D11SamplerState *RenderStateCache::getSamplerState(const gl::SamplerState &sa leastRecentlyUsed = i; } } - leastRecentlyUsed->second.first->Release(); + SafeRelease(leastRecentlyUsed->second.first); mSamplerStateCache.erase(leastRecentlyUsed); } D3D11_SAMPLER_DESC samplerDesc; - samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, samplerState.maxAnisotropy); + samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, + samplerState.maxAnisotropy, samplerState.compareMode); samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS); samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT); - samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.MipLODBias = static_cast<float>(samplerState.lodOffset); + samplerDesc.AddressW = gl_d3d11::ConvertTextureWrap(samplerState.wrapR); + samplerDesc.MipLODBias = 0; samplerDesc.MaxAnisotropy = samplerState.maxAnisotropy; - samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.compareFunc); samplerDesc.BorderColor[0] = 0.0f; samplerDesc.BorderColor[1] = 0.0f; samplerDesc.BorderColor[2] = 0.0f; samplerDesc.BorderColor[3] = 0.0f; - samplerDesc.MinLOD = gl_d3d11::ConvertMinLOD(samplerState.minFilter, samplerState.lodOffset); - samplerDesc.MaxLOD = mDevice->GetFeatureLevel() >= D3D_FEATURE_LEVEL_10_0 - ? gl_d3d11::ConvertMaxLOD(samplerState.minFilter, samplerState.lodOffset) : FLT_MAX; + samplerDesc.MinLOD = samplerState.minLod; + samplerDesc.MaxLOD = samplerState.maxLod; ID3D11SamplerState *dx11SamplerState = NULL; HRESULT result = mDevice->CreateSamplerState(&samplerDesc, &dx11SamplerState); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/RenderStateCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h index b4b871a4bd..e6380fbd82 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/RenderStateCache.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -20,6 +20,7 @@ class Framebuffer; namespace rx { +class Renderer11; class RenderStateCache { @@ -30,10 +31,8 @@ class RenderStateCache void initialize(ID3D11Device *device); void clear(); - // Increments refcount on the returned blend state, Release() must be called. - ID3D11BlendState *getBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState); - ID3D11RasterizerState *getRasterizerState(const gl::RasterizerState &rasterState, - bool scissorEnabled, unsigned int depthSize); + ID3D11BlendState *getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState); + ID3D11RasterizerState *getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled); ID3D11DepthStencilState *getDepthStencilState(const gl::DepthStencilState &dsState); ID3D11SamplerState *getSamplerState(const gl::SamplerState &samplerState); @@ -63,7 +62,6 @@ class RenderStateCache { gl::RasterizerState rasterizerState; bool scissorEnabled; - unsigned int depthSize; }; static std::size_t hashRasterizerState(const RasterizerStateKey &rasterState); static bool compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/RenderTarget11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp index 3707097aa4..6aa75ae5bd 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/RenderTarget11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp @@ -8,26 +8,67 @@ // RenderTarget11.cpp: Implements a DX11-specific wrapper for ID3D11View pointers // retained by Renderbuffers. -#include "libGLESv2/renderer/d3d11/RenderTarget11.h" -#include "libGLESv2/renderer/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" #include "libGLESv2/main.h" namespace rx { -static unsigned int getRTVSubresourceIndex(ID3D11Texture2D *texture, ID3D11RenderTargetView *view) +static bool getTextureProperties(ID3D11Resource *resource, unsigned int *mipLevels, unsigned int *samples) +{ + ID3D11Texture1D *texture1D = d3d11::DynamicCastComObject<ID3D11Texture1D>(resource); + if (texture1D) + { + D3D11_TEXTURE1D_DESC texDesc; + texture1D->GetDesc(&texDesc); + SafeRelease(texture1D); + + *mipLevels = texDesc.MipLevels; + *samples = 0; + + return true; + } + + ID3D11Texture2D *texture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(resource); + if (texture2D) + { + D3D11_TEXTURE2D_DESC texDesc; + texture2D->GetDesc(&texDesc); + SafeRelease(texture2D); + + *mipLevels = texDesc.MipLevels; + *samples = texDesc.SampleDesc.Count > 1 ? texDesc.SampleDesc.Count : 0; + + return true; + } + + ID3D11Texture3D *texture3D = d3d11::DynamicCastComObject<ID3D11Texture3D>(resource); + if (texture3D) + { + D3D11_TEXTURE3D_DESC texDesc; + texture3D->GetDesc(&texDesc); + SafeRelease(texture3D); + + *mipLevels = texDesc.MipLevels; + *samples = 0; + + return true; + } + + return false; +} + +static unsigned int getRTVSubresourceIndex(ID3D11Resource *resource, ID3D11RenderTargetView *view) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; view->GetDesc(&rtvDesc); - D3D11_TEXTURE2D_DESC texDesc; - texture->GetDesc(&texDesc); - unsigned int mipSlice = 0; unsigned int arraySlice = 0; - unsigned int mipLevels = texDesc.MipLevels; switch (rtvDesc.ViewDimension) { @@ -76,20 +117,19 @@ static unsigned int getRTVSubresourceIndex(ID3D11Texture2D *texture, ID3D11Rende break; } + unsigned int mipLevels, samples; + getTextureProperties(resource, &mipLevels, &samples); + return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); } -static unsigned int getDSVSubresourceIndex(ID3D11Texture2D *texture, ID3D11DepthStencilView *view) +static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11DepthStencilView *view) { D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; view->GetDesc(&dsvDesc); - D3D11_TEXTURE2D_DESC texDesc; - texture->GetDesc(&texDesc); - unsigned int mipSlice = 0; unsigned int arraySlice = 0; - unsigned int mipLevels = texDesc.MipLevels; switch (dsvDesc.ViewDimension) { @@ -123,7 +163,7 @@ static unsigned int getDSVSubresourceIndex(ID3D11Texture2D *texture, ID3D11Depth arraySlice = dsvDesc.Texture2DMSArray.FirstArraySlice; break; - case D3D11_RTV_DIMENSION_UNKNOWN: + case D3D11_DSV_DIMENSION_UNKNOWN: UNIMPLEMENTED(); break; @@ -132,16 +172,37 @@ static unsigned int getDSVSubresourceIndex(ID3D11Texture2D *texture, ID3D11Depth break; } + unsigned int mipLevels, samples; + getTextureProperties(resource, &mipLevels, &samples); + return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); } -RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Texture2D *tex, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height) +RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Resource *resource, + ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth) { mRenderer = Renderer11::makeRenderer11(renderer); - mTexture = tex; + + mTexture = resource; + if (mTexture) + { + mTexture->AddRef(); + } + mRenderTarget = rtv; + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + mDepthStencil = NULL; + mShaderResource = srv; + if (mShaderResource) + { + mShaderResource->AddRef(); + } + mSubresourceIndex = 0; if (mRenderTarget && mTexture) @@ -149,26 +210,45 @@ RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, D3D11_RENDER_TARGET_VIEW_DESC desc; mRenderTarget->GetDesc(&desc); - D3D11_TEXTURE2D_DESC texDesc; - mTexture->GetDesc(&texDesc); + unsigned int mipLevels, samples; + getTextureProperties(mTexture, &mipLevels, &samples); mSubresourceIndex = getRTVSubresourceIndex(mTexture, mRenderTarget); mWidth = width; mHeight = height; - mSamples = (texDesc.SampleDesc.Count > 1) ? texDesc.SampleDesc.Count : 0; + mDepth = depth; + mSamples = samples; - mInternalFormat = d3d11_gl::ConvertTextureInternalFormat(desc.Format); - mActualFormat = d3d11_gl::ConvertTextureInternalFormat(desc.Format); + mInternalFormat = d3d11_gl::GetInternalFormat(desc.Format); + mActualFormat = d3d11_gl::GetInternalFormat(desc.Format); } } -RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Texture2D *tex, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height) +RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Resource *resource, + ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth) { mRenderer = Renderer11::makeRenderer11(renderer); - mTexture = tex; + + mTexture = resource; + if (mTexture) + { + mTexture->AddRef(); + } + mRenderTarget = NULL; + mDepthStencil = dsv; + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + mShaderResource = srv; + if (mShaderResource) + { + mShaderResource->AddRef(); + } + mSubresourceIndex = 0; if (mDepthStencil && mTexture) @@ -176,20 +256,21 @@ RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, D3D11_DEPTH_STENCIL_VIEW_DESC desc; mDepthStencil->GetDesc(&desc); - D3D11_TEXTURE2D_DESC texDesc; - mTexture->GetDesc(&texDesc); + unsigned int mipLevels, samples; + getTextureProperties(mTexture, &mipLevels, &samples); mSubresourceIndex = getDSVSubresourceIndex(mTexture, mDepthStencil); mWidth = width; mHeight = height; - mSamples = (texDesc.SampleDesc.Count > 1) ? texDesc.SampleDesc.Count : 0; + mDepth = depth; + mSamples = samples; - mInternalFormat = d3d11_gl::ConvertTextureInternalFormat(desc.Format); - mActualFormat = d3d11_gl::ConvertTextureInternalFormat(desc.Format); + mInternalFormat = d3d11_gl::GetInternalFormat(desc.Format); + mActualFormat = d3d11_gl::GetInternalFormat(desc.Format); } } -RenderTarget11::RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum format, GLsizei samples, bool depth) +RenderTarget11::RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples) { mRenderer = Renderer11::makeRenderer11(renderer); mTexture = NULL; @@ -197,9 +278,13 @@ RenderTarget11::RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height mDepthStencil = NULL; mShaderResource = NULL; - DXGI_FORMAT requestedFormat = gl_d3d11::ConvertRenderbufferFormat(format); + DXGI_FORMAT texFormat = gl_d3d11::GetTexFormat(internalFormat); + DXGI_FORMAT srvFormat = gl_d3d11::GetSRVFormat(internalFormat); + DXGI_FORMAT rtvFormat = gl_d3d11::GetRTVFormat(internalFormat); + DXGI_FORMAT dsvFormat = gl_d3d11::GetDSVFormat(internalFormat); - int supportedSamples = mRenderer->getNearestSupportedSamples(requestedFormat, samples); + DXGI_FORMAT multisampleFormat = (dsvFormat != DXGI_FORMAT_UNKNOWN ? dsvFormat : rtvFormat); + int supportedSamples = mRenderer->getNearestSupportedSamples(multisampleFormat, samples); if (supportedSamples < 0) { gl::error(GL_OUT_OF_MEMORY); @@ -214,16 +299,35 @@ RenderTarget11::RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height desc.Height = height; desc.MipLevels = 1; desc.ArraySize = 1; - desc.Format = requestedFormat; + desc.Format = texFormat; desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; - desc.BindFlags = (depth ? D3D11_BIND_DEPTH_STENCIL : (D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE)); + + // If a rendertarget or depthstencil format exists for this texture format, + // we'll flag it to allow binding that way. Shader resource views are a little + // more complicated. + bool bindRTV = false, bindDSV = false, bindSRV = false; + bindRTV = (rtvFormat != DXGI_FORMAT_UNKNOWN); + bindDSV = (dsvFormat != DXGI_FORMAT_UNKNOWN); + if (srvFormat != DXGI_FORMAT_UNKNOWN) + { + // Multisample targets flagged for binding as depth stencil cannot also be + // flagged for binding as SRV, so make certain not to add the SRV flag for + // these targets. + bindSRV = !(dsvFormat != DXGI_FORMAT_UNKNOWN && desc.SampleDesc.Count > 1); + } + + desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET : 0) | + (bindDSV ? D3D11_BIND_DEPTH_STENCIL : 0) | + (bindSRV ? D3D11_BIND_SHADER_RESOURCE : 0); ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + ID3D11Texture2D *texture = NULL; + HRESULT result = device->CreateTexture2D(&desc, NULL, &texture); + mTexture = texture; if (result == E_OUTOFMEMORY) { @@ -232,10 +336,28 @@ RenderTarget11::RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height } ASSERT(SUCCEEDED(result)); - if (depth) + if (bindSRV) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = srvFormat; + srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.MipLevels = 1; + result = device->CreateShaderResourceView(mTexture, &srvDesc, &mShaderResource); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(mTexture); + gl::error(GL_OUT_OF_MEMORY); + return; + } + ASSERT(SUCCEEDED(result)); + } + + if (bindDSV) { D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = requestedFormat; + dsvDesc.Format = dsvFormat; dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS; dsvDesc.Texture2D.MipSlice = 0; dsvDesc.Flags = 0; @@ -243,82 +365,57 @@ RenderTarget11::RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height if (result == E_OUTOFMEMORY) { - mTexture->Release(); - mTexture = NULL; + SafeRelease(mTexture); + SafeRelease(mShaderResource); gl::error(GL_OUT_OF_MEMORY); + return; } ASSERT(SUCCEEDED(result)); } - else + + if (bindRTV) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = requestedFormat; + rtvDesc.Format = rtvFormat; rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS; rtvDesc.Texture2D.MipSlice = 0; result = device->CreateRenderTargetView(mTexture, &rtvDesc, &mRenderTarget); if (result == E_OUTOFMEMORY) { - mTexture->Release(); - mTexture = NULL; + SafeRelease(mTexture); + SafeRelease(mShaderResource); + SafeRelease(mDepthStencil); gl::error(GL_OUT_OF_MEMORY); return; } ASSERT(SUCCEEDED(result)); - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = requestedFormat; - srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; - srvDesc.Texture2D.MostDetailedMip = 0; - srvDesc.Texture2D.MipLevels = 1; - result = device->CreateShaderResourceView(mTexture, &srvDesc, &mShaderResource); - - if (result == E_OUTOFMEMORY) + if (gl_d3d11::RequiresTextureDataInitialization(internalFormat)) { - mTexture->Release(); - mTexture = NULL; - mRenderTarget->Release(); - mRenderTarget = NULL; - gl::error(GL_OUT_OF_MEMORY); - return; + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + const float clearValues[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + context->ClearRenderTargetView(mRenderTarget, clearValues); } - ASSERT(SUCCEEDED(result)); } } mWidth = width; mHeight = height; - mInternalFormat = format; + mDepth = 1; + mInternalFormat = internalFormat; mSamples = supportedSamples; - mActualFormat = d3d11_gl::ConvertTextureInternalFormat(requestedFormat); + mActualFormat = d3d11_gl::GetInternalFormat(texFormat); mSubresourceIndex = D3D11CalcSubresource(0, 0, 1); } RenderTarget11::~RenderTarget11() { - if (mTexture) - { - mTexture->Release(); - mTexture = NULL; - } - - if (mRenderTarget) - { - mRenderTarget->Release(); - mRenderTarget = NULL; - } - - if (mDepthStencil) - { - mDepthStencil->Release(); - mDepthStencil = NULL; - } - - if (mShaderResource) - { - mShaderResource->Release(); - mShaderResource = NULL; - } + SafeRelease(mTexture); + SafeRelease(mRenderTarget); + SafeRelease(mDepthStencil); + SafeRelease(mShaderResource); } RenderTarget11 *RenderTarget11::makeRenderTarget11(RenderTarget *target) @@ -327,7 +424,12 @@ RenderTarget11 *RenderTarget11::makeRenderTarget11(RenderTarget *target) return static_cast<rx::RenderTarget11*>(target); } -ID3D11Texture2D *RenderTarget11::getTexture() const +void RenderTarget11::invalidate(GLint x, GLint y, GLsizei width, GLsizei height) +{ + // Currently a no-op +} + +ID3D11Resource *RenderTarget11::getTexture() const { return mTexture; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/RenderTarget11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h index 97827f2639..ba9f76e5de 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/RenderTarget11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h @@ -20,14 +20,17 @@ class Renderer11; class RenderTarget11 : public RenderTarget { public: - RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Texture2D *tex, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height); - RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Texture2D *tex, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height); - RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum format, GLsizei samples, bool depth); + // RenderTarget11 takes ownership of any D3D11 resources it is given and will AddRef them + RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth); + RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth); + RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples); virtual ~RenderTarget11(); static RenderTarget11 *makeRenderTarget11(RenderTarget *renderTarget); - ID3D11Texture2D *getTexture() const; + virtual void invalidate(GLint x, GLint y, GLsizei width, GLsizei height); + + ID3D11Resource *getTexture() const; ID3D11RenderTargetView *getRenderTargetView() const; ID3D11DepthStencilView *getDepthStencilView() const; ID3D11ShaderResourceView *getShaderResourceView() const; @@ -38,7 +41,7 @@ class RenderTarget11 : public RenderTarget DISALLOW_COPY_AND_ASSIGN(RenderTarget11); unsigned int mSubresourceIndex; - ID3D11Texture2D *mTexture; + ID3D11Resource *mTexture; ID3D11RenderTargetView *mRenderTarget; ID3D11DepthStencilView *mDepthStencil; ID3D11ShaderResourceView *mShaderResource; @@ -48,4 +51,4 @@ class RenderTarget11 : public RenderTarget } -#endif LIBGLESV2_RENDERER_RENDERTARGET11_H_
\ No newline at end of file +#endif LIBGLESV2_RENDERER_RENDERTARGET11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp index e70727c65e..17a13f97d6 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -8,43 +8,39 @@ // Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer. #include "libGLESv2/main.h" -#include "libGLESv2/utilities.h" +#include "common/utilities.h" +#include "common/platform.h" #include "libGLESv2/Buffer.h" +#include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/Framebuffer.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/renderer/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d11/RenderTarget11.h" -#include "libGLESv2/renderer/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/d3d11/ShaderExecutable11.h" -#include "libGLESv2/renderer/d3d11/SwapChain11.h" -#include "libGLESv2/renderer/d3d11/Image11.h" -#include "libGLESv2/renderer/d3d11/VertexBuffer11.h" -#include "libGLESv2/renderer/d3d11/IndexBuffer11.h" -#include "libGLESv2/renderer/d3d11/BufferStorage11.h" -#include "libGLESv2/renderer/VertexDataManager.h" -#include "libGLESv2/renderer/IndexDataManager.h" -#include "libGLESv2/renderer/d3d11/TextureStorage11.h" -#include "libGLESv2/renderer/d3d11/Query11.h" -#include "libGLESv2/renderer/d3d11/Fence11.h" - -#include "libGLESv2/renderer/d3d11/shaders/compiled/passthrough11vs.h" -#include "libGLESv2/renderer/d3d11/shaders/compiled/passthroughrgba11ps.h" -#include "libGLESv2/renderer/d3d11/shaders/compiled/passthroughrgb11ps.h" -#include "libGLESv2/renderer/d3d11/shaders/compiled/passthroughlum11ps.h" -#include "libGLESv2/renderer/d3d11/shaders/compiled/passthroughlumalpha11ps.h" - -#include "libGLESv2/renderer/d3d11/shaders/compiled/clear11vs.h" -#include "libGLESv2/renderer/d3d11/shaders/compiled/clearsingle11ps.h" -#include "libGLESv2/renderer/d3d11/shaders/compiled/clearmultiple11ps.h" - +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" +#include "libGLESv2/renderer/d3d/d3d11/Image11.h" +#include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" +#include "libGLESv2/renderer/d3d/VertexDataManager.h" +#include "libGLESv2/renderer/d3d/IndexDataManager.h" +#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" +#include "libGLESv2/renderer/d3d/d3d11/Query11.h" +#include "libGLESv2/renderer/d3d/d3d11/Fence11.h" +#include "libGLESv2/renderer/d3d/d3d11/Blit11.h" +#include "libGLESv2/renderer/d3d/d3d11/Clear11.h" +#include "libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h" +#include "libGLESv2/renderer/d3d/d3d11/VertexArray11.h" +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" #include "libEGL/Display.h" -#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) -# include <dxgi1_3.h> -# include <wrl.h> -# include <windows.applicationmodel.core.h> -typedef ABI::Windows::Foundation::IEventHandler<ABI::Windows::ApplicationModel::SuspendingEventArgs *> SuspendEventHandler; +// Enable ANGLE_SKIP_DXGI_1_2_CHECK if there is not a possibility of using cross-process +// HWNDs or the Windows 7 Platform Update (KB2670838) is expected to be installed. +#ifndef ANGLE_SKIP_DXGI_1_2_CHECK +#define ANGLE_SKIP_DXGI_1_2_CHECK 0 #endif #ifdef _DEBUG @@ -73,7 +69,10 @@ enum MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16 }; -Renderer11::Renderer11(egl::Display *display) : Renderer(display) +Renderer11::Renderer11(egl::Display *display, EGLNativeDisplayType hDc, EGLint requestedDisplay) + : Renderer(display), + mDc(hDc), + mRequestedDisplay(requestedDisplay) { mVertexDataManager = NULL; mIndexDataManager = NULL; @@ -81,24 +80,10 @@ Renderer11::Renderer11(egl::Display *display) : Renderer(display) mLineLoopIB = NULL; mTriangleFanIB = NULL; - mCopyResourcesInitialized = false; - mCopyVB = NULL; - mCopySampler = NULL; - mCopyIL = NULL; - mCopyVS = NULL; - mCopyRGBAPS = NULL; - mCopyRGBPS = NULL; - mCopyLumPS = NULL; - mCopyLumAlphaPS = NULL; - - mClearResourcesInitialized = false; - mClearVB = NULL; - mClearIL = NULL; - mClearVS = NULL; - mClearSinglePS = NULL; - mClearMultiplePS = NULL; - mClearScissorRS = NULL; - mClearNoScissorRS = NULL; + mBlit = NULL; + mPixelTransfer = NULL; + + mClear = NULL; mSyncQuery = NULL; @@ -117,9 +102,10 @@ Renderer11::Renderer11(egl::Display *display) : Renderer(display) mDriverConstantBufferVS = NULL; mDriverConstantBufferPS = NULL; - mBGRATextureSupport = false; - - mIsGeometryShaderActive = false; + mAppliedVertexShader = NULL; + mAppliedGeometryShader = NULL; + mCurPointGeometryShader = NULL; + mAppliedPixelShader = NULL; } Renderer11::~Renderer11() @@ -139,12 +125,12 @@ Renderer11 *Renderer11::makeRenderer11(Renderer *renderer) EGLint Renderer11::initialize() { - if (!initializeCompiler()) + if (!mCompiler.initialize()) { return EGL_NOT_INITIALIZED; } -#if !defined(ANGLE_OS_WINRT) +#if !defined(ANGLE_PLATFORM_WINRT) mDxgiModule = LoadLibrary(TEXT("dxgi.dll")); mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); @@ -154,7 +140,6 @@ EGLint Renderer11::initialize() return EGL_NOT_INITIALIZED; } - // create the D3D11 device ASSERT(mDevice == NULL); PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); @@ -178,11 +163,17 @@ EGLint Renderer11::initialize() #endif }; + D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_HARDWARE; + if (mRequestedDisplay == EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE) + { + driverType = D3D_DRIVER_TYPE_WARP; + } + HRESULT result = S_OK; #ifdef _DEBUG result = D3D11CreateDevice(NULL, - D3D_DRIVER_TYPE_HARDWARE, + driverType, NULL, D3D11_CREATE_DEVICE_DEBUG, featureLevels, @@ -201,7 +192,7 @@ EGLint Renderer11::initialize() #endif { result = D3D11CreateDevice(NULL, - D3D_DRIVER_TYPE_HARDWARE, + driverType, NULL, 0, featureLevels, @@ -218,7 +209,37 @@ EGLint Renderer11::initialize() } } -#if !defined(ANGLE_OS_WINRT) +#if !ANGLE_SKIP_DXGI_1_2_CHECK && !defined(ANGLE_PLATFORM_WINRT) + // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required. + // The easiest way to check is to query for a IDXGIDevice2. + bool requireDXGI1_2 = false; + HWND hwnd = WindowFromDC(mDc); + if (hwnd) + { + DWORD currentProcessId = GetCurrentProcessId(); + DWORD wndProcessId; + GetWindowThreadProcessId(hwnd, &wndProcessId); + requireDXGI1_2 = (currentProcessId != wndProcessId); + } + else + { + requireDXGI1_2 = true; + } + + if (requireDXGI1_2) + { + IDXGIDevice2 *dxgiDevice2 = NULL; + result = mDevice->QueryInterface(__uuidof(IDXGIDevice2), (void**)&dxgiDevice2); + if (FAILED(result)) + { + ERR("DXGI 1.2 required to present to HWNDs owned by another process.\n"); + return EGL_NOT_INITIALIZED; + } + SafeRelease(dxgiDevice2); + } +#endif + +#if !defined(ANGLE_PLATFORM_WINRT) IDXGIDevice *dxgiDevice = NULL; #else IDXGIDevice1 *dxgiDevice = NULL; @@ -239,7 +260,7 @@ EGLint Renderer11::initialize() return EGL_NOT_INITIALIZED; } - dxgiDevice->Release(); + SafeRelease(dxgiDevice); mDxgiAdapter->GetDesc(&mAdapterDescription); memset(mDescription, 0, sizeof(mDescription)); @@ -270,212 +291,25 @@ EGLint Renderer11::initialize() filter.DenyList.pIDList = hideMessages; infoQueue->AddStorageFilterEntries(&filter); - - infoQueue->Release(); + SafeRelease(infoQueue); } #endif - unsigned int maxSupportedSamples = 0; - unsigned int rtFormatCount = ArraySize(RenderTargetFormats); - unsigned int dsFormatCount = ArraySize(DepthStencilFormats); - for (unsigned int i = 0; i < rtFormatCount + dsFormatCount; ++i) - { - DXGI_FORMAT format = (i < rtFormatCount) ? RenderTargetFormats[i] : DepthStencilFormats[i - rtFormatCount]; - if (format != DXGI_FORMAT_UNKNOWN) - { - UINT formatSupport; - result = mDevice->CheckFormatSupport(format, &formatSupport); - if (SUCCEEDED(result) && (formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET)) - { - MultisampleSupportInfo supportInfo; - - for (unsigned int j = 1; j <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; j++) - { - result = mDevice->CheckMultisampleQualityLevels(format, j, &supportInfo.qualityLevels[j - 1]); - if (SUCCEEDED(result) && supportInfo.qualityLevels[j - 1] > 0) - { - maxSupportedSamples = std::max(j, maxSupportedSamples); - } - else - { - supportInfo.qualityLevels[j - 1] = 0; - } - } - - mMultisampleSupportMap.insert(std::make_pair(format, supportInfo)); - } - } - } - mMaxSupportedSamples = maxSupportedSamples; - - initializeDevice(); - - // BGRA texture support is optional in feature levels 10 and 10_1 - UINT formatSupport; - result = mDevice->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &formatSupport); - if (FAILED(result)) - { - ERR("Error checking BGRA format support: 0x%08X", result); - } - else - { - const int flags = (D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_RENDER_TARGET); - mBGRATextureSupport = (formatSupport & flags) == flags; - } - - // Check floating point texture support - static const unsigned int requiredTextureFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURECUBE; - static const unsigned int requiredRenderableFlags = D3D11_FORMAT_SUPPORT_RENDER_TARGET; - static const unsigned int requiredFilterFlags = D3D11_FORMAT_SUPPORT_SHADER_SAMPLE; - - DXGI_FORMAT float16Formats[] = - { - DXGI_FORMAT_R16_FLOAT, - DXGI_FORMAT_R16G16_FLOAT, - DXGI_FORMAT_R16G16B16A16_FLOAT, - }; - - DXGI_FORMAT float32Formats[] = - { - DXGI_FORMAT_R32_FLOAT, - DXGI_FORMAT_R32G32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - }; - - mFloat16TextureSupport = true; - mFloat16FilterSupport = true; - mFloat16RenderSupport = true; - for (unsigned int i = 0; i < ArraySize(float16Formats); i++) - { - if (SUCCEEDED(mDevice->CheckFormatSupport(float16Formats[i], &formatSupport))) - { - mFloat16TextureSupport = mFloat16TextureSupport && (formatSupport & requiredTextureFlags) == requiredTextureFlags; - mFloat16FilterSupport = mFloat16FilterSupport && (formatSupport & requiredFilterFlags) == requiredFilterFlags; - mFloat16RenderSupport = mFloat16RenderSupport && (formatSupport & requiredRenderableFlags) == requiredRenderableFlags; - } - else - { - mFloat16TextureSupport = false; - mFloat16RenderSupport = false; - mFloat16FilterSupport = false; - } - } - - mFloat32TextureSupport = true; - mFloat32FilterSupport = true; - mFloat32RenderSupport = true; - for (unsigned int i = 0; i < ArraySize(float32Formats); i++) - { - if (SUCCEEDED(mDevice->CheckFormatSupport(float32Formats[i], &formatSupport))) - { - mFloat32TextureSupport = mFloat32TextureSupport && (formatSupport & requiredTextureFlags) == requiredTextureFlags; - mFloat32FilterSupport = mFloat32FilterSupport && (formatSupport & requiredFilterFlags) == requiredFilterFlags; - mFloat32RenderSupport = mFloat32RenderSupport && (formatSupport & requiredRenderableFlags) == requiredRenderableFlags; - } - else - { - mFloat32TextureSupport = false; - mFloat32FilterSupport = false; - mFloat32RenderSupport = false; - } - } - - // Check compressed texture support - const unsigned int requiredCompressedTextureFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D; - - if (SUCCEEDED(mDevice->CheckFormatSupport(DXGI_FORMAT_BC1_UNORM, &formatSupport))) - { - mDXT1TextureSupport = (formatSupport & requiredCompressedTextureFlags) == requiredCompressedTextureFlags; - } - else - { - mDXT1TextureSupport = false; - } - - if (SUCCEEDED(mDevice->CheckFormatSupport(DXGI_FORMAT_BC3_UNORM, &formatSupport))) - { - mDXT3TextureSupport = (formatSupport & requiredCompressedTextureFlags) == requiredCompressedTextureFlags; - } - else - { - mDXT3TextureSupport = false; - } - - if (SUCCEEDED(mDevice->CheckFormatSupport(DXGI_FORMAT_BC5_UNORM, &formatSupport))) - { - mDXT5TextureSupport = (formatSupport & requiredCompressedTextureFlags) == requiredCompressedTextureFlags; - } - else - { - mDXT5TextureSupport = false; - } - - // Check depth texture support - DXGI_FORMAT depthTextureFormats[] = - { - DXGI_FORMAT_D16_UNORM, - DXGI_FORMAT_D24_UNORM_S8_UINT, - }; - - static const unsigned int requiredDepthTextureFlags = D3D11_FORMAT_SUPPORT_DEPTH_STENCIL | - D3D11_FORMAT_SUPPORT_TEXTURE2D; - - mDepthTextureSupport = true; - for (unsigned int i = 0; i < ArraySize(depthTextureFormats); i++) - { - if (SUCCEEDED(mDevice->CheckFormatSupport(depthTextureFormats[i], &formatSupport))) - { - mDepthTextureSupport = mDepthTextureSupport && ((formatSupport & requiredDepthTextureFlags) == requiredDepthTextureFlags); - } - else - { - mDepthTextureSupport = false; - } - } + mMaxSupportedSamples = 0; -#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) - // Monitor when the application suspends so that Trim() can be called - Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::Core::ICoreApplication> application; - result = RoGetActivationFactory(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), - IID_PPV_ARGS(&application)); - if (FAILED(result)) + const d3d11::DXGIFormatSet &dxgiFormats = d3d11::GetAllUsedDXGIFormats(); + for (d3d11::DXGIFormatSet::const_iterator i = dxgiFormats.begin(); i != dxgiFormats.end(); ++i) { - ERR("Error obtaining CoreApplication: 0x%08X", result); - return EGL_NOT_INITIALIZED; + MultisampleSupportInfo support = getMultisampleSupportInfo(*i); + mMultisampleSupportMap.insert(std::make_pair(*i, support)); + mMaxSupportedSamples = std::max(mMaxSupportedSamples, support.maxSupportedSamples); } - EventRegistrationToken cookie; - result = application->add_Suspending(Microsoft::WRL::Callback<SuspendEventHandler>(this, &Renderer11::onSuspend).Get(), &cookie); - if (FAILED(result)) - { - ERR("Error setting suspend callback: 0x%08X", result); - return EGL_NOT_INITIALIZED; - } -#endif + initializeDevice(); return EGL_SUCCESS; } -#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) -HRESULT Renderer11::onSuspend(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *) -{ - if (!mDevice) - return S_OK; - - Microsoft::WRL::ComPtr<IDXGIDevice3> dxgiDevice; - HRESULT result = mDevice->QueryInterface(IID_PPV_ARGS(&dxgiDevice)); - if (FAILED(result)) - { - ERR("Error obtaining DXGIDevice3 on suspend: 0x%08X", result); - return S_OK; - } - - dxgiDevice->Trim(); - - return S_OK; -} -#endif - // do any one-time device initialization // NOTE: this is also needed after a device lost/reset // to reset the scene status and ensure the default states are reset. @@ -488,6 +322,15 @@ void Renderer11::initializeDevice() mVertexDataManager = new VertexDataManager(this); mIndexDataManager = new IndexDataManager(this); + ASSERT(!mBlit); + mBlit = new Blit11(this); + + ASSERT(!mClear); + mClear = new Clear11(this); + + ASSERT(!mPixelTransfer); + mPixelTransfer = new PixelTransfer11(this); + markAllStateDirty(); } @@ -515,18 +358,19 @@ int Renderer11::generateConfigs(ConfigDesc **configDescList) if (depthStencilFormat != DXGI_FORMAT_UNKNOWN) { - UINT formatSupport = 0; - result = mDevice->CheckFormatSupport(depthStencilFormat, &formatSupport); - depthStencilFormatOK = SUCCEEDED(result) && (formatSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL); + UINT depthStencilSupport = 0; + result = mDevice->CheckFormatSupport(depthStencilFormat, &depthStencilSupport); + depthStencilFormatOK = SUCCEEDED(result) && (depthStencilSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL); } if (depthStencilFormatOK) { ConfigDesc newConfig; - newConfig.renderTargetFormat = d3d11_gl::ConvertBackBufferFormat(renderTargetFormat); - newConfig.depthStencilFormat = d3d11_gl::ConvertDepthStencilFormat(depthStencilFormat); + newConfig.renderTargetFormat = d3d11_gl::GetInternalFormat(renderTargetFormat); + newConfig.depthStencilFormat = d3d11_gl::GetInternalFormat(depthStencilFormat); newConfig.multiSample = 0; // FIXME: enumerate multi-sampling newConfig.fastConfig = true; // Assume all DX11 format conversions to be fast + newConfig.es3Capable = true; (*configDescList)[numConfigs++] = newConfig; } @@ -586,6 +430,23 @@ SwapChain *Renderer11::createSwapChain(EGLNativeWindowType window, HANDLE shareH return new rx::SwapChain11(this, window, shareHandle, backBufferFormat, depthBufferFormat); } +void Renderer11::generateSwizzle(gl::Texture *texture) +{ + if (texture) + { + TextureStorageInterface *texStorage = texture->getNativeTexture(); + if (texStorage) + { + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage->getStorageInstance()); + + storage11->generateSwizzles(texture->getSamplerState().swizzleRed, + texture->getSamplerState().swizzleGreen, + texture->getSamplerState().swizzleBlue, + texture->getSamplerState().swizzleAlpha); + } + } +} + void Renderer11::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState) { if (type == gl::SAMPLER_PIXEL) @@ -644,7 +505,6 @@ void Renderer11::setSamplerState(gl::SamplerType type, int index, const gl::Samp void Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *texture) { ID3D11ShaderResourceView *textureSRV = NULL; - unsigned int serial = 0; bool forceSetTexture = false; if (texture) @@ -653,14 +513,15 @@ void Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *textur if (texStorage) { TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage->getStorageInstance()); - textureSRV = storage11->getSRV(); + gl::SamplerState samplerState; + texture->getSamplerStateWithNativeOffset(&samplerState); + textureSRV = storage11->getSRV(samplerState); } // If we get NULL back from getSRV here, something went wrong in the texture class and we're unexpectedly // missing the shader resource view ASSERT(textureSRV != NULL); - serial = texture->getTextureSerial(); forceSetTexture = texture->hasDirtyImages(); } @@ -672,12 +533,12 @@ void Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *textur return; } - if (forceSetTexture || mCurPixelTextureSerials[index] != serial) + if (forceSetTexture || mCurPixelSRVs[index] != textureSRV) { mDeviceContext->PSSetShaderResources(index, 1, &textureSRV); } - mCurPixelTextureSerials[index] = serial; + mCurPixelSRVs[index] = textureSRV; } else if (type == gl::SAMPLER_VERTEX) { @@ -687,22 +548,70 @@ void Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *textur return; } - if (forceSetTexture || mCurVertexTextureSerials[index] != serial) + if (forceSetTexture || mCurVertexSRVs[index] != textureSRV) { mDeviceContext->VSSetShaderResources(index, 1, &textureSRV); } - mCurVertexTextureSerials[index] = serial; + mCurVertexSRVs[index] = textureSRV; } else UNREACHABLE(); } +bool Renderer11::setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]) +{ + for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; uniformBufferIndex++) + { + const gl::Buffer *uniformBuffer = vertexUniformBuffers[uniformBufferIndex]; + if (uniformBuffer) + { + Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); + ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + + if (!constantBuffer) + { + return false; + } + + if (mCurrentConstantBufferVS[uniformBufferIndex] != bufferStorage->getSerial()) + { + mDeviceContext->VSSetConstantBuffers(getReservedVertexUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer); + mCurrentConstantBufferVS[uniformBufferIndex] = bufferStorage->getSerial(); + } + } + } + + for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS; uniformBufferIndex++) + { + const gl::Buffer *uniformBuffer = fragmentUniformBuffers[uniformBufferIndex]; + if (uniformBuffer) + { + Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); + ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + + if (!constantBuffer) + { + return false; + } + + if (mCurrentConstantBufferPS[uniformBufferIndex] != bufferStorage->getSerial()) + { + mDeviceContext->PSSetConstantBuffers(getReservedFragmentUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer); + mCurrentConstantBufferPS[uniformBufferIndex] = bufferStorage->getSerial(); + } + } + } + + return true; +} + void Renderer11::setRasterizerState(const gl::RasterizerState &rasterState) { if (mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0) { - ID3D11RasterizerState *dxRasterState = mStateCache.getRasterizerState(rasterState, mScissorEnabled, - mCurDepthSize); + ID3D11RasterizerState *dxRasterState = mStateCache.getRasterizerState(rasterState, mScissorEnabled); if (!dxRasterState) { ERR("NULL rasterizer state returned by RenderStateCache::getRasterizerState, setting the default" @@ -717,12 +626,12 @@ void Renderer11::setRasterizerState(const gl::RasterizerState &rasterState) mForceSetRasterState = false; } -void Renderer11::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::Color &blendColor, +void Renderer11::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, unsigned int sampleMask) { if (mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0 || - memcmp(&blendColor, &mCurBlendColor, sizeof(gl::Color)) != 0 || + memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0 || sampleMask != mCurSampleMask) { ID3D11BlendState *dxBlendState = mStateCache.getBlendState(framebuffer, blendState); @@ -766,14 +675,9 @@ void Renderer11::setDepthStencilState(const gl::DepthStencilState &depthStencilS memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0 || stencilRef != mCurStencilRef || stencilBackRef != mCurStencilBackRef) { - if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask || - stencilRef != stencilBackRef || - depthStencilState.stencilMask != depthStencilState.stencilBackMask) - { - ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are " - "invalid under WebGL."); - return gl::error(GL_INVALID_OPERATION); - } + ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask); + ASSERT(stencilRef == stencilBackRef); + ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask); ID3D11DepthStencilState *dxDepthStencilState = mStateCache.getDepthStencilState(depthStencilState); if (!dxDepthStencilState) @@ -782,7 +686,13 @@ void Renderer11::setDepthStencilState(const gl::DepthStencilState &depthStencilS "setting the default depth stencil state."); } - mDeviceContext->OMSetDepthStencilState(dxDepthStencilState, static_cast<UINT>(stencilRef)); + // Max D3D11 stencil reference value is 0xFF, corresponding to the max 8 bits in a stencil buffer + // GL specifies we should clamp the ref value to the nearest bit depth when doing stencil ops + META_ASSERT(D3D11_DEFAULT_STENCIL_READ_MASK == 0xFF); + META_ASSERT(D3D11_DEFAULT_STENCIL_WRITE_MASK == 0xFF); + UINT dxStencilRef = std::min<UINT>(stencilRef, 0xFFu); + + mDeviceContext->OMSetDepthStencilState(dxDepthStencilState, dxStencilRef); mCurDepthStencilState = depthStencilState; mCurStencilRef = stencilRef; @@ -836,17 +746,14 @@ bool Renderer11::setViewport(const gl::Rectangle &viewport, float zNear, float z actualZFar = 1.0f; } - // Get D3D viewport bounds, which depends on the feature level - const Range& viewportBounds = getViewportBounds(); + const gl::Caps& caps = getRendererCaps(); // Clamp width and height first to the gl maximum, then clamp further if we extend past the D3D maximum bounds D3D11_VIEWPORT dxViewport; - dxViewport.TopLeftX = gl::clamp(actualViewport.x, viewportBounds.start, viewportBounds.end); - dxViewport.TopLeftY = gl::clamp(actualViewport.y, viewportBounds.start, viewportBounds.end); - dxViewport.Width = gl::clamp(actualViewport.width, 0, getMaxViewportDimension()); - dxViewport.Height = gl::clamp(actualViewport.height, 0, getMaxViewportDimension()); - dxViewport.Width = std::min((int)dxViewport.Width, viewportBounds.end - static_cast<int>(dxViewport.TopLeftX)); - dxViewport.Height = std::min((int)dxViewport.Height, viewportBounds.end - static_cast<int>(dxViewport.TopLeftY)); + dxViewport.TopLeftX = gl::clamp(actualViewport.x, -static_cast<int>(caps.maxViewportWidth), static_cast<int>(caps.maxViewportWidth)); + dxViewport.TopLeftY = gl::clamp(actualViewport.y, -static_cast<int>(caps.maxViewportHeight), static_cast<int>(caps.maxViewportHeight)); + dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast<int>(caps.maxViewportWidth - dxViewport.TopLeftX)); + dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast<int>(caps.maxViewportHeight - dxViewport.TopLeftY)); dxViewport.MinDepth = actualZNear; dxViewport.MaxDepth = actualZFar; @@ -904,7 +811,8 @@ bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count) // emulate fans via rewriting index buffer case GL_TRIANGLE_FAN: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; default: - return gl::error(GL_INVALID_ENUM, false); + UNREACHABLE(); + return false; } if (primitiveTopology != mCurrentPrimitiveTopology) @@ -930,20 +838,13 @@ bool Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { const GLenum drawBufferState = framebuffer->getDrawBufferState(colorAttachment); + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(colorAttachment); - if (framebuffer->getColorbufferType(colorAttachment) != GL_NONE && drawBufferState != GL_NONE) + if (colorbuffer && drawBufferState != GL_NONE) { // the draw buffer must be either "none", "back" for the default buffer or the same index as this color (in order) ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment)); - gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(colorAttachment); - - if (!colorbuffer) - { - ERR("render target pointer unexpectedly null."); - return false; - } - // check for zero-sized default framebuffer, which is a special case. // in this case we do not wish to modify any state and just silently return false. // this will not report any gl error but will cause the calling method to return. @@ -977,59 +878,25 @@ bool Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) missingColorRenderTarget = false; } -#ifdef _DEBUG - // Workaround for Debug SETSHADERRESOURCES_HAZARD D3D11 warnings - for (unsigned int vertexSerialIndex = 0; vertexSerialIndex < gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; vertexSerialIndex++) - { - if (colorbuffer->getTextureSerial() != 0 && mCurVertexTextureSerials[vertexSerialIndex] == colorbuffer->getTextureSerial()) - { - setTexture(gl::SAMPLER_VERTEX, vertexSerialIndex, NULL); - } - } - - for (unsigned int pixelSerialIndex = 0; pixelSerialIndex < gl::MAX_TEXTURE_IMAGE_UNITS; pixelSerialIndex++) - { - if (colorbuffer->getTextureSerial() != 0 && mCurPixelTextureSerials[pixelSerialIndex] == colorbuffer->getTextureSerial()) - { - setTexture(gl::SAMPLER_PIXEL, pixelSerialIndex, NULL); - } - } -#endif + // TODO: Detect if this color buffer is already bound as a texture and unbind it first to prevent + // D3D11 warnings. } } // Get the depth stencil render buffer and serials - gl::Renderbuffer *depthStencil = NULL; + gl::FramebufferAttachment *depthStencil = framebuffer->getDepthbuffer(); unsigned int depthbufferSerial = 0; unsigned int stencilbufferSerial = 0; - if (framebuffer->getDepthbufferType() != GL_NONE) + if (depthStencil) { - depthStencil = framebuffer->getDepthbuffer(); - if (!depthStencil) - { - ERR("Depth stencil pointer unexpectedly null."); - SafeRelease(framebufferRTVs); - return false; - } - depthbufferSerial = depthStencil->getSerial(); } - else if (framebuffer->getStencilbufferType() != GL_NONE) + else if (framebuffer->getStencilbuffer()) { depthStencil = framebuffer->getStencilbuffer(); - if (!depthStencil) - { - ERR("Depth stencil pointer unexpectedly null."); - SafeRelease(framebufferRTVs); - return false; - } - stencilbufferSerial = depthStencil->getSerial(); } - // Extract the depth stencil sizes and view - unsigned int depthSize = 0; - unsigned int stencilSize = 0; ID3D11DepthStencilView* framebufferDSV = NULL; if (depthStencil) { @@ -1057,9 +924,6 @@ bool Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) renderTargetHeight = depthStencil->getHeight(); renderTargetFormat = depthStencil->getActualFormat(); } - - depthSize = depthStencil->getDepthSize(); - stencilSize = depthStencil->getStencilSize(); } // Apply the render target and depth stencil @@ -1068,22 +932,20 @@ bool Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) depthbufferSerial != mAppliedDepthbufferSerial || stencilbufferSerial != mAppliedStencilbufferSerial) { - mDeviceContext->OMSetRenderTargets(getMaxRenderTargets(), framebufferRTVs, framebufferDSV); + mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, framebufferRTVs, framebufferDSV); mRenderTargetDesc.width = renderTargetWidth; mRenderTargetDesc.height = renderTargetHeight; mRenderTargetDesc.format = renderTargetFormat; mForceSetViewport = true; mForceSetScissor = true; + mForceSetBlendState = true; - if (!mDepthStencilInitialized || depthSize != mCurDepthSize) + if (!mDepthStencilInitialized) { - mCurDepthSize = depthSize; mForceSetRasterState = true; } - mCurStencilSize = stencilSize; - for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++) { mAppliedRenderTargetSerials[rtIndex] = renderTargetSerials[rtIndex]; @@ -1094,13 +956,16 @@ bool Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) mDepthStencilInitialized = true; } + invalidateFramebufferSwizzles(framebuffer); + return true; } -GLenum Renderer11::applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances) +GLenum Renderer11::applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], + GLint first, GLsizei count, GLsizei instances) { TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; - GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, programBinary, first, count, attributes, instances); + GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances); if (err != GL_NO_ERROR) { return err; @@ -1115,28 +980,27 @@ GLenum Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementAr if (err == GL_NO_ERROR) { - if (indexInfo->storage) - { - if (indexInfo->serial != mAppliedStorageIBSerial || indexInfo->startOffset != mAppliedIBOffset) - { - BufferStorage11 *storage = BufferStorage11::makeBufferStorage11(indexInfo->storage); - IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer); + IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer); - mDeviceContext->IASetIndexBuffer(storage->getBuffer(BUFFER_USAGE_INDEX), indexBuffer->getIndexFormat(), indexInfo->startOffset); + ID3D11Buffer *buffer = NULL; + DXGI_FORMAT bufferFormat = indexBuffer->getIndexFormat(); - mAppliedIBSerial = 0; - mAppliedStorageIBSerial = storage->getSerial(); - mAppliedIBOffset = indexInfo->startOffset; - } + if (indexInfo->storage) + { + Buffer11 *storage = Buffer11::makeBuffer11(indexInfo->storage); + buffer = storage->getBuffer(BUFFER_USAGE_INDEX); } - else if (indexInfo->serial != mAppliedIBSerial || indexInfo->startOffset != mAppliedIBOffset) + else { - IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer); + buffer = indexBuffer->getBuffer(); + } - mDeviceContext->IASetIndexBuffer(indexBuffer->getBuffer(), indexBuffer->getIndexFormat(), indexInfo->startOffset); + if (buffer != mAppliedIB || bufferFormat != mAppliedIBFormat || indexInfo->startOffset != mAppliedIBOffset) + { + mDeviceContext->IASetIndexBuffer(buffer, bufferFormat, indexInfo->startOffset); - mAppliedIBSerial = indexInfo->serial; - mAppliedStorageIBSerial = 0; + mAppliedIB = buffer; + mAppliedIBFormat = bufferFormat; mAppliedIBOffset = indexInfo->startOffset; } } @@ -1144,9 +1008,79 @@ GLenum Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementAr return err; } -void Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances) +void Renderer11::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) { - if (mode == GL_LINE_LOOP) + ID3D11Buffer* d3dBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + UINT d3dOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + bool requiresUpdate = false; + for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + if (transformFeedbackBuffers[i]) + { + Buffer11 *storage = Buffer11::makeBuffer11(transformFeedbackBuffers[i]->getImplementation()); + ID3D11Buffer *buffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + + d3dBuffers[i] = buffer; + d3dOffsets[i] = (mAppliedTFBuffers[i] != buffer) ? static_cast<UINT>(offsets[i]) : -1; + } + else + { + d3dBuffers[i] = NULL; + d3dOffsets[i] = 0; + } + + if (d3dBuffers[i] != mAppliedTFBuffers[i] || offsets[i] != mAppliedTFOffsets[i]) + { + requiresUpdate = true; + } + } + + if (requiresUpdate) + { + mDeviceContext->SOSetTargets(ArraySize(d3dBuffers), d3dBuffers, d3dOffsets); + for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + mAppliedTFBuffers[i] = d3dBuffers[i]; + mAppliedTFOffsets[i] = offsets[i]; + } + } +} + +void Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) +{ + if (mode == GL_POINTS && transformFeedbackActive) + { + // Since point sprites are generated with a geometry shader, too many vertices will + // be written if transform feedback is active. To work around this, draw only the points + // with the stream out shader and no pixel shader to feed the stream out buffers and then + // draw again with the point sprite geometry shader to rasterize the point sprites. + + mDeviceContext->PSSetShader(NULL, NULL, 0); + + if (instances > 0) + { + mDeviceContext->DrawInstanced(count, instances, 0, 0); + } + else + { + mDeviceContext->Draw(count, 0); + } + + mDeviceContext->GSSetShader(mCurPointGeometryShader, NULL, 0); + mDeviceContext->PSSetShader(mAppliedPixelShader, NULL, 0); + + if (instances > 0) + { + mDeviceContext->DrawInstanced(count, instances, 0, 0); + } + else + { + mDeviceContext->Draw(count, 0); + } + + mDeviceContext->GSSetShader(mAppliedGeometryShader, NULL, 0); + } + else if (mode == GL_LINE_LOOP) { drawLineLoop(count, GL_NONE, NULL, 0, NULL); } @@ -1164,7 +1098,8 @@ void Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances) } } -void Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) +void Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) { if (mode == GL_LINE_LOOP) { @@ -1268,12 +1203,13 @@ void Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, if (type != GL_NONE && elementArrayBuffer) { gl::Buffer *indexBuffer = elementArrayBuffer; - BufferStorage *storage = indexBuffer->getStorage(); + BufferImpl *storage = indexBuffer->getImplementation(); intptr_t offset = reinterpret_cast<intptr_t>(indices); indices = static_cast<const GLubyte*>(storage->getData()) + offset; } - const int indexType = get32BitIndexSupport() ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; + // TODO: some level 9 hardware supports 32-bit indices; test and store support instead + const int indexType = isLevel9() ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; if (!mLineLoopIB) { @@ -1291,13 +1227,14 @@ void Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, // Checked by Renderer11::applyPrimitiveType ASSERT(count >= 0); - if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int))) + int indexTypeSize = indexType == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int); + if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned int>::max() / indexTypeSize)) { ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); return gl::error(GL_OUT_OF_MEMORY); } - const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int); + const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * indexTypeSize; if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, indexType)) { ERR("Could not reserve enough space in looping index buffer for GL_LINE_LOOP."); @@ -1324,13 +1261,15 @@ void Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, return gl::error(GL_OUT_OF_MEMORY); } - if (mAppliedIBSerial != mLineLoopIB->getSerial() || mAppliedIBOffset != indexBufferOffset) - { - IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mLineLoopIB->getIndexBuffer()); + IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mLineLoopIB->getIndexBuffer()); + ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); + if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) + { mDeviceContext->IASetIndexBuffer(indexBuffer->getBuffer(), indexBuffer->getIndexFormat(), indexBufferOffset); - mAppliedIBSerial = mLineLoopIB->getSerial(); - mAppliedStorageIBSerial = 0; + mAppliedIB = d3dIndexBuffer; + mAppliedIBFormat = indexFormat; mAppliedIBOffset = indexBufferOffset; } @@ -1343,12 +1282,12 @@ void Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indic if (type != GL_NONE && elementArrayBuffer) { gl::Buffer *indexBuffer = elementArrayBuffer; - BufferStorage *storage = indexBuffer->getStorage(); + BufferImpl *storage = indexBuffer->getImplementation(); intptr_t offset = reinterpret_cast<intptr_t>(indices); indices = static_cast<const GLubyte*>(storage->getData()) + offset; } - const int indexType = get32BitIndexSupport() ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; + const int indexType = isLevel9() ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; if (!mTriangleFanIB) { @@ -1368,13 +1307,14 @@ void Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indic const unsigned int numTris = count - 2; - if (numTris > (std::numeric_limits<unsigned int>::max() / (sizeof(unsigned int) * 3))) + int indexTypeSize = indexType == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int); + if (numTris > (std::numeric_limits<unsigned int>::max() / (indexTypeSize * 3))) { ERR("Could not create a scratch index buffer for GL_TRIANGLE_FAN, too many indices required."); return gl::error(GL_OUT_OF_MEMORY); } - const unsigned int spaceNeeded = (numTris * 3) * sizeof(unsigned int); + const unsigned int spaceNeeded = (numTris * 3) * indexTypeSize; if (!mTriangleFanIB->reserveBufferSpace(spaceNeeded, indexType)) { ERR("Could not reserve enough space in scratch index buffer for GL_TRIANGLE_FAN."); @@ -1395,20 +1335,21 @@ void Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indic fillTriangleFanIndices(type, numTris, indices, reinterpret_cast<unsigned int*>(mappedMemory)); unsigned int indexBufferOffset = offset; - if (!mTriangleFanIB->unmapBuffer()) { ERR("Could not unmap scratch index buffer for GL_TRIANGLE_FAN."); return gl::error(GL_OUT_OF_MEMORY); } - if (mAppliedIBSerial != mTriangleFanIB->getSerial() || mAppliedIBOffset != indexBufferOffset) - { - IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mTriangleFanIB->getIndexBuffer()); + IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mTriangleFanIB->getIndexBuffer()); + ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); + if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) + { mDeviceContext->IASetIndexBuffer(indexBuffer->getBuffer(), indexBuffer->getIndexFormat(), indexBufferOffset); - mAppliedIBSerial = mTriangleFanIB->getSerial(); - mAppliedStorageIBSerial = 0; + mAppliedIB = d3dIndexBuffer; + mAppliedIBFormat = indexFormat; mAppliedIBOffset = indexBufferOffset; } @@ -1422,54 +1363,73 @@ void Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indic } } -void Renderer11::applyShaders(gl::ProgramBinary *programBinary) +void Renderer11::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive) { - unsigned int programBinarySerial = programBinary->getSerial(); - const bool updateProgramState = (programBinarySerial != mAppliedProgramBinarySerial); + ShaderExecutable *vertexExe = programBinary->getVertexExecutableForInputLayout(inputLayout); + ShaderExecutable *pixelExe = programBinary->getPixelExecutableForFramebuffer(framebuffer); + ShaderExecutable *geometryExe = programBinary->getGeometryExecutable(); + + ID3D11VertexShader *vertexShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader() : NULL); - if (updateProgramState) + ID3D11PixelShader *pixelShader = NULL; + // Skip pixel shader if we're doing rasterizer discard. + if (!rasterizerDiscard) { - ShaderExecutable *vertexExe = programBinary->getVertexExecutable(); - ShaderExecutable *pixelExe = programBinary->getPixelExecutable(); + pixelShader = (pixelExe ? ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader() : NULL); + } - ID3D11VertexShader *vertexShader = NULL; - if (vertexExe) vertexShader = ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader(); + ID3D11GeometryShader *geometryShader = NULL; + if (transformFeedbackActive) + { + geometryShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getStreamOutShader() : NULL); + } + else if (mCurRasterState.pointDrawMode) + { + geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL); + } - ID3D11PixelShader *pixelShader = NULL; - if (pixelExe) pixelShader = ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader(); + bool dirtyUniforms = false; - mDeviceContext->PSSetShader(pixelShader, NULL, 0); + if (vertexShader != mAppliedVertexShader) + { mDeviceContext->VSSetShader(vertexShader, NULL, 0); + mAppliedVertexShader = vertexShader; + dirtyUniforms = true; + } - programBinary->dirtyAllUniforms(); - - mAppliedProgramBinarySerial = programBinarySerial; + if (geometryShader != mAppliedGeometryShader) + { + mDeviceContext->GSSetShader(geometryShader, NULL, 0); + mAppliedGeometryShader = geometryShader; + dirtyUniforms = true; } - // Only use the geometry shader currently for point sprite drawing - const bool usesGeometryShader = (programBinary->usesGeometryShader() && mCurRasterState.pointDrawMode); + if (geometryExe && mCurRasterState.pointDrawMode) + { + mCurPointGeometryShader = ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader(); + } + else + { + mCurPointGeometryShader = NULL; + } - if (updateProgramState || usesGeometryShader != mIsGeometryShaderActive) + if (pixelShader != mAppliedPixelShader) { - if (usesGeometryShader) - { - ShaderExecutable *geometryExe = programBinary->getGeometryExecutable(); - ID3D11GeometryShader *geometryShader = ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader(); - mDeviceContext->GSSetShader(geometryShader, NULL, 0); - } - else - { - mDeviceContext->GSSetShader(NULL, NULL, 0); - } + mDeviceContext->PSSetShader(pixelShader, NULL, 0); + mAppliedPixelShader = pixelShader; + dirtyUniforms = true; + } - mIsGeometryShaderActive = usesGeometryShader; + if (dirtyUniforms) + { + programBinary->dirtyAllUniforms(); } } -void Renderer11::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray) +void Renderer11::applyUniforms(const gl::ProgramBinary &programBinary) { - ShaderExecutable11 *vertexExecutable = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutable()); - ShaderExecutable11 *pixelExecutable = ShaderExecutable11::makeShaderExecutable11(programBinary->getPixelExecutable()); + const std::vector<gl::LinkedUniform*> &uniformArray = programBinary.getUniforms(); unsigned int totalRegisterCountVS = 0; unsigned int totalRegisterCountPS = 0; @@ -1477,25 +1437,30 @@ void Renderer11::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArra bool vertexUniformsDirty = false; bool pixelUniformsDirty = false; - for (gl::UniformArray::const_iterator uniform_iterator = uniformArray->begin(); uniform_iterator != uniformArray->end(); uniform_iterator++) + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) { - const gl::Uniform *uniform = *uniform_iterator; + const gl::LinkedUniform &uniform = *uniformArray[uniformIndex]; - if (uniform->vsRegisterIndex >= 0) + if (uniform.isReferencedByVertexShader() && !uniform.isSampler()) { - totalRegisterCountVS += uniform->registerCount; - vertexUniformsDirty = vertexUniformsDirty || uniform->dirty; + totalRegisterCountVS += uniform.registerCount; + vertexUniformsDirty = (vertexUniformsDirty || uniform.dirty); } - if (uniform->psRegisterIndex >= 0) + if (uniform.isReferencedByFragmentShader() && !uniform.isSampler()) { - totalRegisterCountPS += uniform->registerCount; - pixelUniformsDirty = pixelUniformsDirty || uniform->dirty; + totalRegisterCountPS += uniform.registerCount; + pixelUniformsDirty = (pixelUniformsDirty || uniform.dirty); } } - ID3D11Buffer *vertexConstantBuffer = vertexExecutable->getConstantBuffer(mDevice, totalRegisterCountVS); - ID3D11Buffer *pixelConstantBuffer = pixelExecutable->getConstantBuffer(mDevice, totalRegisterCountPS); + const UniformStorage11 *vertexUniformStorage = UniformStorage11::makeUniformStorage11(&programBinary.getVertexUniformStorage()); + const UniformStorage11 *fragmentUniformStorage = UniformStorage11::makeUniformStorage11(&programBinary.getFragmentUniformStorage()); + ASSERT(vertexUniformStorage); + ASSERT(fragmentUniformStorage); + + ID3D11Buffer *vertexConstantBuffer = vertexUniformStorage->getConstantBuffer(); + ID3D11Buffer *pixelConstantBuffer = fragmentUniformStorage->getConstantBuffer(); float (*mapVS)[4] = NULL; float (*mapPS)[4] = NULL; @@ -1504,6 +1469,7 @@ void Renderer11::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArra { D3D11_MAPPED_SUBRESOURCE map = {0}; HRESULT result = mDeviceContext->Map(vertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); mapVS = (float(*)[4])map.pData; } @@ -1512,28 +1478,32 @@ void Renderer11::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArra { D3D11_MAPPED_SUBRESOURCE map = {0}; HRESULT result = mDeviceContext->Map(pixelConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); mapPS = (float(*)[4])map.pData; } - for (gl::UniformArray::iterator uniform_iterator = uniformArray->begin(); uniform_iterator != uniformArray->end(); uniform_iterator++) + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) { - gl::Uniform *uniform = *uniform_iterator; + gl::LinkedUniform *uniform = uniformArray[uniformIndex]; - if (uniform->type != GL_SAMPLER_2D && uniform->type != GL_SAMPLER_CUBE) + if (!uniform->isSampler()) { - if (uniform->vsRegisterIndex >= 0 && mapVS) + unsigned int componentCount = (4 - uniform->registerElement); + + // we assume that uniforms from structs are arranged in struct order in our uniforms list. otherwise we would + // overwrite previously written regions of memory. + + if (uniform->isReferencedByVertexShader() && mapVS) { - memcpy(mapVS + uniform->vsRegisterIndex, uniform->data, uniform->registerCount * sizeof(float[4])); + memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount); } - if (uniform->psRegisterIndex >= 0 && mapPS) + if (uniform->isReferencedByFragmentShader() && mapPS) { - memcpy(mapPS + uniform->psRegisterIndex, uniform->data, uniform->registerCount * sizeof(float[4])); + memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount); } } - - uniform->dirty = false; } if (mapVS) @@ -1570,6 +1540,7 @@ void Renderer11::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArra constantBufferDescription.StructureByteStride = 0; HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferVS); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); mDeviceContext->VSSetConstantBuffers(1, 1, &mDriverConstantBufferVS); @@ -1586,6 +1557,7 @@ void Renderer11::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArra constantBufferDescription.StructureByteStride = 0; HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferPS); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); mDeviceContext->PSSetConstantBuffers(1, 1, &mDriverConstantBufferPS); @@ -1613,271 +1585,8 @@ void Renderer11::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArra void Renderer11::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) { - gl::Renderbuffer *firstRenderbuffer = frameBuffer->getFirstColorbuffer(); - GLenum internalFormat = firstRenderbuffer ? firstRenderbuffer->getInternalFormat() : GL_NONE; - - bool needMaskedColorClear = (clearParams.mask & GL_COLOR_BUFFER_BIT) && - ((!clearParams.colorMaskRed && gl::GetRedSize(internalFormat) > 0) || - (!clearParams.colorMaskGreen && gl::GetGreenSize(internalFormat) > 0) || - (!clearParams.colorMaskBlue && gl::GetBlueSize(internalFormat) > 0) || - (!clearParams.colorMaskAlpha && gl::GetAlphaSize(internalFormat) > 0)); - - unsigned int stencilUnmasked = 0x0; - if (frameBuffer->hasStencil()) - { - unsigned int stencilSize = gl::GetStencilSize(frameBuffer->getStencilbuffer()->getActualFormat()); - stencilUnmasked = (0x1 << stencilSize) - 1; - } - bool needMaskedStencilClear = (clearParams.mask & GL_STENCIL_BUFFER_BIT) && - (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; - - bool needScissoredClear = mScissorEnabled && (mCurScissor.x > 0 || mCurScissor.y > 0 || - mCurScissor.x + mCurScissor.width < mRenderTargetDesc.width || - mCurScissor.y + mCurScissor.height < mRenderTargetDesc.height); - - if (needMaskedColorClear || needMaskedStencilClear || needScissoredClear) - { - maskedClear(clearParams, frameBuffer); - } - else - { - if (clearParams.mask & GL_COLOR_BUFFER_BIT) - { - for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - if (frameBuffer->isEnabledColorAttachment(colorAttachment)) - { - gl::Renderbuffer *renderbufferObject = frameBuffer->getColorbuffer(colorAttachment); - if (renderbufferObject) - { - RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(renderbufferObject->getRenderTarget()); - if (!renderTarget) - { - ERR("render target pointer unexpectedly null."); - return; - } - - ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView(); - if (!framebufferRTV) - { - ERR("render target view pointer unexpectedly null."); - return; - } - - GLenum format = renderbufferObject->getInternalFormat(); - - const float clearValues[4] = { (gl::GetRedSize(format) > 0) ? clearParams.colorClearValue.red : 0.0f, - (gl::GetGreenSize(format) > 0) ? clearParams.colorClearValue.green : 0.0f, - (gl::GetBlueSize(format) > 0) ? clearParams.colorClearValue.blue : 0.0f, - (gl::GetAlphaSize(format) > 0) ? clearParams.colorClearValue.alpha : 1.0f }; - mDeviceContext->ClearRenderTargetView(framebufferRTV, clearValues); - } - } - } - } - if (clearParams.mask & GL_DEPTH_BUFFER_BIT || clearParams.mask & GL_STENCIL_BUFFER_BIT) - { - gl::Renderbuffer *renderbufferObject = frameBuffer->getDepthOrStencilbuffer(); - if (renderbufferObject) - { - RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(renderbufferObject->getDepthStencil()); - if (!renderTarget) - { - ERR("render target pointer unexpectedly null."); - return; - } - - ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView(); - if (!framebufferDSV) - { - ERR("depth stencil view pointer unexpectedly null."); - return; - } - - UINT clearFlags = 0; - if (clearParams.mask & GL_DEPTH_BUFFER_BIT) - { - clearFlags |= D3D11_CLEAR_DEPTH; - } - if (clearParams.mask & GL_STENCIL_BUFFER_BIT) - { - clearFlags |= D3D11_CLEAR_STENCIL; - } - - float depthClear = gl::clamp01(clearParams.depthClearValue); - UINT8 stencilClear = clearParams.stencilClearValue & 0x000000FF; - - mDeviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear); - } - } - } -} - -void Renderer11::maskedClear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) -{ - HRESULT result; - - if (!mClearResourcesInitialized) - { - ASSERT(!mClearVB && !mClearVS && !mClearSinglePS && !mClearMultiplePS && !mClearScissorRS && !mClearNoScissorRS); - - D3D11_BUFFER_DESC vbDesc; - vbDesc.ByteWidth = sizeof(d3d11::PositionDepthColorVertex) * 4; - vbDesc.Usage = D3D11_USAGE_DYNAMIC; - vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - vbDesc.MiscFlags = 0; - vbDesc.StructureByteStride = 0; - - result = mDevice->CreateBuffer(&vbDesc, NULL, &mClearVB); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mClearVB, "Renderer11 masked clear vertex buffer"); - - D3D11_INPUT_ELEMENT_DESC quadLayout[] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - - result = mDevice->CreateInputLayout(quadLayout, 2, g_VS_Clear, sizeof(g_VS_Clear), &mClearIL); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mClearIL, "Renderer11 masked clear input layout"); - - result = mDevice->CreateVertexShader(g_VS_Clear, sizeof(g_VS_Clear), NULL, &mClearVS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mClearVS, "Renderer11 masked clear vertex shader"); - - result = mDevice->CreatePixelShader(g_PS_ClearSingle, sizeof(g_PS_ClearSingle), NULL, &mClearSinglePS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mClearSinglePS, "Renderer11 masked clear pixel shader (1 RT)"); - - result = mDevice->CreatePixelShader(g_PS_ClearMultiple, sizeof(g_PS_ClearMultiple), NULL, &mClearMultiplePS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mClearMultiplePS, "Renderer11 masked clear pixel shader (MRT)"); - - D3D11_RASTERIZER_DESC rsScissorDesc; - rsScissorDesc.FillMode = D3D11_FILL_SOLID; - rsScissorDesc.CullMode = D3D11_CULL_NONE; - rsScissorDesc.FrontCounterClockwise = FALSE; - rsScissorDesc.DepthBias = 0; - rsScissorDesc.DepthBiasClamp = 0.0f; - rsScissorDesc.SlopeScaledDepthBias = 0.0f; - rsScissorDesc.DepthClipEnable = FALSE; - rsScissorDesc.ScissorEnable = TRUE; - rsScissorDesc.MultisampleEnable = FALSE; - rsScissorDesc.AntialiasedLineEnable = FALSE; - - result = mDevice->CreateRasterizerState(&rsScissorDesc, &mClearScissorRS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mClearScissorRS, "Renderer11 masked clear scissor rasterizer state"); - - D3D11_RASTERIZER_DESC rsNoScissorDesc; - rsNoScissorDesc.FillMode = D3D11_FILL_SOLID; - rsNoScissorDesc.CullMode = D3D11_CULL_NONE; - rsNoScissorDesc.FrontCounterClockwise = FALSE; - rsNoScissorDesc.DepthBias = 0; - rsNoScissorDesc.DepthBiasClamp = 0.0f; - rsNoScissorDesc.SlopeScaledDepthBias = 0.0f; - rsNoScissorDesc.DepthClipEnable = FALSE; - rsNoScissorDesc.ScissorEnable = FALSE; - rsNoScissorDesc.MultisampleEnable = FALSE; - rsNoScissorDesc.AntialiasedLineEnable = FALSE; - - result = mDevice->CreateRasterizerState(&rsNoScissorDesc, &mClearNoScissorRS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mClearNoScissorRS, "Renderer11 masked clear no scissor rasterizer state"); - - mClearResourcesInitialized = true; - } - - // Prepare the depth stencil state to write depth values if the depth should be cleared - // and stencil values if the stencil should be cleared - gl::DepthStencilState glDSState; - glDSState.depthTest = (clearParams.mask & GL_DEPTH_BUFFER_BIT) != 0; - glDSState.depthFunc = GL_ALWAYS; - glDSState.depthMask = (clearParams.mask & GL_DEPTH_BUFFER_BIT) != 0; - glDSState.stencilTest = (clearParams.mask & GL_STENCIL_BUFFER_BIT) != 0; - glDSState.stencilFunc = GL_ALWAYS; - glDSState.stencilMask = 0; - glDSState.stencilFail = GL_REPLACE; - glDSState.stencilPassDepthFail = GL_REPLACE; - glDSState.stencilPassDepthPass = GL_REPLACE; - glDSState.stencilWritemask = clearParams.stencilWriteMask; - glDSState.stencilBackFunc = GL_ALWAYS; - glDSState.stencilBackMask = 0; - glDSState.stencilBackFail = GL_REPLACE; - glDSState.stencilBackPassDepthFail = GL_REPLACE; - glDSState.stencilBackPassDepthPass = GL_REPLACE; - glDSState.stencilBackWritemask = clearParams.stencilWriteMask; - - int stencilClear = clearParams.stencilClearValue & 0x000000FF; - - ID3D11DepthStencilState *dsState = mStateCache.getDepthStencilState(glDSState); - - // Prepare the blend state to use a write mask if the color buffer should be cleared - gl::BlendState glBlendState; - glBlendState.blend = false; - glBlendState.sourceBlendRGB = GL_ONE; - glBlendState.destBlendRGB = GL_ZERO; - glBlendState.sourceBlendAlpha = GL_ONE; - glBlendState.destBlendAlpha = GL_ZERO; - glBlendState.blendEquationRGB = GL_FUNC_ADD; - glBlendState.blendEquationAlpha = GL_FUNC_ADD; - glBlendState.colorMaskRed = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskRed : false; - glBlendState.colorMaskGreen = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskGreen : false; - glBlendState.colorMaskBlue = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskBlue : false; - glBlendState.colorMaskAlpha = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskAlpha : false; - glBlendState.sampleAlphaToCoverage = false; - glBlendState.dither = false; - - static const float blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - static const UINT sampleMask = 0xFFFFFFFF; - - ID3D11BlendState *blendState = mStateCache.getBlendState(frameBuffer, glBlendState); - - // Set the vertices - D3D11_MAPPED_SUBRESOURCE mappedResource; - result = mDeviceContext->Map(mClearVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - ERR("Failed to map masked clear vertex buffer, HRESULT: 0x%X.", result); - return; - } - - d3d11::PositionDepthColorVertex *vertices = reinterpret_cast<d3d11::PositionDepthColorVertex*>(mappedResource.pData); - - float depthClear = gl::clamp01(clearParams.depthClearValue); - d3d11::SetPositionDepthColorVertex(&vertices[0], -1.0f, 1.0f, depthClear, clearParams.colorClearValue); - d3d11::SetPositionDepthColorVertex(&vertices[1], -1.0f, -1.0f, depthClear, clearParams.colorClearValue); - d3d11::SetPositionDepthColorVertex(&vertices[2], 1.0f, 1.0f, depthClear, clearParams.colorClearValue); - d3d11::SetPositionDepthColorVertex(&vertices[3], 1.0f, -1.0f, depthClear, clearParams.colorClearValue); - - mDeviceContext->Unmap(mClearVB, 0); - - // Apply state - mDeviceContext->OMSetBlendState(blendState, blendFactors, sampleMask); - mDeviceContext->OMSetDepthStencilState(dsState, stencilClear); - mDeviceContext->RSSetState(mScissorEnabled ? mClearScissorRS : mClearNoScissorRS); - - // Apply shaders - ID3D11PixelShader *pixelShader = frameBuffer->usingExtendedDrawBuffers() ? mClearMultiplePS : mClearSinglePS; - - mDeviceContext->IASetInputLayout(mClearIL); - mDeviceContext->VSSetShader(mClearVS, NULL, 0); - mDeviceContext->PSSetShader(pixelShader, NULL, 0); - mDeviceContext->GSSetShader(NULL, NULL, 0); - - // Apply vertex buffer - static UINT stride = sizeof(d3d11::PositionDepthColorVertex); - static UINT startIdx = 0; - mDeviceContext->IASetVertexBuffers(0, 1, &mClearVB, &stride, &startIdx); - mDeviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - - // Draw the clear quad - mDeviceContext->Draw(4, 0); - - // Clean up - markAllStateDirty(); + mClear->clearFramebuffer(clearParams, frameBuffer); + invalidateFramebufferSwizzles(frameBuffer); } void Renderer11::markAllStateDirty() @@ -1894,12 +1603,12 @@ void Renderer11::markAllStateDirty() for (int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++) { mForceSetVertexSamplerStates[i] = true; - mCurVertexTextureSerials[i] = 0; + mCurVertexSRVs[i] = NULL; } for (int i = 0; i < gl::MAX_TEXTURE_IMAGE_UNITS; i++) { mForceSetPixelSamplerStates[i] = true; - mCurPixelTextureSerials[i] = 0; + mCurPixelSRVs[i] = NULL; } mForceSetBlendState = true; @@ -1908,16 +1617,32 @@ void Renderer11::markAllStateDirty() mForceSetScissor = true; mForceSetViewport = true; - mAppliedIBSerial = 0; - mAppliedStorageIBSerial = 0; + mAppliedIB = NULL; + mAppliedIBFormat = DXGI_FORMAT_UNKNOWN; mAppliedIBOffset = 0; - mAppliedProgramBinarySerial = 0; + mAppliedVertexShader = NULL; + mAppliedGeometryShader = NULL; + mCurPointGeometryShader = NULL; + mAppliedPixelShader = NULL; + + for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + mAppliedTFBuffers[i] = NULL; + mAppliedTFOffsets[i] = 0; + } + memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants)); memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants)); mInputLayoutCache.markDirty(); + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; i++) + { + mCurrentConstantBufferVS[i] = -1; + mCurrentConstantBufferPS[i] = -1; + } + mCurrentVertexConstantBuffer = NULL; mCurrentPixelConstantBuffer = NULL; mCurrentGeometryConstantBuffer = NULL; @@ -1930,39 +1655,13 @@ void Renderer11::releaseDeviceResources() mStateCache.clear(); mInputLayoutCache.clear(); - delete mVertexDataManager; - mVertexDataManager = NULL; - - delete mIndexDataManager; - mIndexDataManager = NULL; - - delete mLineLoopIB; - mLineLoopIB = NULL; - - delete mTriangleFanIB; - mTriangleFanIB = NULL; - - SafeRelease(mCopyVB); - SafeRelease(mCopySampler); - SafeRelease(mCopyIL); - SafeRelease(mCopyIL); - SafeRelease(mCopyVS); - SafeRelease(mCopyRGBAPS); - SafeRelease(mCopyRGBPS); - SafeRelease(mCopyLumPS); - SafeRelease(mCopyLumAlphaPS); - - mCopyResourcesInitialized = false; - - SafeRelease(mClearVB); - SafeRelease(mClearIL); - SafeRelease(mClearVS); - SafeRelease(mClearSinglePS); - SafeRelease(mClearMultiplePS); - SafeRelease(mClearScissorRS); - SafeRelease(mClearNoScissorRS); - - mClearResourcesInitialized = false; + SafeDelete(mVertexDataManager); + SafeDelete(mIndexDataManager); + SafeDelete(mLineLoopIB); + SafeDelete(mTriangleFanIB); + SafeDelete(mBlit); + SafeDelete(mClear); + SafeDelete(mPixelTransfer); SafeRelease(mDriverConstantBufferVS); SafeRelease(mDriverConstantBufferPS); @@ -2058,8 +1757,8 @@ bool Renderer11::testDeviceResettable() return false; } - dummyContext->Release(); - dummyDevice->Release(); + SafeRelease(dummyContext); + SafeRelease(dummyDevice); return true; } @@ -2068,31 +1767,17 @@ void Renderer11::release() { releaseDeviceResources(); - if (mDxgiFactory) - { - mDxgiFactory->Release(); - mDxgiFactory = NULL; - } - - if (mDxgiAdapter) - { - mDxgiAdapter->Release(); - mDxgiAdapter = NULL; - } + SafeRelease(mDxgiFactory); + SafeRelease(mDxgiAdapter); if (mDeviceContext) { mDeviceContext->ClearState(); mDeviceContext->Flush(); - mDeviceContext->Release(); - mDeviceContext = NULL; + SafeRelease(mDeviceContext); } - if (mDevice) - { - mDevice->Release(); - mDevice = NULL; - } + SafeRelease(mDevice); if (mD3d11Module) { @@ -2105,6 +1790,8 @@ void Renderer11::release() FreeLibrary(mDxgiModule); mDxgiModule = NULL; } + + mCompiler.release(); } bool Renderer11::resetDevice() @@ -2152,112 +1839,109 @@ GUID Renderer11::getAdapterIdentifier() const return adapterId; } -bool Renderer11::getBGRATextureSupport() const -{ - return mBGRATextureSupport; -} - -bool Renderer11::getDXT1TextureSupport() -{ - return mDXT1TextureSupport; -} - -bool Renderer11::getDXT3TextureSupport() -{ - return mDXT3TextureSupport; -} - -bool Renderer11::getDXT5TextureSupport() -{ - return mDXT5TextureSupport; -} - -bool Renderer11::getDepthTextureSupport() const +unsigned int Renderer11::getMaxVertexTextureImageUnits() const { - return mDepthTextureSupport; + META_ASSERT(MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 <= gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS); + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return MAX_TEXTURE_IMAGE_UNITS_VTF_SM4; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; + default: UNREACHABLE(); + return 0; + } } -bool Renderer11::getFloat32TextureSupport(bool *filtering, bool *renderable) +unsigned int Renderer11::getMaxCombinedTextureImageUnits() const { - *renderable = mFloat32RenderSupport; - *filtering = mFloat32FilterSupport; - return mFloat32TextureSupport; + return gl::MAX_TEXTURE_IMAGE_UNITS + getMaxVertexTextureImageUnits(); } -bool Renderer11::getFloat16TextureSupport(bool *filtering, bool *renderable) +unsigned int Renderer11::getReservedVertexUniformVectors() const { - *renderable = mFloat16RenderSupport; - *filtering = mFloat16FilterSupport; - return mFloat16TextureSupport; + return 0; // Driver uniforms are stored in a separate constant buffer } -bool Renderer11::getLuminanceTextureSupport() +unsigned int Renderer11::getReservedFragmentUniformVectors() const { - return false; + return 0; // Driver uniforms are stored in a separate constant buffer } -bool Renderer11::getLuminanceAlphaTextureSupport() +unsigned int Renderer11::getMaxVertexUniformVectors() const { - return false; + META_ASSERT(MAX_VERTEX_UNIFORM_VECTORS_D3D11 <= D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT); + ASSERT(mFeatureLevel >= D3D_FEATURE_LEVEL_9_1); + return MAX_VERTEX_UNIFORM_VECTORS_D3D11; } -bool Renderer11::getTextureFilterAnisotropySupport() const +unsigned int Renderer11::getMaxFragmentUniformVectors() const { - return true; + META_ASSERT(MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 <= D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT); + ASSERT(mFeatureLevel >= D3D_FEATURE_LEVEL_9_1); + return MAX_FRAGMENT_UNIFORM_VECTORS_D3D11; } -float Renderer11::getTextureMaxAnisotropy() const +unsigned int Renderer11::getMaxVaryingVectors() const { + META_ASSERT(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT); + META_ASSERT(D3D11_VS_OUTPUT_REGISTER_COUNT <= D3D11_PS_INPUT_REGISTER_COUNT); + META_ASSERT(D3D10_VS_OUTPUT_REGISTER_COUNT <= D3D10_PS_INPUT_REGISTER_COUNT); switch (mFeatureLevel) { case D3D_FEATURE_LEVEL_11_0: - return D3D11_MAX_MAXANISOTROPY; + return D3D11_VS_OUTPUT_REGISTER_COUNT - getReservedVaryings(); case D3D_FEATURE_LEVEL_10_1: + return D3D10_1_VS_OUTPUT_REGISTER_COUNT - getReservedVaryings(); case D3D_FEATURE_LEVEL_10_0: - return D3D10_MAX_MAXANISOTROPY; + return D3D10_VS_OUTPUT_REGISTER_COUNT - getReservedVaryings(); case D3D_FEATURE_LEVEL_9_3: + return 10 - getReservedVaryings(); case D3D_FEATURE_LEVEL_9_2: - return 16; case D3D_FEATURE_LEVEL_9_1: - return D3D_FL9_1_DEFAULT_MAX_ANISOTROPY; + return 8 - getReservedVaryings(); default: UNREACHABLE(); return 0; } } -bool Renderer11::getEventQuerySupport() +unsigned int Renderer11::getMaxVertexShaderUniformBuffers() const { - return true; -} + META_ASSERT(gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS >= D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT && + gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS >= D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT); -Range Renderer11::getViewportBounds() const -{ switch (mFeatureLevel) { case D3D_FEATURE_LEVEL_11_0: - return Range(D3D11_VIEWPORT_BOUNDS_MIN, D3D11_VIEWPORT_BOUNDS_MAX); + return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - getReservedVertexUniformBuffers(); case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: - return Range(D3D10_VIEWPORT_BOUNDS_MIN, D3D10_VIEWPORT_BOUNDS_MAX); + return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - getReservedVertexUniformBuffers(); case D3D_FEATURE_LEVEL_9_3: - return Range(D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION * -2, D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION * 2); case D3D_FEATURE_LEVEL_9_2: case D3D_FEATURE_LEVEL_9_1: - return Range(D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION * -2, D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION * 2); + return 0; default: UNREACHABLE(); - return Range(0, 0); + return 0; } } -unsigned int Renderer11::getMaxVertexTextureImageUnits() const +unsigned int Renderer11::getMaxFragmentShaderUniformBuffers() const { - META_ASSERT(MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 <= gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS); + META_ASSERT(gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS >= D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT && + gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS >= D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT); + switch (mFeatureLevel) { case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - getReservedFragmentUniformBuffers(); case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: - return MAX_TEXTURE_IMAGE_UNITS_VTF_SM4; + return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - getReservedFragmentUniformBuffers(); case D3D_FEATURE_LEVEL_9_3: case D3D_FEATURE_LEVEL_9_2: case D3D_FEATURE_LEVEL_9_1: @@ -2267,103 +1951,90 @@ unsigned int Renderer11::getMaxVertexTextureImageUnits() const } } -unsigned int Renderer11::getMaxCombinedTextureImageUnits() const +unsigned int Renderer11::getReservedVertexUniformBuffers() const { - return gl::MAX_TEXTURE_IMAGE_UNITS + getMaxVertexTextureImageUnits(); + // we reserve one buffer for the application uniforms, and one for driver uniforms + return 2; } -unsigned int Renderer11::getReservedVertexUniformVectors() const +unsigned int Renderer11::getReservedFragmentUniformBuffers() const { - return 0; // Driver uniforms are stored in a separate constant buffer + // we reserve one buffer for the application uniforms, and one for driver uniforms + return 2; } -unsigned int Renderer11::getReservedFragmentUniformVectors() const +unsigned int Renderer11::getReservedVaryings() const { - return 0; // Driver uniforms are stored in a separate constant buffer + // We potentially reserve varyings for gl_Position, dx_Position, gl_FragCoord and gl_PointSize + return 4; } -unsigned int Renderer11::getMaxVertexUniformVectors() const -{ - META_ASSERT(MAX_VERTEX_UNIFORM_VECTORS_D3D11 <= D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT); - ASSERT(mFeatureLevel >= D3D_FEATURE_LEVEL_9_1); - return MAX_VERTEX_UNIFORM_VECTORS_D3D11; -} -unsigned int Renderer11::getMaxFragmentUniformVectors() const +unsigned int Renderer11::getMaxTransformFeedbackBuffers() const { - META_ASSERT(MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 <= D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT); - ASSERT(mFeatureLevel >= D3D_FEATURE_LEVEL_9_1); - return MAX_FRAGMENT_UNIFORM_VECTORS_D3D11; -} + META_ASSERT(gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS >= D3D11_SO_BUFFER_SLOT_COUNT && + gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS >= D3D10_SO_BUFFER_SLOT_COUNT); -unsigned int Renderer11::getMaxVaryingVectors() const -{ - META_ASSERT(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT); switch (mFeatureLevel) { case D3D_FEATURE_LEVEL_11_0: - return D3D11_VS_OUTPUT_REGISTER_COUNT; + return D3D11_SO_BUFFER_SLOT_COUNT; case D3D_FEATURE_LEVEL_10_1: + return D3D10_1_SO_BUFFER_SLOT_COUNT; case D3D_FEATURE_LEVEL_10_0: - return D3D10_VS_OUTPUT_REGISTER_COUNT; + return D3D10_SO_BUFFER_SLOT_COUNT; case D3D_FEATURE_LEVEL_9_3: case D3D_FEATURE_LEVEL_9_2: case D3D_FEATURE_LEVEL_9_1: - return 8; + return 0; default: UNREACHABLE(); return 0; } } -bool Renderer11::getNonPower2TextureSupport() const +unsigned int Renderer11::getMaxTransformFeedbackSeparateComponents() const { switch (mFeatureLevel) { case D3D_FEATURE_LEVEL_11_0: + return getMaxTransformFeedbackInterleavedComponents() / getMaxTransformFeedbackBuffers(); case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: - return true; + // D3D 10 and 10.1 only allow one output per output slot if an output slot other than zero + // is used. + return 4; case D3D_FEATURE_LEVEL_9_3: case D3D_FEATURE_LEVEL_9_2: case D3D_FEATURE_LEVEL_9_1: - return false; + return 0; default: UNREACHABLE(); - return false; + return 0; } } -bool Renderer11::getOcclusionQuerySupport() const +unsigned int Renderer11::getMaxTransformFeedbackInterleavedComponents() const { - switch (mFeatureLevel) - { - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - return true; - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - return true; - case D3D_FEATURE_LEVEL_9_1: - return false; - default: UNREACHABLE(); - return false; - } + return (getMaxVaryingVectors() * 4); } -bool Renderer11::getInstancingSupport() const +unsigned int Renderer11::getMaxUniformBufferSize() const { + // Each component is a 4-element vector of 4-byte units (floats) + const unsigned int bytesPerComponent = 4 * sizeof(float); + switch (mFeatureLevel) { case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; case D3D_FEATURE_LEVEL_9_3: - return true; case D3D_FEATURE_LEVEL_9_2: case D3D_FEATURE_LEVEL_9_1: - return false; + return 0; default: UNREACHABLE(); - return false; + return 0; } } @@ -2372,25 +2043,7 @@ bool Renderer11::getShareHandleSupport() const // We only currently support share handles with BGRA surfaces, because // chrome needs BGRA. Once chrome fixes this, we should always support them. // PIX doesn't seem to support using share handles, so disable them. - return getBGRATextureSupport() && !gl::perfActive(); -} - -bool Renderer11::getDerivativeInstructionSupport() const -{ - switch (mFeatureLevel) - { - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - return true; - case D3D_FEATURE_LEVEL_9_3: - return true; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: - return false; - default: UNREACHABLE(); - return false; - } + return getRendererExtensions().textureFormatBGRA8888 && !gl::perfActive(); } bool Renderer11::getPostSubBufferSupport() const @@ -2399,16 +2052,40 @@ bool Renderer11::getPostSubBufferSupport() const return false; } +int Renderer11::getMaxRecommendedElementsIndices() const +{ + META_ASSERT(D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32); + META_ASSERT(D3D10_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32); + + // D3D11 allows up to 2^32 elements, but we report max signed int for convenience. + return std::numeric_limits<GLint>::max(); +} + +int Renderer11::getMaxRecommendedElementsVertices() const +{ + META_ASSERT(D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32); + META_ASSERT(D3D10_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32); + + // D3D11 allows up to 2^32 elements, but we report max signed int for convenience. + return std::numeric_limits<GLint>::max(); +} + +bool Renderer11::getSRGBTextureSupport() const +{ + return true; +} + int Renderer11::getMajorShaderModel() const { switch (mFeatureLevel) { case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MAJOR_VERSION; // 5 case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MAJOR_VERSION; // 4 - case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MAJOR_VERSION; // 4 + case D3D_FEATURE_LEVEL_10_0: case D3D_FEATURE_LEVEL_9_3: case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D10_SHADER_MAJOR_VERSION; // 4 (level 9) + case D3D_FEATURE_LEVEL_9_1: + return D3D10_SHADER_MAJOR_VERSION; // 4 default: UNREACHABLE(); return 0; } } @@ -2419,100 +2096,87 @@ int Renderer11::getMinorShaderModel() const { case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MINOR_VERSION; // 0 case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MINOR_VERSION; // 1 - case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MINOR_VERSION; // 0 + case D3D_FEATURE_LEVEL_10_0: case D3D_FEATURE_LEVEL_9_3: case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D10_SHADER_MINOR_VERSION; // 0 (level 9) + case D3D_FEATURE_LEVEL_9_1: return D3D10_SHADER_MINOR_VERSION; // 0 default: UNREACHABLE(); return 0; } } -float Renderer11::getMaxPointSize() const +int Renderer11::getMinSwapInterval() const { - // choose a reasonable maximum. we enforce this in the shader. - // (nb: on a Radeon 2600xt, DX9 reports a 256 max point size) - return 1024.0f; + return 0; } -int Renderer11::getMaxViewportDimension() const +int Renderer11::getMaxSwapInterval() const { - // Maximum viewport size must be at least as large as the largest render buffer (or larger). - // In our case return the maximum texture size, which is the maximum render buffer size. - META_ASSERT(D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION * 2 - 1 <= D3D11_VIEWPORT_BOUNDS_MAX); - META_ASSERT(D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION * 2 - 1 <= D3D10_VIEWPORT_BOUNDS_MAX); - - switch (mFeatureLevel) - { - case D3D_FEATURE_LEVEL_11_0: - return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 16384 - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 8192 - case D3D_FEATURE_LEVEL_9_3: - return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 4096 - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: - return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 2048 - default: UNREACHABLE(); - return 0; - } + return 4; } -int Renderer11::getMaxTextureWidth() const +int Renderer11::getMaxSupportedSamples() const { - switch (mFeatureLevel) - { - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 16384 - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 8192 - case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 4096 - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 2048 - default: UNREACHABLE(); return 0; - } + return mMaxSupportedSamples; } -int Renderer11::getMaxTextureHeight() const +GLsizei Renderer11::getMaxSupportedFormatSamples(GLenum internalFormat) const { - switch (mFeatureLevel) - { - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 16384 - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 8192 - case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 4096 - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 2048 - default: UNREACHABLE(); return 0; - } + DXGI_FORMAT format = gl_d3d11::GetRenderableFormat(internalFormat); + MultisampleSupportMap::const_iterator iter = mMultisampleSupportMap.find(format); + return (iter != mMultisampleSupportMap.end()) ? iter->second.maxSupportedSamples : 0; } -bool Renderer11::get32BitIndexSupport() const +GLsizei Renderer11::getNumSampleCounts(GLenum internalFormat) const { - switch (mFeatureLevel) + unsigned int numCounts = 0; + + // D3D11 supports multisampling for signed and unsigned format, but ES 3.0 does not + GLenum componentType = gl::GetComponentType(internalFormat); + if (componentType != GL_INT && componentType != GL_UNSIGNED_INT) { - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP >= 32; // true - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; - default: UNREACHABLE(); return false; + DXGI_FORMAT format = gl_d3d11::GetRenderableFormat(internalFormat); + MultisampleSupportMap::const_iterator iter = mMultisampleSupportMap.find(format); + + if (iter != mMultisampleSupportMap.end()) + { + const MultisampleSupportInfo& info = iter->second; + for (int i = 0; i < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; i++) + { + if (info.qualityLevels[i] > 0) + { + numCounts++; + } + } + } } -} -int Renderer11::getMinSwapInterval() const -{ - return 0; + return numCounts; } -int Renderer11::getMaxSwapInterval() const +void Renderer11::getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const { - return 4; -} + // D3D11 supports multisampling for signed and unsigned format, but ES 3.0 does not + GLenum componentType = gl::GetComponentType(internalFormat); + if (componentType == GL_INT || componentType == GL_UNSIGNED_INT) + { + return; + } -int Renderer11::getMaxSupportedSamples() const -{ - return mMaxSupportedSamples; + DXGI_FORMAT format = gl_d3d11::GetRenderableFormat(internalFormat); + MultisampleSupportMap::const_iterator iter = mMultisampleSupportMap.find(format); + + if (iter != mMultisampleSupportMap.end()) + { + const MultisampleSupportInfo& info = iter->second; + int bufPos = 0; + for (int i = D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT - 1; i >= 0 && bufPos < bufSize; i--) + { + if (info.qualityLevels[i] > 0) + { + params[bufPos++] = i + 1; + } + } + } } int Renderer11::getNearestSupportedSamples(DXGI_FORMAT format, unsigned int requested) const @@ -2538,32 +2202,6 @@ int Renderer11::getNearestSupportedSamples(DXGI_FORMAT format, unsigned int requ return -1; } -unsigned int Renderer11::getMaxRenderTargets() const -{ - META_ASSERT(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT <= gl::IMPLEMENTATION_MAX_DRAW_BUFFERS); - META_ASSERT(D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT <= gl::IMPLEMENTATION_MAX_DRAW_BUFFERS); - META_ASSERT(D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT <= gl::IMPLEMENTATION_MAX_DRAW_BUFFERS); - META_ASSERT(D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT <= gl::IMPLEMENTATION_MAX_DRAW_BUFFERS); - - switch (mFeatureLevel) - { - case D3D_FEATURE_LEVEL_11_0: - return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; // 8 - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - case D3D_FEATURE_LEVEL_9_3: // return D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT; // 4 - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: // return D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT; // 1 - // Feature level 10.0 and 10.1 cards perform very poorly when the pixel shader - // outputs to multiple RTs that are not bound. - // TODO: Remove pixel shader outputs for render targets that are not bound. - return 1; - default: - UNREACHABLE(); - return 1; - } -} - bool Renderer11::copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source) { if (source && dest) @@ -2571,7 +2209,10 @@ bool Renderer11::copyToRenderTarget(TextureStorageInterface2D *dest, TextureStor TextureStorage11_2D *source11 = TextureStorage11_2D::makeTextureStorage11_2D(source->getStorageInstance()); TextureStorage11_2D *dest11 = TextureStorage11_2D::makeTextureStorage11_2D(dest->getStorageInstance()); - mDeviceContext->CopyResource(dest11->getBaseTexture(), source11->getBaseTexture()); + mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); + + dest11->invalidateSwizzleCache(); + return true; } @@ -2585,7 +2226,44 @@ bool Renderer11::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureSt TextureStorage11_Cube *source11 = TextureStorage11_Cube::makeTextureStorage11_Cube(source->getStorageInstance()); TextureStorage11_Cube *dest11 = TextureStorage11_Cube::makeTextureStorage11_Cube(dest->getStorageInstance()); - mDeviceContext->CopyResource(dest11->getBaseTexture(), source11->getBaseTexture()); + mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); + + dest11->invalidateSwizzleCache(); + + return true; + } + + return false; +} + +bool Renderer11::copyToRenderTarget(TextureStorageInterface3D *dest, TextureStorageInterface3D *source) +{ + if (source && dest) + { + TextureStorage11_3D *source11 = TextureStorage11_3D::makeTextureStorage11_3D(source->getStorageInstance()); + TextureStorage11_3D *dest11 = TextureStorage11_3D::makeTextureStorage11_3D(dest->getStorageInstance()); + + mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); + + dest11->invalidateSwizzleCache(); + + return true; + } + + return false; +} + +bool Renderer11::copyToRenderTarget(TextureStorageInterface2DArray *dest, TextureStorageInterface2DArray *source) +{ + if (source && dest) + { + TextureStorage11_2DArray *source11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(source->getStorageInstance()); + TextureStorage11_2DArray *dest11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(dest->getStorageInstance()); + + mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); + + dest11->invalidateSwizzleCache(); + return true; } @@ -2595,7 +2273,7 @@ bool Renderer11::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureSt bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level) { - gl::Renderbuffer *colorbuffer = framebuffer->getReadColorbuffer(); + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); if (!colorbuffer) { ERR("Failed to retrieve the color buffer from the frame buffer."); @@ -2637,14 +2315,18 @@ bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &so return gl::error(GL_OUT_OF_MEMORY, false); } - gl::Rectangle destRect; - destRect.x = xoffset; - destRect.y = yoffset; - destRect.width = sourceRect.width; - destRect.height = sourceRect.height; + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + + gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + + // Use nearest filtering because source and destination are the same size for the direct + // copy + bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST); - bool ret = copyTexture(source, sourceRect, sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), - dest, destRect, destRenderTarget->getWidth(), destRenderTarget->getHeight(), destFormat); + storage11->invalidateSwizzleCacheLevel(level); return ret; } @@ -2652,7 +2334,7 @@ bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &so bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level) { - gl::Renderbuffer *colorbuffer = framebuffer->getReadColorbuffer(); + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); if (!colorbuffer) { ERR("Failed to retrieve the color buffer from the frame buffer."); @@ -2680,7 +2362,7 @@ bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &so return gl::error(GL_OUT_OF_MEMORY, false); } - RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTarget(target, level)); + RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTargetFace(target, level)); if (!destRenderTarget) { ERR("Failed to retrieve the render target from the destination storage."); @@ -2694,194 +2376,144 @@ bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &so return gl::error(GL_OUT_OF_MEMORY, false); } - gl::Rectangle destRect; - destRect.x = xoffset; - destRect.y = yoffset; - destRect.width = sourceRect.width; - destRect.height = sourceRect.height; + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); - bool ret = copyTexture(source, sourceRect, sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), - dest, destRect, destRenderTarget->getWidth(), destRenderTarget->getHeight(), destFormat); + gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + + // Use nearest filtering because source and destination are the same size for the direct + // copy + bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST); + + storage11->invalidateSwizzleCacheLevel(level); return ret; } -bool Renderer11::copyTexture(ID3D11ShaderResourceView *source, const gl::Rectangle &sourceArea, unsigned int sourceWidth, unsigned int sourceHeight, - ID3D11RenderTargetView *dest, const gl::Rectangle &destArea, unsigned int destWidth, unsigned int destHeight, GLenum destFormat) +bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface3D *storage, GLint level) { - HRESULT result; - - if (!mCopyResourcesInitialized) + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + if (!colorbuffer) { - ASSERT(!mCopyVB && !mCopySampler && !mCopyIL && !mCopyVS && !mCopyRGBAPS && !mCopyRGBPS && !mCopyLumPS && !mCopyLumAlphaPS); - - D3D11_BUFFER_DESC vbDesc; - vbDesc.ByteWidth = sizeof(d3d11::PositionTexCoordVertex) * 4; - vbDesc.Usage = D3D11_USAGE_DYNAMIC; - vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - vbDesc.MiscFlags = 0; - vbDesc.StructureByteStride = 0; - - result = mDevice->CreateBuffer(&vbDesc, NULL, &mCopyVB); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mCopyVB, "Renderer11 copy texture vertex buffer"); - - D3D11_SAMPLER_DESC samplerDesc; - samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.MipLODBias = 0.0f; - samplerDesc.MaxAnisotropy = 0; - samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; - samplerDesc.BorderColor[0] = 0.0f; - samplerDesc.BorderColor[1] = 0.0f; - samplerDesc.BorderColor[2] = 0.0f; - samplerDesc.BorderColor[3] = 0.0f; - samplerDesc.MinLOD = 0.0f; - samplerDesc.MaxLOD = mDevice->GetFeatureLevel() >= D3D_FEATURE_LEVEL_10_0 ? 0.0f : FLT_MAX; - - result = mDevice->CreateSamplerState(&samplerDesc, &mCopySampler); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mCopySampler, "Renderer11 copy sampler"); - - D3D11_INPUT_ELEMENT_DESC quadLayout[] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - - result = mDevice->CreateInputLayout(quadLayout, 2, g_VS_Passthrough, sizeof(g_VS_Passthrough), &mCopyIL); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mCopyIL, "Renderer11 copy texture input layout"); - - result = mDevice->CreateVertexShader(g_VS_Passthrough, sizeof(g_VS_Passthrough), NULL, &mCopyVS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mCopyVS, "Renderer11 copy texture vertex shader"); - - result = mDevice->CreatePixelShader(g_PS_PassthroughRGBA, sizeof(g_PS_PassthroughRGBA), NULL, &mCopyRGBAPS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mCopyRGBAPS, "Renderer11 copy texture RGBA pixel shader"); - - result = mDevice->CreatePixelShader(g_PS_PassthroughRGB, sizeof(g_PS_PassthroughRGB), NULL, &mCopyRGBPS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mCopyRGBPS, "Renderer11 copy texture RGB pixel shader"); - - result = mDevice->CreatePixelShader(g_PS_PassthroughLum, sizeof(g_PS_PassthroughLum), NULL, &mCopyLumPS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mCopyLumPS, "Renderer11 copy texture luminance pixel shader"); - - result = mDevice->CreatePixelShader(g_PS_PassthroughLumAlpha, sizeof(g_PS_PassthroughLumAlpha), NULL, &mCopyLumAlphaPS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mCopyLumAlphaPS, "Renderer11 copy texture luminance alpha pixel shader"); - - mCopyResourcesInitialized = true; + ERR("Failed to retrieve the color buffer from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); } - // Verify the source and destination area sizes - if (sourceArea.x < 0 || sourceArea.x + sourceArea.width > static_cast<int>(sourceWidth) || - sourceArea.y < 0 || sourceArea.y + sourceArea.height > static_cast<int>(sourceHeight) || - destArea.x < 0 || destArea.x + destArea.width > static_cast<int>(destWidth) || - destArea.y < 0 || destArea.y + destArea.height > static_cast<int>(destHeight)) + RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); + if (!sourceRenderTarget) { - return gl::error(GL_INVALID_VALUE, false); + ERR("Failed to retrieve the render target from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); } - // Set vertices - D3D11_MAPPED_SUBRESOURCE mappedResource; - result = mDeviceContext->Map(mCopyVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + if (!source) { - ERR("Failed to map vertex buffer for texture copy, HRESULT: 0x%X.", result); + ERR("Failed to retrieve the render target view from the render target."); return gl::error(GL_OUT_OF_MEMORY, false); } - d3d11::PositionTexCoordVertex *vertices = static_cast<d3d11::PositionTexCoordVertex*>(mappedResource.pData); + TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage->getStorageInstance()); + if (!storage11) + { + ERR("Failed to retrieve the texture storage from the destination."); + return gl::error(GL_OUT_OF_MEMORY, false); + } - // Create a quad in homogeneous coordinates - float x1 = (destArea.x / float(destWidth)) * 2.0f - 1.0f; - float y1 = ((destHeight - destArea.y - destArea.height) / float(destHeight)) * 2.0f - 1.0f; - float x2 = ((destArea.x + destArea.width) / float(destWidth)) * 2.0f - 1.0f; - float y2 = ((destHeight - destArea.y) / float(destHeight)) * 2.0f - 1.0f; + RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTargetLayer(level, zOffset)); + if (!destRenderTarget) + { + ERR("Failed to retrieve the render target from the destination storage."); + return gl::error(GL_OUT_OF_MEMORY, false); + } - float u1 = sourceArea.x / float(sourceWidth); - float v1 = sourceArea.y / float(sourceHeight); - float u2 = (sourceArea.x + sourceArea.width) / float(sourceWidth); - float v2 = (sourceArea.y + sourceArea.height) / float(sourceHeight); + ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); + if (!dest) + { + ERR("Failed to retrieve the render target view from the destination render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } - d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v2); - d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v1); - d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v2); - d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v1); + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); - mDeviceContext->Unmap(mCopyVB, 0); + gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); - static UINT stride = sizeof(d3d11::PositionTexCoordVertex); - static UINT startIdx = 0; - mDeviceContext->IASetVertexBuffers(0, 1, &mCopyVB, &stride, &startIdx); + // Use nearest filtering because source and destination are the same size for the direct + // copy + bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST); - // Apply state - mDeviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); - mDeviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); - mDeviceContext->RSSetState(NULL); + storage11->invalidateSwizzleCacheLevel(level); - // Apply shaders - mDeviceContext->IASetInputLayout(mCopyIL); - mDeviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - mDeviceContext->VSSetShader(mCopyVS, NULL, 0); + return ret; +} - ID3D11PixelShader *ps = NULL; - switch(destFormat) +bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level) +{ + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + if (!colorbuffer) { - case GL_RGBA: ps = mCopyRGBAPS; break; - case GL_RGB: ps = mCopyRGBPS; break; - case GL_ALPHA: ps = mCopyRGBAPS; break; - case GL_BGRA_EXT: ps = mCopyRGBAPS; break; - case GL_LUMINANCE: ps = mCopyLumPS; break; - case GL_LUMINANCE_ALPHA: ps = mCopyLumAlphaPS; break; - default: UNREACHABLE(); ps = NULL; break; + ERR("Failed to retrieve the color buffer from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); } - mDeviceContext->PSSetShader(ps, NULL, 0); - mDeviceContext->GSSetShader(NULL, NULL, 0); - - // Unset the currently bound shader resource to avoid conflicts - static ID3D11ShaderResourceView *const nullSRV = NULL; - mDeviceContext->PSSetShaderResources(0, 1, &nullSRV); + RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); + if (!sourceRenderTarget) + { + ERR("Failed to retrieve the render target from the frame buffer."); + return gl::error(GL_OUT_OF_MEMORY, false); + } - // Apply render target - setOneTimeRenderTarget(dest); + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + if (!source) + { + ERR("Failed to retrieve the render target view from the render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } - // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = destWidth; - viewport.Height = destHeight; - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - mDeviceContext->RSSetViewports(1, &viewport); + TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage->getStorageInstance()); + if (!storage11) + { + SafeRelease(source); + ERR("Failed to retrieve the texture storage from the destination."); + return gl::error(GL_OUT_OF_MEMORY, false); + } - // Apply textures - mDeviceContext->PSSetShaderResources(0, 1, &source); - mDeviceContext->PSSetSamplers(0, 1, &mCopySampler); + RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTargetLayer(level, zOffset)); + if (!destRenderTarget) + { + SafeRelease(source); + ERR("Failed to retrieve the render target from the destination storage."); + return gl::error(GL_OUT_OF_MEMORY, false); + } - // Draw the quad - mDeviceContext->Draw(4, 0); + ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); + if (!dest) + { + ERR("Failed to retrieve the render target view from the destination render target."); + return gl::error(GL_OUT_OF_MEMORY, false); + } - // Unbind textures and render targets and vertex buffer - mDeviceContext->PSSetShaderResources(0, 1, &nullSRV); + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); - unapplyRenderTargets(); + gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); - UINT zero = 0; - ID3D11Buffer *const nullBuffer = NULL; - mDeviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + // Use nearest filtering because source and destination are the same size for the direct + // copy + bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, + destFormat, GL_NEAREST); - markAllStateDirty(); + storage11->invalidateSwizzleCacheLevel(level); - return true; + return ret; } void Renderer11::unapplyRenderTargets() @@ -2895,7 +2527,7 @@ void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView rtvArray[0] = renderTargetView; - mDeviceContext->OMSetRenderTargets(getMaxRenderTargets(), rtvArray, NULL); + mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, rtvArray, NULL); // Do not preserve the serial for this one-time-use render target for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++) @@ -2913,8 +2545,9 @@ RenderTarget *Renderer11::createRenderTarget(SwapChain *swapChain, bool depth) { // Note: depth stencil may be NULL for 0 sized surfaces renderTarget = new RenderTarget11(this, swapChain11->getDepthStencil(), - swapChain11->getDepthStencilTexture(), NULL, - swapChain11->getWidth(), swapChain11->getHeight()); + swapChain11->getDepthStencilTexture(), + swapChain11->getDepthStencilShaderResource(), + swapChain11->getWidth(), swapChain11->getHeight(), 1); } else { @@ -2922,56 +2555,89 @@ RenderTarget *Renderer11::createRenderTarget(SwapChain *swapChain, bool depth) renderTarget = new RenderTarget11(this, swapChain11->getRenderTarget(), swapChain11->getOffscreenTexture(), swapChain11->getRenderTargetShaderResource(), - swapChain11->getWidth(), swapChain11->getHeight()); + swapChain11->getWidth(), swapChain11->getHeight(), 1); } return renderTarget; } -RenderTarget *Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth) +RenderTarget *Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples) { - RenderTarget11 *renderTarget = new RenderTarget11(this, width, height, format, samples, depth); + RenderTarget11 *renderTarget = new RenderTarget11(this, width, height, format, samples); return renderTarget; } -ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length, rx::ShaderType type) +ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers) { ShaderExecutable11 *executable = NULL; + HRESULT result; switch (type) { case rx::SHADER_VERTEX: { - ID3D11VertexShader *vshader = NULL; - HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vshader); + ID3D11VertexShader *vertexShader = NULL; + ID3D11GeometryShader *streamOutShader = NULL; + + result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader); ASSERT(SUCCEEDED(result)); - if (vshader) + if (transformFeedbackVaryings.size() > 0) + { + std::vector<D3D11_SO_DECLARATION_ENTRY> soDeclaration; + for (size_t i = 0; i < transformFeedbackVaryings.size(); i++) + { + const gl::LinkedVarying &varying = transformFeedbackVaryings[i]; + GLenum transposedType = gl::TransposeMatrixType(varying.type); + + for (size_t j = 0; j < varying.semanticIndexCount; j++) + { + D3D11_SO_DECLARATION_ENTRY entry = { 0 }; + entry.Stream = 0; + entry.SemanticName = varying.semanticName.c_str(); + entry.SemanticIndex = varying.semanticIndex + j; + entry.StartComponent = 0; + entry.ComponentCount = gl::VariableColumnCount(transposedType); + entry.OutputSlot = (separatedOutputBuffers ? i : 0); + soDeclaration.push_back(entry); + } + } + + result = mDevice->CreateGeometryShaderWithStreamOutput(function, length, soDeclaration.data(), soDeclaration.size(), + NULL, 0, 0, NULL, &streamOutShader); + ASSERT(SUCCEEDED(result)); + } + + if (vertexShader) { - executable = new ShaderExecutable11(function, length, vshader); + executable = new ShaderExecutable11(function, length, vertexShader, streamOutShader); } } break; case rx::SHADER_PIXEL: { - ID3D11PixelShader *pshader = NULL; - HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pshader); + ID3D11PixelShader *pixelShader = NULL; + + result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader); ASSERT(SUCCEEDED(result)); - if (pshader) + if (pixelShader) { - executable = new ShaderExecutable11(function, length, pshader); + executable = new ShaderExecutable11(function, length, pixelShader); } } break; case rx::SHADER_GEOMETRY: { - ID3D11GeometryShader *gshader = NULL; - HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &gshader); + ID3D11GeometryShader *geometryShader = NULL; + + result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader); ASSERT(SUCCEEDED(result)); - if (gshader) + if (geometryShader) { - executable = new ShaderExecutable11(function, length, gshader); + executable = new ShaderExecutable11(function, length, geometryShader); } } break; @@ -2983,41 +2649,107 @@ ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length return executable; } -ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, D3DWorkaroundType workaround) +ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround) { - std::string profile; - + const char *profileType = NULL; switch (type) { case rx::SHADER_VERTEX: - profile = "vs_4_0"; + profileType = "vs"; break; case rx::SHADER_PIXEL: - profile = "ps_4_0"; + profileType = "ps"; break; case rx::SHADER_GEOMETRY: - profile = "gs_4_0"; + profileType = "gs"; + break; + default: + UNREACHABLE(); + return NULL; + } + + const char *profileVersion = NULL; + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: + profileVersion = "5_0"; + break; + case D3D_FEATURE_LEVEL_10_1: + profileVersion = "4_1"; + break; + case D3D_FEATURE_LEVEL_10_0: + profileVersion = "4_0"; + break; + case D3D_FEATURE_LEVEL_9_3: + profileVersion = "4_0_level_9_3"; + break; + case D3D_FEATURE_LEVEL_9_2: + profileVersion = "4_0_level_9_2"; + break; + case D3D_FEATURE_LEVEL_9_1: + profileVersion = "4_0_level_9_1"; break; default: UNREACHABLE(); return NULL; } - if (mFeatureLevel == D3D_FEATURE_LEVEL_9_3) - profile += "_level_9_3"; - else if (mFeatureLevel == D3D_FEATURE_LEVEL_9_2 || mFeatureLevel == D3D_FEATURE_LEVEL_9_1) - profile += "_level_9_1"; + char profile[32]; + snprintf(profile, ArraySize(profile), "%s_%s", profileType, profileVersion); + + UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL0; + + if (gl::perfActive()) + { +#ifndef NDEBUG + flags = D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + flags |= D3DCOMPILE_DEBUG; + + std::string sourcePath = getTempPath(); + std::string sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(shaderHLSL); + writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); + } + + // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. + // Try the default flags first and if compilation fails, try some alternatives. + const UINT extraFlags[] = + { + flags, + flags | D3DCOMPILE_SKIP_VALIDATION, + flags | D3DCOMPILE_SKIP_OPTIMIZATION + }; + + const static char *extraFlagNames[] = + { + "default", + "skip validation", + "skip optimization" + }; - ID3DBlob *binary = (ID3DBlob*)compileToBinary(infoLog, shaderHLSL, profile.c_str(), D3DCOMPILE_OPTIMIZATION_LEVEL0, false); + int attempts = ArraySize(extraFlags); + + ID3DBlob *binary = (ID3DBlob*)mCompiler.compileToBinary(infoLog, shaderHLSL, profile, extraFlags, extraFlagNames, attempts); if (!binary) + { return NULL; + } - ShaderExecutable *executable = loadExecutable((DWORD *)binary->GetBufferPointer(), binary->GetBufferSize(), type); - binary->Release(); + ShaderExecutable *executable = loadExecutable((DWORD *)binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers); + SafeRelease(binary); return executable; } +rx::UniformStorage *Renderer11::createUniformStorage(size_t storageSize) +{ + return new UniformStorage11(this, storageSize); +} + VertexBuffer *Renderer11::createVertexBuffer() { return new VertexBuffer11(this); @@ -3028,9 +2760,14 @@ IndexBuffer *Renderer11::createIndexBuffer() return new IndexBuffer11(this); } -BufferStorage *Renderer11::createBufferStorage() +BufferImpl *Renderer11::createBuffer() { - return new BufferStorage11(this); + return new Buffer11(this); +} + +VertexArrayImpl *Renderer11::createVertexArray() +{ + return new VertexArray11(this); } QueryImpl *Renderer11::createQuery(GLenum type) @@ -3043,7 +2780,45 @@ FenceImpl *Renderer11::createFence() return new Fence11(this); } -bool Renderer11::getRenderTargetResource(gl::Renderbuffer *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource) +bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const +{ + ASSERT(getRendererExtensions().pixelBufferObject); + + // sRGB formats do not work with D3D11 buffer SRVs + if (gl::GetColorEncoding(internalFormat) == GL_SRGB) + { + return false; + } + + // We cannot support direct copies to non-color-renderable formats + if (gl_d3d11::GetRTVFormat(internalFormat) != DXGI_FORMAT_UNKNOWN) + { + return false; + } + + // We skip all 3-channel formats since sometimes format support is missing + if (gl::GetComponentCount(internalFormat) == 3) + { + return false; + } + + // We don't support formats which we can't represent without conversion + if (getNativeTextureFormat(internalFormat) != internalFormat) + { + return false; + } + + return true; +} + +bool Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +{ + ASSERT(supportsFastCopyBufferToTexture(destinationFormat)); + return mPixelTransfer->copyBufferToTexture(unpack, offset, destRenderTarget, destinationFormat, sourcePixelsType, destArea); +} + +bool Renderer11::getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource) { ASSERT(colorbuffer != NULL); @@ -3060,8 +2835,8 @@ bool Renderer11::getRenderTargetResource(gl::Renderbuffer *colorbuffer, unsigned if (textureResource) { - HRESULT result = textureResource->QueryInterface(IID_ID3D11Texture2D, (void**)resource); - textureResource->Release(); + HRESULT result = textureResource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)resource); + SafeRelease(textureResource); if (SUCCEEDED(result)) { @@ -3080,11 +2855,11 @@ bool Renderer11::getRenderTargetResource(gl::Renderbuffer *colorbuffer, unsigned } bool Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - bool blitRenderTarget, bool blitDepthStencil) + const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) { if (blitRenderTarget) { - gl::Renderbuffer *readBuffer = readTarget->getReadColorbuffer(); + gl::FramebufferAttachment *readBuffer = readTarget->getReadColorbuffer(); if (!readBuffer) { @@ -3098,7 +2873,7 @@ bool Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &read { if (drawTarget->isEnabledColorAttachment(colorAttachment)) { - gl::Renderbuffer *drawBuffer = drawTarget->getColorbuffer(colorAttachment); + gl::FramebufferAttachment *drawBuffer = drawTarget->getColorbuffer(colorAttachment); if (!drawBuffer) { @@ -3108,7 +2883,8 @@ bool Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &read RenderTarget *drawRenderTarget = drawBuffer->getRenderTarget(); - if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, false)) + if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor, + blitRenderTarget, false, false)) { return false; } @@ -3116,10 +2892,10 @@ bool Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &read } } - if (blitDepthStencil) + if (blitDepth || blitStencil) { - gl::Renderbuffer *readBuffer = readTarget->getDepthOrStencilbuffer(); - gl::Renderbuffer *drawBuffer = drawTarget->getDepthOrStencilbuffer(); + gl::FramebufferAttachment *readBuffer = readTarget->getDepthOrStencilbuffer(); + gl::FramebufferAttachment *drawBuffer = drawTarget->getDepthOrStencilbuffer(); if (!readBuffer) { @@ -3136,22 +2912,25 @@ bool Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &read RenderTarget *readRenderTarget = readBuffer->getDepthStencil(); RenderTarget *drawRenderTarget = drawBuffer->getDepthStencil(); - if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, true)) + if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor, + false, blitDepth, blitStencil)) { return false; } } + invalidateFramebufferSwizzles(drawTarget); + return true; } -void Renderer11::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, - GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels) +void Renderer11::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void* pixels) { ID3D11Texture2D *colorBufferTexture = NULL; unsigned int subresourceIndex = 0; - gl::Renderbuffer *colorbuffer = framebuffer->getReadColorbuffer(); + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); if (colorbuffer && getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture)) { @@ -3161,11 +2940,18 @@ void Renderer11::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsi area.width = width; area.height = height; - readTextureData(colorBufferTexture, subresourceIndex, area, colorbuffer->getActualFormat(), format, type, outputPitch, - packReverseRowOrder, packAlignment, pixels); + if (pack.pixelBuffer.get() != NULL) + { + rx::Buffer11 *packBufferStorage = Buffer11::makeBuffer11(pack.pixelBuffer.get()->getImplementation()); + PackPixelsParams packParams(area, format, type, outputPitch, pack, reinterpret_cast<ptrdiff_t>(pixels)); + packBufferStorage->packPixels(colorBufferTexture, subresourceIndex, packParams); + } + else + { + readTextureData(colorBufferTexture, subresourceIndex, area, format, type, outputPitch, pack, pixels); + } - colorBufferTexture->Release(); - colorBufferTexture = NULL; + SafeRelease(colorBufferTexture); } } @@ -3187,305 +2973,78 @@ TextureStorage *Renderer11::createTextureStorage2D(SwapChain *swapChain) return new TextureStorage11_2D(this, swapChain11); } -TextureStorage *Renderer11::createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height) +TextureStorage *Renderer11::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) { - return new TextureStorage11_2D(this, levels, internalformat, usage, forceRenderable, width, height); + return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels); } -TextureStorage *Renderer11::createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size) +TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) { - return new TextureStorage11_Cube(this, levels, internalformat, usage, forceRenderable, size); + return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels); } -static inline unsigned int getFastPixelCopySize(DXGI_FORMAT sourceFormat, GLenum sourceGLFormat, GLenum destFormat, GLenum destType) +TextureStorage *Renderer11::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) { - if (sourceFormat == DXGI_FORMAT_A8_UNORM && - destFormat == GL_ALPHA && - destType == GL_UNSIGNED_BYTE) - { - return 1; - } - else if (sourceFormat == DXGI_FORMAT_R8G8B8A8_UNORM && - sourceGLFormat == GL_RGBA8_OES && - destFormat == GL_RGBA && - destType == GL_UNSIGNED_BYTE) - { - return 4; - } - else if (sourceFormat == DXGI_FORMAT_B8G8R8A8_UNORM && - destFormat == GL_BGRA_EXT && - destType == GL_UNSIGNED_BYTE) - { - return 4; - } - else if (sourceFormat == DXGI_FORMAT_R16G16B16A16_FLOAT && - sourceGLFormat == GL_RGBA16F_EXT && - destFormat == GL_RGBA && - destType == GL_HALF_FLOAT_OES) - { - return 8; - } - else if (sourceFormat == DXGI_FORMAT_R32G32B32_FLOAT && - destFormat == GL_RGB && - destType == GL_FLOAT) - { - return 12; - } - else if (sourceFormat == DXGI_FORMAT_R32G32B32A32_FLOAT && - sourceGLFormat == GL_RGBA32F_EXT && - destFormat == GL_RGBA && - destType == GL_FLOAT) - { - return 16; - } - else - { - return 0; - } + return new TextureStorage11_3D(this, internalformat, renderTarget, width, height, depth, levels); } -static inline void readPixelColor(const unsigned char *data, DXGI_FORMAT format, GLenum glFormat, unsigned int x, - unsigned int y, int inputPitch, gl::Color *outColor) +TextureStorage *Renderer11::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) { - switch (format) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - { - unsigned int rgba = *reinterpret_cast<const unsigned int*>(data + 4 * x + y * inputPitch); - outColor->red = (rgba & 0x000000FF) * (1.0f / 0x000000FF); - outColor->green = (rgba & 0x0000FF00) * (1.0f / 0x0000FF00); - outColor->blue = (rgba & 0x00FF0000) * (1.0f / 0x00FF0000); - - if (gl::GetAlphaSize(glFormat) > 0) - { - outColor->alpha = (rgba & 0xFF000000) * (1.0f / 0xFF000000); - } - else - { - outColor->alpha = 1.0f; - } - } - break; - - case DXGI_FORMAT_A8_UNORM: - { - outColor->red = 0.0f; - outColor->green = 0.0f; - outColor->blue = 0.0f; - outColor->alpha = *(data + x + y * inputPitch) / 255.0f; - } - break; - - case DXGI_FORMAT_R32G32B32A32_FLOAT: - { - outColor->red = *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 0); - outColor->green = *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 1); - outColor->blue = *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 2); - - if (gl::GetAlphaSize(glFormat) > 0) - { - outColor->alpha = *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 3); - } - else - { - outColor->alpha = 1.0f; - } - } - break; - - case DXGI_FORMAT_R32G32B32_FLOAT: - { - outColor->red = *(reinterpret_cast<const float*>(data + 12 * x + y * inputPitch) + 0); - outColor->green = *(reinterpret_cast<const float*>(data + 12 * x + y * inputPitch) + 1); - outColor->blue = *(reinterpret_cast<const float*>(data + 12 * x + y * inputPitch) + 2); - outColor->alpha = 1.0f; - } - break; - - case DXGI_FORMAT_R16G16B16A16_FLOAT: - { - outColor->red = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 0)); - outColor->green = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 1)); - outColor->blue = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 2)); - - if (gl::GetAlphaSize(glFormat) > 0) - { - outColor->alpha = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 3)); - } - else - { - outColor->alpha = 1.0f; - } - } - break; - - case DXGI_FORMAT_B8G8R8A8_UNORM: - { - unsigned int bgra = *reinterpret_cast<const unsigned int*>(data + 4 * x + y * inputPitch); - outColor->red = (bgra & 0x00FF0000) * (1.0f / 0x00FF0000); - outColor->blue = (bgra & 0x000000FF) * (1.0f / 0x000000FF); - outColor->green = (bgra & 0x0000FF00) * (1.0f / 0x0000FF00); - outColor->alpha = (bgra & 0xFF000000) * (1.0f / 0xFF000000); - } - break; - - case DXGI_FORMAT_R8_UNORM: - { - outColor->red = *(data + x + y * inputPitch) / 255.0f; - outColor->green = 0.0f; - outColor->blue = 0.0f; - outColor->alpha = 1.0f; - } - break; - - case DXGI_FORMAT_R8G8_UNORM: - { - unsigned short rg = *reinterpret_cast<const unsigned short*>(data + 2 * x + y * inputPitch); - - outColor->red = (rg & 0xFF00) * (1.0f / 0xFF00); - outColor->green = (rg & 0x00FF) * (1.0f / 0x00FF); - outColor->blue = 0.0f; - outColor->alpha = 1.0f; - } - break; - - case DXGI_FORMAT_R16_FLOAT: - { - outColor->red = gl::float16ToFloat32(*reinterpret_cast<const unsigned short*>(data + 2 * x + y * inputPitch)); - outColor->green = 0.0f; - outColor->blue = 0.0f; - outColor->alpha = 1.0f; - } - break; - - case DXGI_FORMAT_R16G16_FLOAT: - { - outColor->red = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 4 * x + y * inputPitch) + 0)); - outColor->green = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 4 * x + y * inputPitch) + 1)); - outColor->blue = 0.0f; - outColor->alpha = 1.0f; - } - break; + return new TextureStorage11_2DArray(this, internalformat, renderTarget, width, height, depth, levels); +} - default: - ERR("ReadPixelColor not implemented for DXGI format %u.", format); - UNIMPLEMENTED(); - break; - } +Texture2DImpl *Renderer11::createTexture2D() +{ + return new TextureD3D_2D(this); } -static inline void writePixelColor(const gl::Color &color, GLenum format, GLenum type, unsigned int x, - unsigned int y, int outputPitch, void *outData) +TextureCubeImpl *Renderer11::createTextureCube() { - unsigned char* byteData = reinterpret_cast<unsigned char*>(outData); - unsigned short* shortData = reinterpret_cast<unsigned short*>(outData); + return new TextureD3D_Cube(this); +} - switch (format) - { - case GL_RGBA: - switch (type) - { - case GL_UNSIGNED_BYTE: - byteData[4 * x + y * outputPitch + 0] = static_cast<unsigned char>(255 * color.red + 0.5f); - byteData[4 * x + y * outputPitch + 1] = static_cast<unsigned char>(255 * color.green + 0.5f); - byteData[4 * x + y * outputPitch + 2] = static_cast<unsigned char>(255 * color.blue + 0.5f); - byteData[4 * x + y * outputPitch + 3] = static_cast<unsigned char>(255 * color.alpha + 0.5f); - break; +Texture3DImpl *Renderer11::createTexture3D() +{ + return new TextureD3D_3D(this); +} - default: - ERR("WritePixelColor not implemented for format GL_RGBA and type 0x%X.", type); - UNIMPLEMENTED(); - break; - } - break; +Texture2DArrayImpl *Renderer11::createTexture2DArray() +{ + return new TextureD3D_2DArray(this); +} - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: - byteData[4 * x + y * outputPitch + 0] = static_cast<unsigned char>(255 * color.blue + 0.5f); - byteData[4 * x + y * outputPitch + 1] = static_cast<unsigned char>(255 * color.green + 0.5f); - byteData[4 * x + y * outputPitch + 2] = static_cast<unsigned char>(255 * color.red + 0.5f); - byteData[4 * x + y * outputPitch + 3] = static_cast<unsigned char>(255 * color.alpha + 0.5f); - break; - - case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: - // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section - // this type is packed as follows: - // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - // -------------------------------------------------------------------------------- - // | 4th | 3rd | 2nd | 1st component | - // -------------------------------------------------------------------------------- - // in the case of BGRA_EXT, B is the first component, G the second, and so forth. - shortData[x + y * outputPitch / sizeof(unsigned short)] = - (static_cast<unsigned short>(15 * color.alpha + 0.5f) << 12) | - (static_cast<unsigned short>(15 * color.red + 0.5f) << 8) | - (static_cast<unsigned short>(15 * color.green + 0.5f) << 4) | - (static_cast<unsigned short>(15 * color.blue + 0.5f) << 0); - break; - - case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: - // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section - // this type is packed as follows: - // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - // -------------------------------------------------------------------------------- - // | 4th | 3rd | 2nd | 1st component | - // -------------------------------------------------------------------------------- - // in the case of BGRA_EXT, B is the first component, G the second, and so forth. - shortData[x + y * outputPitch / sizeof(unsigned short)] = - (static_cast<unsigned short>( color.alpha + 0.5f) << 15) | - (static_cast<unsigned short>(31 * color.red + 0.5f) << 10) | - (static_cast<unsigned short>(31 * color.green + 0.5f) << 5) | - (static_cast<unsigned short>(31 * color.blue + 0.5f) << 0); - break; - - default: - ERR("WritePixelColor not implemented for format GL_BGRA_EXT and type 0x%X.", type); - UNIMPLEMENTED(); - break; - } - break; +void Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void *pixels) +{ + ASSERT(area.width >= 0); + ASSERT(area.height >= 0); - case GL_RGB: - switch (type) - { - case GL_UNSIGNED_SHORT_5_6_5: - shortData[x + y * outputPitch / sizeof(unsigned short)] = - (static_cast<unsigned short>(31 * color.blue + 0.5f) << 0) | - (static_cast<unsigned short>(63 * color.green + 0.5f) << 5) | - (static_cast<unsigned short>(31 * color.red + 0.5f) << 11); - break; + D3D11_TEXTURE2D_DESC textureDesc; + texture->GetDesc(&textureDesc); - case GL_UNSIGNED_BYTE: - byteData[3 * x + y * outputPitch + 0] = static_cast<unsigned char>(255 * color.red + 0.5f); - byteData[3 * x + y * outputPitch + 1] = static_cast<unsigned char>(255 * color.green + 0.5f); - byteData[3 * x + y * outputPitch + 2] = static_cast<unsigned char>(255 * color.blue + 0.5f); - break; + // Clamp read region to the defined texture boundaries, preventing out of bounds reads + // and reads of uninitialized data. + gl::Rectangle safeArea; + safeArea.x = gl::clamp(area.x, 0, static_cast<int>(textureDesc.Width)); + safeArea.y = gl::clamp(area.y, 0, static_cast<int>(textureDesc.Height)); + safeArea.width = gl::clamp(area.width + std::min(area.x, 0), 0, + static_cast<int>(textureDesc.Width) - safeArea.x); + safeArea.height = gl::clamp(area.height + std::min(area.y, 0), 0, + static_cast<int>(textureDesc.Height) - safeArea.y); - default: - ERR("WritePixelColor not implemented for format GL_RGB and type 0x%X.", type); - UNIMPLEMENTED(); - break; - } - break; + ASSERT(safeArea.x >= 0 && safeArea.y >= 0); + ASSERT(safeArea.x + safeArea.width <= static_cast<int>(textureDesc.Width)); + ASSERT(safeArea.y + safeArea.height <= static_cast<int>(textureDesc.Height)); - default: - ERR("WritePixelColor not implemented for format 0x%X.", format); - UNIMPLEMENTED(); - break; + if (safeArea.width == 0 || safeArea.height == 0) + { + // no work to do + return; } -} - -void Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, - GLenum sourceFormat, GLenum format, GLenum type, GLsizei outputPitch, bool packReverseRowOrder, - GLint packAlignment, void *pixels) -{ - D3D11_TEXTURE2D_DESC textureDesc; - texture->GetDesc(&textureDesc); D3D11_TEXTURE2D_DESC stagingDesc; - stagingDesc.Width = area.width; - stagingDesc.Height = area.height; + stagingDesc.Width = safeArea.width; + stagingDesc.Height = safeArea.height; stagingDesc.MipLevels = 1; stagingDesc.ArraySize = 1; stagingDesc.Format = textureDesc.Format; @@ -3524,7 +3083,7 @@ void Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResou if (FAILED(result)) { ERR("Failed to create resolve texture for readPixels, HRESULT: 0x%X.", result); - stagingTex->Release(); + SafeRelease(stagingTex); return; } @@ -3538,26 +3097,38 @@ void Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResou } D3D11_BOX srcBox; - srcBox.left = area.x; - srcBox.right = area.x + area.width; - srcBox.top = area.y; - srcBox.bottom = area.y + area.height; - srcBox.front = 0; - srcBox.back = 1; + srcBox.left = static_cast<UINT>(safeArea.x); + srcBox.right = static_cast<UINT>(safeArea.x + safeArea.width); + srcBox.top = static_cast<UINT>(safeArea.y); + srcBox.bottom = static_cast<UINT>(safeArea.y + safeArea.height); + srcBox.front = 0; + srcBox.back = 1; mDeviceContext->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, srcTex, subResource, &srcBox); - srcTex->Release(); - srcTex = NULL; + SafeRelease(srcTex); + + PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); + packPixels(stagingTex, packParams, pixels); + + SafeRelease(stagingTex); +} + +void Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, void *pixelsOut) +{ + D3D11_TEXTURE2D_DESC textureDesc; + readTexture->GetDesc(&textureDesc); D3D11_MAPPED_SUBRESOURCE mapping; - mDeviceContext->Map(stagingTex, 0, D3D11_MAP_READ, 0, &mapping); + HRESULT hr = mDeviceContext->Map(readTexture, 0, D3D11_MAP_READ, 0, &mapping); + UNUSED_ASSERTION_VARIABLE(hr); + ASSERT(SUCCEEDED(hr)); unsigned char *source; int inputPitch; - if (packReverseRowOrder) + if (params.pack.reverseRowOrder) { - source = static_cast<unsigned char*>(mapping.pData) + mapping.RowPitch * (area.height - 1); + source = static_cast<unsigned char*>(mapping.pData) + mapping.RowPitch * (params.area.height - 1); inputPitch = -static_cast<int>(mapping.RowPitch); } else @@ -3566,57 +3137,79 @@ void Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResou inputPitch = static_cast<int>(mapping.RowPitch); } - unsigned int fastPixelSize = getFastPixelCopySize(textureDesc.Format, sourceFormat, format, type); - if (fastPixelSize != 0) + GLenum sourceInternalFormat = d3d11_gl::GetInternalFormat(textureDesc.Format); + GLenum sourceFormat = gl::GetFormat(sourceInternalFormat); + GLenum sourceType = gl::GetType(sourceInternalFormat); + + GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat); + + if (sourceFormat == params.format && sourceType == params.type) { - unsigned char *dest = static_cast<unsigned char*>(pixels); - for (int j = 0; j < area.height; j++) + unsigned char *dest = static_cast<unsigned char*>(pixelsOut) + params.offset; + for (int y = 0; y < params.area.height; y++) { - memcpy(dest + j * outputPitch, source + j * inputPitch, area.width * fastPixelSize); + memcpy(dest + y * params.outputPitch, source + y * inputPitch, params.area.width * sourcePixelSize); } } - else if (textureDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM && - format == GL_RGBA && - type == GL_UNSIGNED_BYTE) + else { - // Fast path for swapping red with blue - unsigned char *dest = static_cast<unsigned char*>(pixels); + GLenum destInternalFormat = gl::GetSizedInternalFormat(params.format, params.type); + GLuint destPixelSize = gl::GetPixelBytes(destInternalFormat); - for (int j = 0; j < area.height; j++) + ColorCopyFunction fastCopyFunc = d3d11::GetFastCopyFunction(textureDesc.Format, params.format, params.type); + if (fastCopyFunc) { - for (int i = 0; i < area.width; i++) + // Fast copy is possible through some special function + for (int y = 0; y < params.area.height; y++) { - unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); - *(unsigned int*)(dest + 4 * i + j * outputPitch) = - (argb & 0xFF00FF00) | // Keep alpha and green - (argb & 0x00FF0000) >> 16 | // Move red to blue - (argb & 0x000000FF) << 16; // Move blue to red + for (int x = 0; x < params.area.width; x++) + { + void *dest = static_cast<unsigned char*>(pixelsOut) + params.offset + y * params.outputPitch + x * destPixelSize; + void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize; + + fastCopyFunc(src, dest); + } } } - } - else - { - gl::Color pixelColor; - for (int j = 0; j < area.height; j++) + else { - for (int i = 0; i < area.width; i++) + ColorReadFunction readFunc = d3d11::GetColorReadFunction(textureDesc.Format); + ColorWriteFunction writeFunc = gl::GetColorWriteFunction(params.format, params.type); + + unsigned char temp[16]; // Maximum size of any Color<T> type used. + META_ASSERT(sizeof(temp) >= sizeof(gl::ColorF) && + sizeof(temp) >= sizeof(gl::ColorUI) && + sizeof(temp) >= sizeof(gl::ColorI)); + + for (int y = 0; y < params.area.height; y++) { - readPixelColor(source, textureDesc.Format, sourceFormat, i, j, inputPitch, &pixelColor); - writePixelColor(pixelColor, format, type, i, j, outputPitch, pixels); + for (int x = 0; x < params.area.width; x++) + { + void *dest = static_cast<unsigned char*>(pixelsOut) + params.offset + y * params.outputPitch + x * destPixelSize; + void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize; + + // readFunc and writeFunc will be using the same type of color, CopyTexImage + // will not allow the copy otherwise. + readFunc(src, temp); + writeFunc(temp, dest); + } } } } - mDeviceContext->Unmap(stagingTex, 0); - - stagingTex->Release(); - stagingTex = NULL; + mDeviceContext->Unmap(readTexture, 0); } -bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, - RenderTarget *drawRenderTarget, bool wholeBufferCopy) +bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, + RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, + bool colorBlit, bool depthBlit, bool stencilBlit) { - ASSERT(readRect.width == drawRect.width && readRect.height == drawRect.height); + // Since blitRenderbufferRect is called for each render buffer that needs to be blitted, + // it should never be the case that both color and depth/stencil need to be blitted at + // at the same time. + ASSERT(colorBlit != (depthBlit || stencilBlit)); + + bool result = true; RenderTarget11 *drawRenderTarget11 = RenderTarget11::makeRenderTarget11(drawRenderTarget); if (!drawRenderTarget) @@ -3625,8 +3218,10 @@ bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::R return gl::error(GL_OUT_OF_MEMORY, false); } - ID3D11Texture2D *drawTexture = drawRenderTarget11->getTexture(); + ID3D11Resource *drawTexture = drawRenderTarget11->getTexture(); unsigned int drawSubresource = drawRenderTarget11->getSubresourceIndex(); + ID3D11RenderTargetView *drawRTV = drawRenderTarget11->getRenderTargetView(); + ID3D11DepthStencilView *drawDSV = drawRenderTarget11->getDepthStencilView(); RenderTarget11 *readRenderTarget11 = RenderTarget11::makeRenderTarget11(readRenderTarget); if (!readRenderTarget) @@ -3635,44 +3230,152 @@ bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::R return gl::error(GL_OUT_OF_MEMORY, false); } - ID3D11Texture2D *readTexture = NULL; + ID3D11Resource *readTexture = NULL; + ID3D11ShaderResourceView *readSRV = NULL; unsigned int readSubresource = 0; if (readRenderTarget->getSamples() > 0) { - readTexture = resolveMultisampledTexture(readRenderTarget11->getTexture(), readRenderTarget11->getSubresourceIndex()); - readSubresource = 0; + ID3D11Resource *unresolvedResource = readRenderTarget11->getTexture(); + ID3D11Texture2D *unresolvedTexture = d3d11::DynamicCastComObject<ID3D11Texture2D>(unresolvedResource); + + if (unresolvedTexture) + { + readTexture = resolveMultisampledTexture(unresolvedTexture, readRenderTarget11->getSubresourceIndex()); + readSubresource = 0; + + SafeRelease(unresolvedTexture); + + HRESULT hresult = mDevice->CreateShaderResourceView(readTexture, NULL, &readSRV); + if (FAILED(hresult)) + { + SafeRelease(readTexture); + return gl::error(GL_OUT_OF_MEMORY, false); + } + } } else { readTexture = readRenderTarget11->getTexture(); readTexture->AddRef(); readSubresource = readRenderTarget11->getSubresourceIndex(); + readSRV = readRenderTarget11->getShaderResourceView(); + readSRV->AddRef(); } - if (!readTexture) + if (!readTexture || !readSRV) { + SafeRelease(readTexture); + SafeRelease(readSRV); ERR("Failed to retrieve the read render target view from the read render target."); return gl::error(GL_OUT_OF_MEMORY, false); } - D3D11_BOX readBox; - readBox.left = readRect.x; - readBox.right = readRect.x + readRect.width; - readBox.top = readRect.y; - readBox.bottom = readRect.y + readRect.height; - readBox.front = 0; - readBox.back = 1; + gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); + gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + + bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, NULL); + + bool wholeBufferCopy = !scissorNeeded && + readRect.x == 0 && readRect.width == readSize.width && + readRect.y == 0 && readRect.height == readSize.height && + drawRect.x == 0 && drawRect.width == drawSize.width && + drawRect.y == 0 && drawRect.height == drawSize.height; + + bool stretchRequired = readRect.width != drawRect.width || readRect.height != drawRect.height; - // D3D11 needs depth-stencil CopySubresourceRegions to have a NULL pSrcBox - // We also require complete framebuffer copies for depth-stencil blit. - D3D11_BOX *pSrcBox = wholeBufferCopy ? NULL : &readBox; + bool flipRequired = readRect.width < 0 || readRect.height < 0 || drawRect.width < 0 || drawRect.height < 0; - mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, drawRect.x, drawRect.y, 0, - readTexture, readSubresource, pSrcBox); + bool outOfBounds = readRect.x < 0 || readRect.x + readRect.width > readSize.width || + readRect.y < 0 || readRect.y + readRect.height > readSize.height || + drawRect.x < 0 || drawRect.x + drawRect.width > drawSize.width || + drawRect.y < 0 || drawRect.y + drawRect.height > drawSize.height; + + bool hasDepth = gl::GetDepthBits(drawRenderTarget11->getActualFormat()) > 0; + bool hasStencil = gl::GetStencilBits(drawRenderTarget11->getActualFormat()) > 0; + bool partialDSBlit = (hasDepth && depthBlit) != (hasStencil && stencilBlit); + + if (readRenderTarget11->getActualFormat() == drawRenderTarget->getActualFormat() && + !stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit && + (!(depthBlit || stencilBlit) || wholeBufferCopy)) + { + UINT dstX = drawRect.x; + UINT dstY = drawRect.y; + + D3D11_BOX readBox; + readBox.left = readRect.x; + readBox.right = readRect.x + readRect.width; + readBox.top = readRect.y; + readBox.bottom = readRect.y + readRect.height; + readBox.front = 0; + readBox.back = 1; + + if (scissorNeeded) + { + // drawRect is guaranteed to have positive width and height because stretchRequired is false. + ASSERT(drawRect.width >= 0 || drawRect.height >= 0); + + if (drawRect.x < scissor->x) + { + dstX = scissor->x; + readBox.left += (scissor->x - drawRect.x); + } + if (drawRect.y < scissor->y) + { + dstY = scissor->y; + readBox.top += (scissor->y - drawRect.y); + } + if (drawRect.x + drawRect.width > scissor->x + scissor->width) + { + readBox.right -= ((drawRect.x + drawRect.width) - (scissor->x + scissor->width)); + } + if (drawRect.y + drawRect.height > scissor->y + scissor->height) + { + readBox.bottom -= ((drawRect.y + drawRect.height) - (scissor->y + scissor->height)); + } + } + + // D3D11 needs depth-stencil CopySubresourceRegions to have a NULL pSrcBox + // We also require complete framebuffer copies for depth-stencil blit. + D3D11_BOX *pSrcBox = wholeBufferCopy ? NULL : &readBox; + + mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, dstX, dstY, 0, + readTexture, readSubresource, pSrcBox); + result = true; + } + else + { + gl::Box readArea(readRect.x, readRect.y, 0, readRect.width, readRect.height, 1); + gl::Box drawArea(drawRect.x, drawRect.y, 0, drawRect.width, drawRect.height, 1); + + if (depthBlit && stencilBlit) + { + result = mBlit->copyDepthStencil(readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor); + } + else if (depthBlit) + { + result = mBlit->copyDepth(readSRV, readArea, readSize, drawDSV, drawArea, drawSize, + scissor); + } + else if (stencilBlit) + { + result = mBlit->copyStencil(readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor); + } + else + { + GLenum format = gl::GetFormat(drawRenderTarget->getInternalFormat()); + result = mBlit->copyTexture(readSRV, readArea, readSize, drawRTV, drawArea, drawSize, + scissor, format, filter); + } + } SafeRelease(readTexture); + SafeRelease(readSRV); - return true; + return result; } ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource) @@ -3713,6 +3416,47 @@ ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, } } +void Renderer11::invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *attachment, int mipLevel) +{ + ASSERT(attachment->isTexture()); + TextureStorage *texStorage = attachment->getTextureStorage(); + if (texStorage) + { + TextureStorage11 *texStorage11 = TextureStorage11::makeTextureStorage11(texStorage); + if (!texStorage11) + { + ERR("texture storage pointer unexpectedly null."); + return; + } + + texStorage11->invalidateSwizzleCacheLevel(mipLevel); + } +} + +void Renderer11::invalidateFramebufferSwizzles(gl::Framebuffer *framebuffer) +{ + for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) + { + gl::FramebufferAttachment *attachment = framebuffer->getColorbuffer(colorAttachment); + if (attachment && attachment->isTexture()) + { + invalidateFBOAttachmentSwizzles(attachment, attachment->mipLevel()); + } + } + + gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthbuffer(); + if (depthAttachment && depthAttachment->isTexture()) + { + invalidateFBOAttachmentSwizzles(depthAttachment, depthAttachment->mipLevel()); + } + + gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilbuffer(); + if (stencilAttachment && stencilAttachment->isTexture()) + { + invalidateFBOAttachmentSwizzles(stencilAttachment, stencilAttachment->mipLevel()); + } +} + bool Renderer11::getLUID(LUID *adapterLuid) const { adapterLuid->HighPart = 0; @@ -3733,4 +3477,51 @@ bool Renderer11::getLUID(LUID *adapterLuid) const return true; } +GLenum Renderer11::getNativeTextureFormat(GLenum internalFormat) const +{ + return d3d11_gl::GetInternalFormat(gl_d3d11::GetTexFormat(internalFormat)); +} + +rx::VertexConversionType Renderer11::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +{ + return gl_d3d11::GetVertexConversionType(vertexFormat); +} + +GLenum Renderer11::getVertexComponentType(const gl::VertexFormat &vertexFormat) const +{ + return d3d11::GetComponentType(gl_d3d11::GetNativeVertexFormat(vertexFormat)); +} + +Renderer11::MultisampleSupportInfo Renderer11::getMultisampleSupportInfo(DXGI_FORMAT format) +{ + MultisampleSupportInfo supportInfo = { 0 }; + + UINT formatSupport; + HRESULT result; + + result = mDevice->CheckFormatSupport(format, &formatSupport); + if (SUCCEEDED(result) && (formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET)) + { + for (unsigned int i = 1; i <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; i++) + { + result = mDevice->CheckMultisampleQualityLevels(format, i, &supportInfo.qualityLevels[i - 1]); + if (SUCCEEDED(result) && supportInfo.qualityLevels[i - 1] > 0) + { + supportInfo.maxSupportedSamples = std::max(supportInfo.maxSupportedSamples, i); + } + else + { + supportInfo.qualityLevels[i - 1] = 0; + } + } + } + + return supportInfo; +} + +void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const +{ + d3d11_gl::GenerateCaps(mDevice, outCaps, outTextureCaps, outExtensions); +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h index 773fc26db1..a31f15ee64 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -11,27 +11,17 @@ #include "common/angleutils.h" #include "libGLESv2/angletypes.h" -#include "libGLESv2/mathutil.h" +#include "common/mathutil.h" #include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/d3d11/RenderStateCache.h" -#include "libGLESv2/renderer/d3d11/InputLayoutCache.h" +#include "libGLESv2/renderer/d3d/HLSLCompiler.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderStateCache.h" +#include "libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h" #include "libGLESv2/renderer/RenderTarget.h" -#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) -struct IInspectable; -namespace ABI { - namespace Windows { - namespace ApplicationModel { - struct ISuspendingEventArgs; - } - } -} -#endif - namespace gl { -class Renderbuffer; +class FramebufferAttachment; } namespace rx @@ -40,6 +30,10 @@ namespace rx class VertexDataManager; class IndexDataManager; class StreamingIndexBufferInterface; +class Blit11; +class Clear11; +class PixelTransfer11; +struct PackPixelsParams; enum { @@ -50,7 +44,7 @@ enum class Renderer11 : public Renderer { public: - Renderer11(egl::Display *display); + Renderer11(egl::Display *display, EGLNativeDisplayType hDc, EGLint requestedDisplay); virtual ~Renderer11(); static Renderer11 *makeRenderer11(Renderer *renderer); @@ -65,11 +59,14 @@ class Renderer11 : public Renderer virtual SwapChain *createSwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); + virtual void generateSwizzle(gl::Texture *texture); virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler); virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture); + virtual bool setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]); + virtual void setRasterizerState(const gl::RasterizerState &rasterState); - virtual void setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::Color &blendColor, + virtual void setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, unsigned int sampleMask); virtual void setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, int stencilBackRef, bool frontFaceCCW); @@ -80,13 +77,17 @@ class Renderer11 : public Renderer virtual bool applyPrimitiveType(GLenum mode, GLsizei count); virtual bool applyRenderTarget(gl::Framebuffer *frameBuffer); - virtual void applyShaders(gl::ProgramBinary *programBinary); - virtual void applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray); - virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances); + virtual void applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive); + virtual void applyUniforms(const gl::ProgramBinary &programBinary); + virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], + GLint first, GLsizei count, GLsizei instances); virtual GLenum applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); + virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]); - virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances); - virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); + virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive); + virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); virtual void clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); @@ -98,20 +99,10 @@ class Renderer11 : public Renderer virtual bool testDeviceLost(bool notify); virtual bool testDeviceResettable(); - // Renderer capabilities virtual DWORD getAdapterVendor() const; virtual std::string getRendererDescription() const; virtual GUID getAdapterIdentifier() const; - virtual bool getBGRATextureSupport() const; - virtual bool getDXT1TextureSupport(); - virtual bool getDXT3TextureSupport(); - virtual bool getDXT5TextureSupport(); - virtual bool getEventQuerySupport(); - virtual bool getFloat32TextureSupport(bool *filtering, bool *renderable); - virtual bool getFloat16TextureSupport(bool *filtering, bool *renderable); - virtual bool getLuminanceTextureSupport(); - virtual bool getLuminanceAlphaTextureSupport(); virtual unsigned int getMaxVertexTextureImageUnits() const; virtual unsigned int getMaxCombinedTextureImageUnits() const; virtual unsigned int getReservedVertexUniformVectors() const; @@ -119,66 +110,86 @@ class Renderer11 : public Renderer virtual unsigned int getMaxVertexUniformVectors() const; virtual unsigned int getMaxFragmentUniformVectors() const; virtual unsigned int getMaxVaryingVectors() const; - virtual bool getNonPower2TextureSupport() const; - virtual bool getDepthTextureSupport() const; - virtual bool getOcclusionQuerySupport() const; - virtual bool getInstancingSupport() const; - virtual bool getTextureFilterAnisotropySupport() const; - virtual float getTextureMaxAnisotropy() const; + virtual unsigned int getMaxVertexShaderUniformBuffers() const; + virtual unsigned int getMaxFragmentShaderUniformBuffers() const; + virtual unsigned int getReservedVertexUniformBuffers() const; + virtual unsigned int getReservedFragmentUniformBuffers() const; + unsigned int getReservedVaryings() const; + virtual unsigned int getMaxTransformFeedbackBuffers() const; + virtual unsigned int getMaxTransformFeedbackSeparateComponents() const; + virtual unsigned int getMaxTransformFeedbackInterleavedComponents() const; + virtual unsigned int getMaxUniformBufferSize() const; virtual bool getShareHandleSupport() const; - virtual bool getDerivativeInstructionSupport() const; virtual bool getPostSubBufferSupport() const; + virtual int getMaxRecommendedElementsIndices() const; + virtual int getMaxRecommendedElementsVertices() const; + virtual bool getSRGBTextureSupport() const; virtual int getMajorShaderModel() const; - virtual float getMaxPointSize() const; - virtual int getMaxViewportDimension() const; - virtual int getMaxTextureWidth() const; - virtual int getMaxTextureHeight() const; - virtual bool get32BitIndexSupport() const; virtual int getMinSwapInterval() const; virtual int getMaxSwapInterval() const; virtual GLsizei getMaxSupportedSamples() const; + virtual GLsizei getMaxSupportedFormatSamples(GLenum internalFormat) const; + virtual GLsizei getNumSampleCounts(GLenum internalFormat) const; + virtual void getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const; int getNearestSupportedSamples(DXGI_FORMAT format, unsigned int requested) const; - virtual unsigned int getMaxRenderTargets() const; - // Pixel operations virtual bool copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source); virtual bool copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source); + virtual bool copyToRenderTarget(TextureStorageInterface3D *dest, TextureStorageInterface3D *source); + virtual bool copyToRenderTarget(TextureStorageInterface2DArray *dest, TextureStorageInterface2DArray *source); virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level); virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level); - - bool copyTexture(ID3D11ShaderResourceView *source, const gl::Rectangle &sourceArea, unsigned int sourceWidth, unsigned int sourceHeight, - ID3D11RenderTargetView *dest, const gl::Rectangle &destArea, unsigned int destWidth, unsigned int destHeight, GLenum destFormat); + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface3D *storage, GLint level); + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level); virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - bool blitRenderTarget, bool blitDepthStencil); - virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, - GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels); + const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter); + virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void* pixels); // RenderTarget creation virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth); - virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth); + virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples); // Shader operations - virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type); - virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, D3DWorkaroundType workaround); + virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers); + virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround); + virtual UniformStorage *createUniformStorage(size_t storageSize); // Image operations virtual Image *createImage(); virtual void generateMipmap(Image *dest, Image *source); virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain); - virtual TextureStorage *createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height); - virtual TextureStorage *createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size); + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels); + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + + // Texture creation + virtual Texture2DImpl *createTexture2D(); + virtual TextureCubeImpl *createTextureCube(); + virtual Texture3DImpl *createTexture3D(); + virtual Texture2DArrayImpl *createTexture2DArray(); // Buffer creation + virtual BufferImpl *createBuffer(); virtual VertexBuffer *createVertexBuffer(); virtual IndexBuffer *createIndexBuffer(); - virtual BufferStorage *createBufferStorage(); + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray(); // Query and Fence creation virtual QueryImpl *createQuery(GLenum type); @@ -188,37 +199,50 @@ class Renderer11 : public Renderer ID3D11Device *getDevice() { return mDevice; } ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; }; IDXGIFactory *getDxgiFactory() { return mDxgiFactory; }; - D3D_FEATURE_LEVEL getFeatureLevel() { return mFeatureLevel; } + bool isLevel9() { return mFeatureLevel <= D3D_FEATURE_LEVEL_9_3; } + + Blit11 *getBlitter() { return mBlit; } - bool getRenderTargetResource(gl::Renderbuffer *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource); + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; + virtual bool fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + bool getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource); void unapplyRenderTargets(); void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView); + void packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, void *pixelsOut); virtual bool getLUID(LUID *adapterLuid) const; + virtual GLenum getNativeTextureFormat(GLenum internalFormat) const; + virtual rx::VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; private: DISALLOW_COPY_AND_ASSIGN(Renderer11); + virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const; + void drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); void drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances); - void readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, - GLenum sourceFormat, GLenum format, GLenum type, GLsizei outputPitch, bool packReverseRowOrder, - GLint packAlignment, void *pixels); - - void maskedClear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); - rx::Range getViewportBounds() const; + void readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void *pixels); - bool blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, - RenderTarget *drawRenderTarget, bool wholeBufferCopy); + bool blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, + RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, + bool colorBlit, bool depthBlit, bool stencilBlit); ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource); -#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) - HRESULT onSuspend(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); -#endif + static void invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *attachment, int mipLevel); + static void invalidateFramebufferSwizzles(gl::Framebuffer *framebuffer); HMODULE mD3d11Module; HMODULE mDxgiModule; + EGLNativeDisplayType mDc; + EGLint mRequestedDisplay; + + HLSLCompiler mCompiler; bool mDeviceLost; @@ -229,28 +253,15 @@ class Renderer11 : public Renderer RenderStateCache mStateCache; - // Support flags - bool mFloat16TextureSupport; - bool mFloat16FilterSupport; - bool mFloat16RenderSupport; - - bool mFloat32TextureSupport; - bool mFloat32FilterSupport; - bool mFloat32RenderSupport; - - bool mDXT1TextureSupport; - bool mDXT3TextureSupport; - bool mDXT5TextureSupport; - - bool mDepthTextureSupport; - // Multisample format support struct MultisampleSupportInfo { unsigned int qualityLevels[D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT]; + unsigned int maxSupportedSamples; }; + MultisampleSupportInfo getMultisampleSupportInfo(DXGI_FORMAT format); - typedef std::unordered_map<DXGI_FORMAT, MultisampleSupportInfo, std::hash<int> > MultisampleSupportMap; + typedef std::unordered_map<DXGI_FORMAT, MultisampleSupportInfo> MultisampleSupportMap; MultisampleSupportMap mMultisampleSupportMap; unsigned int mMaxSupportedSamples; @@ -262,8 +273,6 @@ class Renderer11 : public Renderer bool mDepthStencilInitialized; bool mRenderTargetDescInitialized; rx::RenderTarget::Desc mRenderTargetDesc; - unsigned int mCurDepthSize; - unsigned int mCurStencilSize; // Currently applied sampler states bool mForceSetVertexSamplerStates[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; @@ -273,13 +282,13 @@ class Renderer11 : public Renderer gl::SamplerState mCurPixelSamplerStates[gl::MAX_TEXTURE_IMAGE_UNITS]; // Currently applied textures - unsigned int mCurVertexTextureSerials[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; - unsigned int mCurPixelTextureSerials[gl::MAX_TEXTURE_IMAGE_UNITS]; + ID3D11ShaderResourceView *mCurVertexSRVs[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; + ID3D11ShaderResourceView *mCurPixelSRVs[gl::MAX_TEXTURE_IMAGE_UNITS]; // Currently applied blend state bool mForceSetBlendState; gl::BlendState mCurBlendState; - gl::Color mCurBlendColor; + gl::ColorF mCurBlendColor; unsigned int mCurSampleMask; // Currently applied rasterizer state @@ -306,22 +315,32 @@ class Renderer11 : public Renderer // Currently applied primitive topology D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology; - unsigned int mAppliedIBSerial; - unsigned int mAppliedStorageIBSerial; + // Currently applied index buffer + ID3D11Buffer *mAppliedIB; + DXGI_FORMAT mAppliedIBFormat; unsigned int mAppliedIBOffset; - unsigned int mAppliedProgramBinarySerial; - bool mIsGeometryShaderActive; + // Currently applied transform feedback buffers + ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + + // Currently applied shaders + ID3D11VertexShader *mAppliedVertexShader; + ID3D11GeometryShader *mAppliedGeometryShader; + ID3D11GeometryShader *mCurPointGeometryShader; + ID3D11PixelShader *mAppliedPixelShader; dx_VertexConstants mVertexConstants; dx_VertexConstants mAppliedVertexConstants; ID3D11Buffer *mDriverConstantBufferVS; ID3D11Buffer *mCurrentVertexConstantBuffer; + unsigned int mCurrentConstantBufferVS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; dx_PixelConstants mPixelConstants; dx_PixelConstants mAppliedPixelConstants; ID3D11Buffer *mDriverConstantBufferPS; ID3D11Buffer *mCurrentPixelConstantBuffer; + unsigned int mCurrentConstantBufferPS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; ID3D11Buffer *mCurrentGeometryConstantBuffer; @@ -334,25 +353,11 @@ class Renderer11 : public Renderer StreamingIndexBufferInterface *mTriangleFanIB; // Texture copy resources - bool mCopyResourcesInitialized; - ID3D11Buffer *mCopyVB; - ID3D11SamplerState *mCopySampler; - ID3D11InputLayout *mCopyIL; - ID3D11VertexShader *mCopyVS; - ID3D11PixelShader *mCopyRGBAPS; - ID3D11PixelShader *mCopyRGBPS; - ID3D11PixelShader *mCopyLumPS; - ID3D11PixelShader *mCopyLumAlphaPS; + Blit11 *mBlit; + PixelTransfer11 *mPixelTransfer; // Masked clear resources - bool mClearResourcesInitialized; - ID3D11Buffer *mClearVB; - ID3D11InputLayout *mClearIL; - ID3D11VertexShader *mClearVS; - ID3D11PixelShader *mClearSinglePS; - ID3D11PixelShader *mClearMultiplePS; - ID3D11RasterizerState *mClearScissorRS; - ID3D11RasterizerState *mClearNoScissorRS; + Clear11 *mClear; // Sync query ID3D11Query *mSyncQuery; @@ -364,9 +369,6 @@ class Renderer11 : public Renderer DXGI_ADAPTER_DESC mAdapterDescription; char mDescription[128]; IDXGIFactory *mDxgiFactory; - - // Cached device caps - bool mBGRATextureSupport; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/ShaderExecutable11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.cpp index 2e455e3af5..5a7c987494 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/ShaderExecutable11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -8,9 +8,9 @@ // ShaderExecutable11.cpp: Implements a D3D11-specific class to contain shader // executable implementation details. -#include "libGLESv2/renderer/d3d11/ShaderExecutable11.h" +#include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h" -#include "common/debug.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" namespace rx { @@ -21,18 +21,16 @@ ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D mPixelExecutable = executable; mVertexExecutable = NULL; mGeometryExecutable = NULL; - - mConstantBuffer = NULL; + mStreamOutExecutable = NULL; } -ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable) +ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut) : ShaderExecutable(function, length) { mVertexExecutable = executable; mPixelExecutable = NULL; mGeometryExecutable = NULL; - - mConstantBuffer = NULL; + mStreamOutExecutable = streamOut; } ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable) @@ -41,29 +39,15 @@ ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D mGeometryExecutable = executable; mVertexExecutable = NULL; mPixelExecutable = NULL; - - mConstantBuffer = NULL; + mStreamOutExecutable = NULL; } ShaderExecutable11::~ShaderExecutable11() { - if (mVertexExecutable) - { - mVertexExecutable->Release(); - } - if (mPixelExecutable) - { - mPixelExecutable->Release(); - } - if (mGeometryExecutable) - { - mGeometryExecutable->Release(); - } - - if (mConstantBuffer) - { - mConstantBuffer->Release(); - } + SafeRelease(mVertexExecutable); + SafeRelease(mPixelExecutable); + SafeRelease(mGeometryExecutable); + SafeRelease(mStreamOutExecutable); } ShaderExecutable11 *ShaderExecutable11::makeShaderExecutable11(ShaderExecutable *executable) @@ -87,23 +71,42 @@ ID3D11GeometryShader *ShaderExecutable11::getGeometryShader() const return mGeometryExecutable; } -ID3D11Buffer *ShaderExecutable11::getConstantBuffer(ID3D11Device *device, unsigned int registerCount) +ID3D11GeometryShader *ShaderExecutable11::getStreamOutShader() const { - if (!mConstantBuffer && registerCount > 0) + return mStreamOutExecutable; +} + +UniformStorage11::UniformStorage11(Renderer11 *renderer, size_t initialSize) + : UniformStorage(initialSize), + mConstantBuffer(NULL) +{ + ID3D11Device *d3d11Device = renderer->getDevice(); + + if (initialSize > 0) { D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = registerCount * sizeof(float[4]); + constantBufferDescription.ByteWidth = initialSize; constantBufferDescription.Usage = D3D11_USAGE_DYNAMIC; constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; constantBufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; constantBufferDescription.MiscFlags = 0; constantBufferDescription.StructureByteStride = 0; - HRESULT result = device->CreateBuffer(&constantBufferDescription, NULL, &mConstantBuffer); + HRESULT result = d3d11Device->CreateBuffer(&constantBufferDescription, NULL, &mConstantBuffer); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); } +} - return mConstantBuffer; +UniformStorage11::~UniformStorage11() +{ + SafeRelease(mConstantBuffer); } -}
\ No newline at end of file +const UniformStorage11 *UniformStorage11::makeUniformStorage11(const UniformStorage *uniformStorage) +{ + ASSERT(HAS_DYNAMIC_TYPE(const UniformStorage11*, uniformStorage)); + return static_cast<const UniformStorage11*>(uniformStorage); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/ShaderExecutable11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h index c6ec1cf7d2..74a1e03915 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/ShaderExecutable11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -14,12 +14,14 @@ namespace rx { +class Renderer11; +class UniformStorage11; class ShaderExecutable11 : public ShaderExecutable { public: ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable); - ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable); + ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut); ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable); virtual ~ShaderExecutable11(); @@ -29,8 +31,7 @@ class ShaderExecutable11 : public ShaderExecutable ID3D11PixelShader *getPixelShader() const; ID3D11VertexShader *getVertexShader() const; ID3D11GeometryShader *getGeometryShader() const; - - ID3D11Buffer *getConstantBuffer(ID3D11Device *device, unsigned int registerCount); + ID3D11GeometryShader *getStreamOutShader() const; private: DISALLOW_COPY_AND_ASSIGN(ShaderExecutable11); @@ -38,7 +39,20 @@ class ShaderExecutable11 : public ShaderExecutable ID3D11PixelShader *mPixelExecutable; ID3D11VertexShader *mVertexExecutable; ID3D11GeometryShader *mGeometryExecutable; + ID3D11GeometryShader *mStreamOutExecutable; +}; + +class UniformStorage11 : public UniformStorage +{ + public: + UniformStorage11(Renderer11 *renderer, size_t initialSize); + virtual ~UniformStorage11(); + + static const UniformStorage11 *makeUniformStorage11(const UniformStorage *uniformStorage); + ID3D11Buffer *getConstantBuffer() const { return mConstantBuffer; } + + private: ID3D11Buffer *mConstantBuffer; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp index bd97d5cff5..0341df10f9 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/SwapChain11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp @@ -1,19 +1,20 @@ #include "precompiled.h" // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // SwapChain11.cpp: Implements a back-end specific class for the D3D11 swap chain. -#include "libGLESv2/renderer/d3d11/SwapChain11.h" +#include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" -#include "libGLESv2/renderer/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/d3d11/Renderer11.h" - -#include "libGLESv2/renderer/d3d11/shaders/compiled/passthrough11vs.h" -#include "libGLESv2/renderer/d3d11/shaders/compiled/passthroughrgba11ps.h" +#include "common/platform.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2dvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dps.h" namespace rx { @@ -30,6 +31,7 @@ SwapChain11::SwapChain11(Renderer11 *renderer, EGLNativeWindowType window, HANDL mOffscreenSRView = NULL; mDepthStencilTexture = NULL; mDepthStencilDSView = NULL; + mDepthStencilSRView = NULL; mQuadVB = NULL; mPassThroughSampler = NULL; mPassThroughIL = NULL; @@ -37,6 +39,8 @@ SwapChain11::SwapChain11(Renderer11 *renderer, EGLNativeWindowType window, HANDL mPassThroughPS = NULL; mWidth = -1; mHeight = -1; + mViewportWidth = -1; + mViewportHeight = -1; mSwapInterval = 0; mAppCreatedShareHandle = mShareHandle != NULL; mPassThroughResourcesInit = false; @@ -57,6 +61,7 @@ void SwapChain11::release() SafeRelease(mOffscreenSRView); SafeRelease(mDepthStencilTexture); SafeRelease(mDepthStencilDSView); + SafeRelease(mDepthStencilSRView); SafeRelease(mQuadVB); SafeRelease(mPassThroughSampler); SafeRelease(mPassThroughIL); @@ -76,6 +81,7 @@ void SwapChain11::releaseOffscreenTexture() SafeRelease(mOffscreenSRView); SafeRelease(mDepthStencilTexture); SafeRelease(mDepthStencilDSView); + SafeRelease(mDepthStencilSRView); } EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHeight) @@ -88,6 +94,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei ASSERT(backbufferWidth >= 1); ASSERT(backbufferHeight >= 1); +#if !defined(ANGLE_PLATFORM_WINRT) // Preserve the render target content ID3D11Texture2D *previousOffscreenTexture = mOffscreenTexture; if (previousOffscreenTexture) @@ -96,6 +103,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei } const int previousWidth = mWidth; const int previousHeight = mHeight; +#endif releaseOffscreenTexture(); @@ -114,7 +122,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei } result = tempResource11->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&mOffscreenTexture); - tempResource11->Release(); + SafeRelease(tempResource11); if (FAILED(result)) { @@ -129,7 +137,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei if (offscreenTextureDesc.Width != (UINT)backbufferWidth || offscreenTextureDesc.Height != (UINT)backbufferHeight - || offscreenTextureDesc.Format != gl_d3d11::ConvertRenderbufferFormat(mBackBufferFormat) + || offscreenTextureDesc.Format != gl_d3d11::GetTexFormat(mBackBufferFormat) || offscreenTextureDesc.MipLevels != 1 || offscreenTextureDesc.ArraySize != 1) { @@ -145,7 +153,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; offscreenTextureDesc.Width = backbufferWidth; offscreenTextureDesc.Height = backbufferHeight; - offscreenTextureDesc.Format = gl_d3d11::ConvertRenderbufferFormat(mBackBufferFormat); + offscreenTextureDesc.Format = gl_d3d11::GetTexFormat(mBackBufferFormat); offscreenTextureDesc.MipLevels = 1; offscreenTextureDesc.ArraySize = 1; offscreenTextureDesc.SampleDesc.Count = 1; @@ -172,7 +180,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei } } - d3d11::SetDebugName(mOffscreenTexture, "Offscreen texture"); + d3d11::SetDebugName(mOffscreenTexture, "Offscreen back buffer texture"); // EGL_ANGLE_surface_d3d_texture_2d_share_handle requires that we store a share handle for the client if (useSharedResource) @@ -188,7 +196,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei else { result = offscreenTextureResource->GetSharedHandle(&mShareHandle); - offscreenTextureResource->Release(); + SafeRelease(offscreenTextureResource); if (FAILED(result)) { @@ -198,32 +206,43 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei } } } - - HRESULT result = device->CreateRenderTargetView(mOffscreenTexture, NULL, &mOffscreenRTView); + + D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc; + offscreenRTVDesc.Format = gl_d3d11::GetRTVFormat(mBackBufferFormat); + offscreenRTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + offscreenRTVDesc.Texture2D.MipSlice = 0; + + HRESULT result = device->CreateRenderTargetView(mOffscreenTexture, &offscreenRTVDesc, &mOffscreenRTView); ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mOffscreenRTView, "Offscreen render target"); + d3d11::SetDebugName(mOffscreenRTView, "Offscreen back buffer render target"); + + D3D11_SHADER_RESOURCE_VIEW_DESC offscreenSRVDesc; + offscreenSRVDesc.Format = gl_d3d11::GetSRVFormat(mBackBufferFormat); + offscreenSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + offscreenSRVDesc.Texture2D.MostDetailedMip = 0; + offscreenSRVDesc.Texture2D.MipLevels = -1; - result = device->CreateShaderResourceView(mOffscreenTexture, NULL, &mOffscreenSRView); + result = device->CreateShaderResourceView(mOffscreenTexture, &offscreenSRVDesc, &mOffscreenSRView); ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mOffscreenSRView, "Offscreen shader resource"); + d3d11::SetDebugName(mOffscreenSRView, "Offscreen back buffer shader resource"); if (mDepthBufferFormat != GL_NONE) { - D3D11_TEXTURE2D_DESC depthStencilDesc = {0}; - depthStencilDesc.Width = backbufferWidth; - depthStencilDesc.Height = backbufferHeight; - depthStencilDesc.Format = gl_d3d11::ConvertRenderbufferFormat(mDepthBufferFormat); - depthStencilDesc.MipLevels = 1; - depthStencilDesc.ArraySize = 1; - depthStencilDesc.SampleDesc.Count = 1; - depthStencilDesc.SampleDesc.Quality = 0; - depthStencilDesc.Usage = D3D11_USAGE_DEFAULT; - depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - depthStencilDesc.CPUAccessFlags = 0; - depthStencilDesc.MiscFlags = 0; - - result = device->CreateTexture2D(&depthStencilDesc, NULL, &mDepthStencilTexture); + D3D11_TEXTURE2D_DESC depthStencilTextureDesc; + depthStencilTextureDesc.Width = backbufferWidth; + depthStencilTextureDesc.Height = backbufferHeight; + depthStencilTextureDesc.Format = gl_d3d11::GetTexFormat(mDepthBufferFormat); + depthStencilTextureDesc.MipLevels = 1; + depthStencilTextureDesc.ArraySize = 1; + depthStencilTextureDesc.SampleDesc.Count = 1; + depthStencilTextureDesc.SampleDesc.Quality = 0; + depthStencilTextureDesc.Usage = D3D11_USAGE_DEFAULT; + depthStencilTextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; + depthStencilTextureDesc.CPUAccessFlags = 0; + depthStencilTextureDesc.MiscFlags = 0; + + result = device->CreateTexture2D(&depthStencilTextureDesc, NULL, &mDepthStencilTexture); if (FAILED(result)) { ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); @@ -238,16 +257,37 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei return EGL_BAD_ALLOC; } } - d3d11::SetDebugName(mDepthStencilTexture, "Depth stencil texture"); + d3d11::SetDebugName(mDepthStencilTexture, "Offscreen depth stencil texture"); + + D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilDesc; + depthStencilDesc.Format = gl_d3d11::GetDSVFormat(mDepthBufferFormat); + depthStencilDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + depthStencilDesc.Flags = 0; + depthStencilDesc.Texture2D.MipSlice = 0; + + result = device->CreateDepthStencilView(mDepthStencilTexture, &depthStencilDesc, &mDepthStencilDSView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthStencilDSView, "Offscreen depth stencil view"); + + D3D11_SHADER_RESOURCE_VIEW_DESC depthStencilSRVDesc; + depthStencilSRVDesc.Format = gl_d3d11::GetSRVFormat(mDepthBufferFormat); + depthStencilSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + depthStencilSRVDesc.Texture2D.MostDetailedMip = 0; + depthStencilSRVDesc.Texture2D.MipLevels = -1; - result = device->CreateDepthStencilView(mDepthStencilTexture, NULL, &mDepthStencilDSView); + result = device->CreateShaderResourceView(mDepthStencilTexture, &depthStencilSRVDesc, &mDepthStencilSRView); ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mDepthStencilDSView, "Depth stencil view"); + d3d11::SetDebugName(mDepthStencilSRView, "Offscreen depth stencil shader resource"); } mWidth = backbufferWidth; mHeight = backbufferHeight; +#if !defined(ANGLE_PLATFORM_WINRT) || WINAPI_FAMILY==WINAPI_FAMILY_PC_APP + mViewportWidth = backbufferWidth; + mViewportHeight = backbufferHeight; +#endif +#if !defined(ANGLE_PLATFORM_WINRT) if (previousOffscreenTexture != NULL) { D3D11_BOX sourceBox = {0}; @@ -262,13 +302,14 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei const int yoffset = std::max(mHeight - previousHeight, 0); deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0, previousOffscreenTexture, 0, &sourceBox); - previousOffscreenTexture->Release(); + SafeRelease(previousOffscreenTexture); if (mSwapChain) { - swapRect(0, 0, mWidth, mHeight); + swapRect(0, 0, mWidth, mHeight, SWAP_NORMAL); } } +#endif return EGL_SUCCESS; } @@ -295,8 +336,15 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) SafeRelease(mBackBufferRTView); // Resize swap chain - DXGI_FORMAT backbufferDXGIFormat = gl_d3d11::ConvertRenderbufferFormat(mBackBufferFormat); - HRESULT result = mSwapChain->ResizeBuffers(2, backbufferWidth, backbufferHeight, backbufferDXGIFormat, 0); + HRESULT result; +#if !defined(ANGLE_PLATFORM_WINRT) || WINAPI_FAMILY==WINAPI_FAMILY_PC_APP // Windows phone swap chain is never resized, only the texture is +#if !defined(ANGLE_PLATFORM_WINRT) + const int bufferCount = 1; +#else + const int bufferCount = 2; +#endif + DXGI_FORMAT backbufferDXGIFormat = gl_d3d11::GetTexFormat(mBackBufferFormat); + result = mSwapChain->ResizeBuffers(bufferCount, backbufferWidth, backbufferHeight, backbufferDXGIFormat, 0); if (FAILED(result)) { @@ -312,7 +360,7 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) return EGL_BAD_ALLOC; } } - +#endif result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); ASSERT(SUCCEEDED(result)); if (SUCCEEDED(result)) @@ -361,49 +409,56 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap if (mWindow) { -#if !defined(ANGLE_OS_WINRT) IDXGIFactory *factory = mRenderer->getDxgiFactory(); - +#if !defined(ANGLE_PLATFORM_WINRT) DXGI_SWAP_CHAIN_DESC swapChainDesc = {0}; - swapChainDesc.BufferDesc.Format = gl_d3d11::ConvertRenderbufferFormat(mBackBufferFormat); swapChainDesc.BufferDesc.Width = backbufferWidth; swapChainDesc.BufferDesc.Height = backbufferHeight; - swapChainDesc.BufferCount = 2; - swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; - swapChainDesc.Windowed = TRUE; + swapChainDesc.BufferDesc.Format = gl_d3d11::GetTexFormat(mBackBufferFormat); + swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.BufferCount = 1; swapChainDesc.OutputWindow = mWindow; + swapChainDesc.Windowed = TRUE; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + swapChainDesc.Flags = 0; + + HRESULT result = factory->CreateSwapChain(device, &swapChainDesc, &mSwapChain); #else - IDXGIFactory2 *factory; - HRESULT result = mRenderer->getDxgiFactory()->QueryInterface(IID_PPV_ARGS(&factory)); + IDXGIFactory2 *factory2; + HRESULT result = factory->QueryInterface(IID_PPV_ARGS(&factory2)); ASSERT(SUCCEEDED(result)); DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; - swapChainDesc.Format = gl_d3d11::ConvertRenderbufferFormat(mBackBufferFormat); - swapChainDesc.Width = backbufferWidth; - swapChainDesc.Height = backbufferHeight; + swapChainDesc.Width = 0; + swapChainDesc.Height = 0; + swapChainDesc.Format = gl_d3d11::GetTexFormat(mBackBufferFormat); + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.Stereo = FALSE; -#if !defined(ANGLE_OS_WINPHONE) + swapChainDesc.Flags = 0; +#if WINAPI_FAMILY==WINAPI_FAMILY_PC_APP + swapChainDesc.Scaling = DXGI_SCALING_NONE; swapChainDesc.BufferCount = 2; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; -#else +#elif WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP swapChainDesc.BufferCount = 1; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; #endif -#endif - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.Flags = 0; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; -#if !defined(ANGLE_OS_WINRT) - HRESULT result = factory->CreateSwapChain(device, &swapChainDesc, &mSwapChain); -#else IDXGISwapChain1 *swapChain; - result = factory->CreateSwapChainForCoreWindow(device, mWindow, &swapChainDesc, NULL, &swapChain); + result = factory2->CreateSwapChainForCoreWindow(device, mWindow, &swapChainDesc, NULL, &swapChain); mSwapChain = swapChain; + HRESULT hr = swapChain->GetDesc1(&swapChainDesc); + ASSERT(SUCCEEDED(hr)); + mViewportWidth = swapChainDesc.Width; + mViewportHeight = swapChainDesc.Height; #endif if (FAILED(result)) @@ -415,28 +470,10 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap { return EGL_CONTEXT_LOST; } -#if !defined(ANGLE_OS_WINRT) else { - // We cannot create a swap chain for an HWND that is owned by a different process on some versions of - // windows - DWORD currentProcessId = GetCurrentProcessId(); - DWORD wndProcessId; - GetWindowThreadProcessId(mWindow, &wndProcessId); - - if (currentProcessId != wndProcessId) - { - ERR("Could not create swap chain, window owned by different process"); - return EGL_BAD_NATIVE_WINDOW; - } - else - { - return EGL_BAD_ALLOC; - } + return EGL_BAD_ALLOC; } -#else - return EGL_BAD_ALLOC; -#endif } result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); @@ -505,21 +542,21 @@ void SwapChain11::initPassThroughResources() { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; - result = device->CreateInputLayout(quadLayout, 2, g_VS_Passthrough, sizeof(g_VS_Passthrough), &mPassThroughIL); + result = device->CreateInputLayout(quadLayout, 2, g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), &mPassThroughIL); ASSERT(SUCCEEDED(result)); d3d11::SetDebugName(mPassThroughIL, "Swap chain pass through layout"); - result = device->CreateVertexShader(g_VS_Passthrough, sizeof(g_VS_Passthrough), NULL, &mPassThroughVS); + result = device->CreateVertexShader(g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), NULL, &mPassThroughVS); ASSERT(SUCCEEDED(result)); d3d11::SetDebugName(mPassThroughVS, "Swap chain pass through vertex shader"); - result = device->CreatePixelShader(g_PS_PassthroughRGBA, sizeof(g_PS_PassthroughRGBA), NULL, &mPassThroughPS); + result = device->CreatePixelShader(g_PS_PassthroughRGBA2D, sizeof(g_PS_PassthroughRGBA2D), NULL, &mPassThroughPS); ASSERT(SUCCEEDED(result)); d3d11::SetDebugName(mPassThroughPS, "Swap chain pass through pixel shader"); } // parameters should be validated/clamped by caller -EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint flags) { if (!mSwapChain) { @@ -550,10 +587,13 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) float u2 = (x + width) / float(mWidth); float v2 = (y + height) / float(mHeight); - d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v1); - d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2); - d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1); - d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2); + const int rotateL = flags & SWAP_ROTATE_90; + const int rotateR = flags & SWAP_ROTATE_270; + + d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, rotateL ? u2 : u1, rotateR ? v2 : v1); + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, rotateR ? u2 : u1, rotateL ? v1 : v2); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, rotateR ? u1 : u2, rotateL ? v2 : v1); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, rotateL ? u1 : u2, rotateR ? v1 : v2); deviceContext->Unmap(mQuadVB, 0); @@ -583,8 +623,8 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) D3D11_VIEWPORT viewport; viewport.TopLeftX = 0; viewport.TopLeftY = 0; - viewport.Width = mWidth; - viewport.Height = mHeight; + viewport.Width = mViewportWidth; + viewport.Height = mViewportHeight; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; deviceContext->RSSetViewports(1, &viewport); @@ -605,6 +645,7 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) if (result == DXGI_ERROR_DEVICE_REMOVED) { HRESULT removedReason = device->GetDeviceRemovedReason(); + UNUSED_TRACE_VARIABLE(removedReason); ERR("Present failed: the D3D11 device was removed: 0x%08X", removedReason); return EGL_CONTEXT_LOST; } @@ -628,61 +669,33 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) return EGL_SUCCESS; } -// Increments refcount on texture. -// caller must Release() the returned texture ID3D11Texture2D *SwapChain11::getOffscreenTexture() { - if (mOffscreenTexture) - { - mOffscreenTexture->AddRef(); - } - return mOffscreenTexture; } -// Increments refcount on view. -// caller must Release() the returned view ID3D11RenderTargetView *SwapChain11::getRenderTarget() { - if (mOffscreenRTView) - { - mOffscreenRTView->AddRef(); - } - return mOffscreenRTView; } -// Increments refcount on view. -// caller must Release() the returned view ID3D11ShaderResourceView *SwapChain11::getRenderTargetShaderResource() { - if (mOffscreenSRView) - { - mOffscreenSRView->AddRef(); - } - return mOffscreenSRView; } -// Increments refcount on view. -// caller must Release() the returned view ID3D11DepthStencilView *SwapChain11::getDepthStencil() { - if (mDepthStencilDSView) - { - mDepthStencilDSView->AddRef(); - } - return mDepthStencilDSView; } -ID3D11Texture2D *SwapChain11::getDepthStencilTexture() +ID3D11ShaderResourceView * SwapChain11::getDepthStencilShaderResource() { - if (mDepthStencilTexture) - { - mDepthStencilTexture->AddRef(); - } + return mDepthStencilSRView; +} +ID3D11Texture2D *SwapChain11::getDepthStencilTexture() +{ return mDepthStencilTexture; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/SwapChain11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h index 2a030c839d..b30b78568a 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/SwapChain11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h @@ -25,7 +25,7 @@ class SwapChain11 : public SwapChain EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint flags); virtual void recreate(); virtual ID3D11Texture2D *getOffscreenTexture(); @@ -34,6 +34,7 @@ class SwapChain11 : public SwapChain virtual ID3D11Texture2D *getDepthStencilTexture(); virtual ID3D11DepthStencilView *getDepthStencil(); + virtual ID3D11ShaderResourceView *getDepthStencilShaderResource(); EGLint getWidth() const { return mWidth; } EGLint getHeight() const { return mHeight; } @@ -51,6 +52,8 @@ class SwapChain11 : public SwapChain Renderer11 *mRenderer; EGLint mHeight; EGLint mWidth; + EGLint mViewportWidth; + EGLint mViewportHeight; bool mAppCreatedShareHandle; unsigned int mSwapInterval; bool mPassThroughResourcesInit; @@ -66,6 +69,7 @@ class SwapChain11 : public SwapChain ID3D11Texture2D *mDepthStencilTexture; ID3D11DepthStencilView *mDepthStencilDSView; + ID3D11ShaderResourceView *mDepthStencilSRView; ID3D11Buffer *mQuadVB; ID3D11SamplerState *mPassThroughSampler; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp new file mode 100644 index 0000000000..00b81b7c92 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp @@ -0,0 +1,1559 @@ +#include "precompiled.h" +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage11.cpp: Implements the abstract rx::TextureStorage11 class and its concrete derived +// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. + +#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" + +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" +#include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/Blit11.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" + +#include "common/utilities.h" +#include "libGLESv2/main.h" + +namespace rx +{ + +TextureStorage11::SwizzleCacheValue::SwizzleCacheValue() + : swizzleRed(GL_NONE), swizzleGreen(GL_NONE), swizzleBlue(GL_NONE), swizzleAlpha(GL_NONE) +{ +} + +TextureStorage11::SwizzleCacheValue::SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha) + : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha) +{ +} + +bool TextureStorage11::SwizzleCacheValue::operator==(const SwizzleCacheValue &other) const +{ + return swizzleRed == other.swizzleRed && + swizzleGreen == other.swizzleGreen && + swizzleBlue == other.swizzleBlue && + swizzleAlpha == other.swizzleAlpha; +} + +bool TextureStorage11::SwizzleCacheValue::operator!=(const SwizzleCacheValue &other) const +{ + return !(*this == other); +} + +TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle) + : baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle) +{ +} + +bool TextureStorage11::SRVKey::operator==(const SRVKey &rhs) const +{ + return baseLevel == rhs.baseLevel && + mipLevels == rhs.mipLevels && + swizzle == rhs.swizzle; +} + +TextureStorage11::SRVCache::~SRVCache() +{ + for (size_t i = 0; i < cache.size(); i++) + { + SafeRelease(cache[i].srv); + } +} + +ID3D11ShaderResourceView *TextureStorage11::SRVCache::find(const SRVKey &key) const +{ + for (size_t i = 0; i < cache.size(); i++) + { + if (cache[i].key == key) + { + return cache[i].srv; + } + } + + return NULL; +} + +ID3D11ShaderResourceView *TextureStorage11::SRVCache::add(const SRVKey &key, ID3D11ShaderResourceView *srv) +{ + SRVPair pair = {key, srv}; + cache.push_back(pair); + + return srv; +} + +TextureStorage11::TextureStorage11(Renderer *renderer, UINT bindFlags) + : mBindFlags(bindFlags), + mTopLevel(0), + mMipLevels(0), + mTextureFormat(DXGI_FORMAT_UNKNOWN), + mShaderResourceFormat(DXGI_FORMAT_UNKNOWN), + mRenderTargetFormat(DXGI_FORMAT_UNKNOWN), + mDepthStencilFormat(DXGI_FORMAT_UNKNOWN), + mTextureWidth(0), + mTextureHeight(0), + mTextureDepth(0) +{ + mRenderer = Renderer11::makeRenderer11(renderer); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mLevelSRVs[i] = NULL; + } +} + +TextureStorage11::~TextureStorage11() +{ + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mLevelSRVs[level]); + } +} + +TextureStorage11 *TextureStorage11::makeTextureStorage11(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11*, storage)); + return static_cast<TextureStorage11*>(storage); +} + +DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, bool renderTarget) +{ + UINT bindFlags = 0; + + if (gl_d3d11::GetSRVFormat(internalFormat) != DXGI_FORMAT_UNKNOWN) + { + bindFlags |= D3D11_BIND_SHADER_RESOURCE; + } + if (gl_d3d11::GetDSVFormat(internalFormat) != DXGI_FORMAT_UNKNOWN) + { + bindFlags |= D3D11_BIND_DEPTH_STENCIL; + } + if (gl_d3d11::GetRTVFormat(internalFormat) != DXGI_FORMAT_UNKNOWN && renderTarget) + { + bindFlags |= D3D11_BIND_RENDER_TARGET; + } + + return bindFlags; +} + +UINT TextureStorage11::getBindFlags() const +{ + return mBindFlags; +} + +int TextureStorage11::getTopLevel() const +{ + return mTopLevel; +} + +bool TextureStorage11::isRenderTarget() const +{ + return (mBindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL)) != 0; +} + +bool TextureStorage11::isManaged() const +{ + return false; +} + +int TextureStorage11::getLevelCount() const +{ + return mMipLevels - mTopLevel; +} + +int TextureStorage11::getLevelWidth(int mipLevel) const +{ + return std::max(static_cast<int>(mTextureWidth) >> mipLevel, 1); +} + +int TextureStorage11::getLevelHeight(int mipLevel) const +{ + return std::max(static_cast<int>(mTextureHeight) >> mipLevel, 1); +} + +int TextureStorage11::getLevelDepth(int mipLevel) const +{ + return std::max(static_cast<int>(mTextureDepth) >> mipLevel, 1); +} + +UINT TextureStorage11::getSubresourceIndex(int mipLevel, int layerTarget) const +{ + UINT index = 0; + if (getResource()) + { + index = D3D11CalcSubresource(mipLevel, layerTarget, mMipLevels); + } + return index; +} + +ID3D11ShaderResourceView *TextureStorage11::getSRV(const gl::SamplerState &samplerState) +{ + bool swizzleRequired = samplerState.swizzleRequired(); + bool mipmapping = IsMipmapFiltered(samplerState); + unsigned int mipLevels = mipmapping ? (samplerState.maxLevel - samplerState.baseLevel) : 1; + + // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, which corresponds to GL level 0) + mipLevels = std::min(mipLevels, mMipLevels - mTopLevel - samplerState.baseLevel); + + if (swizzleRequired) + { + verifySwizzleExists(samplerState.swizzleRed, samplerState.swizzleGreen, samplerState.swizzleBlue, samplerState.swizzleAlpha); + } + + SRVKey key(samplerState.baseLevel, mipLevels, swizzleRequired); + ID3D11ShaderResourceView *srv = srvCache.find(key); + + if(srv) + { + return srv; + } + + DXGI_FORMAT format = (swizzleRequired ? mSwizzleShaderResourceFormat : mShaderResourceFormat); + ID3D11Resource *texture = swizzleRequired ? getSwizzleTexture() : getResource(); + + srv = createSRV(samplerState.baseLevel, mipLevels, format, texture); + + return srvCache.add(key, srv); +} + +ID3D11ShaderResourceView *TextureStorage11::getSRVLevel(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mLevelSRVs[mipLevel]) + { + mLevelSRVs[mipLevel] = createSRV(mipLevel, 1, mShaderResourceFormat, getResource()); + } + + return mLevelSRVs[mipLevel]; + } + else + { + return NULL; + } +} + +void TextureStorage11::generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); + for (int level = 0; level < getLevelCount(); level++) + { + // Check if the swizzle for this level is out of date + if (mSwizzleCache[level] != swizzleTarget) + { + // Need to re-render the swizzle for this level + ID3D11ShaderResourceView *sourceSRV = getSRVLevel(level); + ID3D11RenderTargetView *destRTV = getSwizzleRenderTarget(level); + + gl::Extents size(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); + + Blit11 *blitter = mRenderer->getBlitter(); + + if (blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha)) + { + mSwizzleCache[level] = swizzleTarget; + } + else + { + ERR("Failed to swizzle texture."); + } + } + } +} + +void TextureStorage11::invalidateSwizzleCacheLevel(int mipLevel) +{ + if (mipLevel >= 0 && static_cast<unsigned int>(mipLevel) < ArraySize(mSwizzleCache)) + { + // The default constructor of SwizzleCacheValue has GL_NONE for all channels which is not a + // valid swizzle combination + mSwizzleCache[mipLevel] = SwizzleCacheValue(); + } +} + +void TextureStorage11::invalidateSwizzleCache() +{ + for (unsigned int mipLevel = 0; mipLevel < ArraySize(mSwizzleCache); mipLevel++) + { + invalidateSwizzleCacheLevel(mipLevel); + } +} + +bool TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsigned int sourceSubresource, + int level, int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth) +{ + if (srcTexture) + { + invalidateSwizzleCacheLevel(level); + + gl::Extents texSize(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); + gl::Box copyArea(xoffset, yoffset, zoffset, width, height, depth); + + bool fullCopy = copyArea.x == 0 && + copyArea.y == 0 && + copyArea.z == 0 && + copyArea.width == texSize.width && + copyArea.height == texSize.height && + copyArea.depth == texSize.depth; + + ID3D11Resource *dstTexture = getResource(); + unsigned int dstSubresource = getSubresourceIndex(level + mTopLevel, layerTarget); + + ASSERT(dstTexture); + + if (!fullCopy && (d3d11::GetDepthBits(mTextureFormat) > 0 || d3d11::GetStencilBits(mTextureFormat) > 0)) + { + // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead + Blit11 *blitter = mRenderer->getBlitter(); + + return blitter->copyDepthStencil(srcTexture, sourceSubresource, copyArea, texSize, + dstTexture, dstSubresource, copyArea, texSize, + NULL); + } + else + { + D3D11_BOX srcBox; + srcBox.left = copyArea.x; + srcBox.top = copyArea.y; + srcBox.right = copyArea.x + roundUp((unsigned int)width, d3d11::GetBlockWidth(mTextureFormat)); + srcBox.bottom = copyArea.y + roundUp((unsigned int)height, d3d11::GetBlockHeight(mTextureFormat)); + srcBox.front = copyArea.z; + srcBox.back = copyArea.z + copyArea.depth; + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + context->CopySubresourceRegion(dstTexture, dstSubresource, copyArea.x, copyArea.y, copyArea.z, + srcTexture, sourceSubresource, fullCopy ? NULL : &srcBox); + return true; + } + } + + return false; +} + +void TextureStorage11::generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest) +{ + if (source && dest) + { + ID3D11ShaderResourceView *sourceSRV = source->getShaderResourceView(); + ID3D11RenderTargetView *destRTV = dest->getRenderTargetView(); + + if (sourceSRV && destRTV) + { + gl::Box sourceArea(0, 0, 0, source->getWidth(), source->getHeight(), source->getDepth()); + gl::Extents sourceSize(source->getWidth(), source->getHeight(), source->getDepth()); + + gl::Box destArea(0, 0, 0, dest->getWidth(), dest->getHeight(), dest->getDepth()); + gl::Extents destSize(dest->getWidth(), dest->getHeight(), dest->getDepth()); + + Blit11 *blitter = mRenderer->getBlitter(); + + blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize, NULL, + gl::GetFormat(source->getInternalFormat()), GL_LINEAR); + } + } +} + +void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); + for (unsigned int level = 0; level < mMipLevels; level++) + { + ASSERT(mSwizzleCache[level] == swizzleTarget); + } +} + +TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain) + : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE) +{ + mTexture = swapchain->getOffscreenTexture(); + mTexture->AddRef(); + mSwizzleTexture = NULL; + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mRenderTarget[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + D3D11_TEXTURE2D_DESC texDesc; + mTexture->GetDesc(&texDesc); + mMipLevels = texDesc.MipLevels; + mTextureFormat = texDesc.Format; + mTextureWidth = texDesc.Width; + mTextureHeight = texDesc.Height; + mTextureDepth = 1; + + ID3D11ShaderResourceView *srv = swapchain->getRenderTargetShaderResource(); + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srv->GetDesc(&srvDesc); + mShaderResourceFormat = srvDesc.Format; + + ID3D11RenderTargetView* offscreenRTV = swapchain->getRenderTarget(); + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + offscreenRTV->GetDesc(&rtvDesc); + mRenderTargetFormat = rtvDesc.Format; + + GLenum internalFormat = d3d11_gl::GetInternalFormat(mTextureFormat); + mSwizzleTextureFormat = gl_d3d11::GetSwizzleTexFormat(internalFormat); + mSwizzleShaderResourceFormat = gl_d3d11::GetSwizzleSRVFormat(internalFormat); + mSwizzleRenderTargetFormat = gl_d3d11::GetSwizzleRTVFormat(internalFormat); + + mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; +} + +TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mRenderTarget[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + mTextureFormat = gl_d3d11::GetTexFormat(internalformat); + mShaderResourceFormat = gl_d3d11::GetSRVFormat(internalformat); + mDepthStencilFormat = gl_d3d11::GetDSVFormat(internalformat); + mRenderTargetFormat = gl_d3d11::GetRTVFormat(internalformat); + mSwizzleTextureFormat = gl_d3d11::GetSwizzleTexFormat(internalformat); + mSwizzleShaderResourceFormat = gl_d3d11::GetSwizzleSRVFormat(internalformat); + mSwizzleRenderTargetFormat = gl_d3d11::GetSwizzleRTVFormat(internalformat); + + // if the width or height is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (width > 0 && height > 0) + { + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; // Compressed texture size constraints? + desc.Height = height; + desc.MipLevels = mRenderer->isLevel9() ? 1 : ((levels > 0) ? (mTopLevel + levels) : 0); + desc.ArraySize = 1; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + gl::error(GL_OUT_OF_MEMORY); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + gl::error(GL_OUT_OF_MEMORY); + } + else + { + mTexture->GetDesc(&desc); + mMipLevels = desc.MipLevels; + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mTextureDepth = 1; + } + } +} + +TextureStorage11_2D::~TextureStorage11_2D() +{ + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + SafeDelete(mRenderTarget[i]); + SafeRelease(mSwizzleRenderTargets[i]); + } +} + +TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2D*, storage)); + return static_cast<TextureStorage11_2D*>(storage); +} + +ID3D11Resource *TextureStorage11_2D::getResource() const +{ + return mTexture; +} + +RenderTarget *TextureStorage11_2D::getRenderTarget(int level) +{ + if (level >= 0 && level < getLevelCount()) + { + if (!mRenderTarget[level]) + { + ID3D11ShaderResourceView *srv = getSRVLevel(level); + if (!srv) + { + return NULL; + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + level; + + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mRenderTarget[level] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mDepthStencilFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = mTopLevel + level; + dsvDesc.Flags = 0; + + ID3D11DepthStencilView *dsv; + HRESULT result = device->CreateDepthStencilView(mTexture, &dsvDesc, &dsv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mRenderTarget[level] = new RenderTarget11(mRenderer, dsv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(dsv); + } + else + { + UNREACHABLE(); + } + } + + return mRenderTarget[level]; + } + else + { + return NULL; + } +} + +ID3D11ShaderResourceView *TextureStorage11_2D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2D.MipLevels = mipLevels; + + ID3D11ShaderResourceView *SRV = NULL; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + + if (result == E_OUTOFMEMORY) + { + gl::error(GL_OUT_OF_MEMORY); + } + ASSERT(SUCCEEDED(result)); + + return SRV; +} + +void TextureStorage11_2D::generateMipmap(int level) +{ + invalidateSwizzleCacheLevel(level); + + RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(level - 1)); + RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(level)); + + generateMipmapLayer(source, dest); +} + +ID3D11Resource *TextureStorage11_2D::getSwizzleTexture() +{ + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = 1; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11Texture2D*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleTexture; +} + +ID3D11RenderTargetView *TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = getSwizzleTexture(); + if (!swizzleTexture) + { + return NULL; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + mipLevel; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11RenderTargetView*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleRenderTargets[mipLevel]; + } + else + { + return NULL; + } +} + +unsigned int TextureStorage11_2D::getTextureLevelDepth(int mipLevel) const +{ + return 1; +} + +TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mSwizzleRenderTargets[level] = NULL; + for (unsigned int face = 0; face < 6; face++) + { + mRenderTarget[face][level] = NULL; + } + } + + mTextureFormat = gl_d3d11::GetTexFormat(internalformat); + mShaderResourceFormat = gl_d3d11::GetSRVFormat(internalformat); + mDepthStencilFormat = gl_d3d11::GetDSVFormat(internalformat); + mRenderTargetFormat = gl_d3d11::GetRTVFormat(internalformat); + mSwizzleTextureFormat = gl_d3d11::GetSwizzleTexFormat(internalformat); + mSwizzleShaderResourceFormat = gl_d3d11::GetSwizzleSRVFormat(internalformat); + mSwizzleRenderTargetFormat = gl_d3d11::GetSwizzleRTVFormat(internalformat); + + // if the size is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (size > 0) + { + // adjust size if needed for compressed textures + int height = size; + d3d11::MakeValidSize(false, mTextureFormat, &size, &height, &mTopLevel); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = size; + desc.Height = size; + desc.MipLevels = ((levels > 0) ? (mTopLevel + levels) : 0); + desc.ArraySize = 6; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + gl::error(GL_OUT_OF_MEMORY); + } + else + { + mTexture->GetDesc(&desc); + mMipLevels = desc.MipLevels; + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mTextureDepth = 1; + } + } +} + +TextureStorage11_Cube::~TextureStorage11_Cube() +{ + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mSwizzleRenderTargets[level]); + for (unsigned int face = 0; face < 6; face++) + { + SafeDelete(mRenderTarget[face][level]); + } + } +} + +TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_Cube*, storage)); + return static_cast<TextureStorage11_Cube*>(storage); +} + +ID3D11Resource *TextureStorage11_Cube::getResource() const +{ + return mTexture; +} + +RenderTarget *TextureStorage11_Cube::getRenderTargetFace(GLenum faceTarget, int level) +{ + if (level >= 0 && level < getLevelCount()) + { + int faceIndex = TextureD3D_Cube::targetToIndex(faceTarget); + if (!mRenderTarget[faceIndex][level]) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = mShaderResourceFormat; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + level; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = faceIndex; + srvDesc.Texture2DArray.ArraySize = 1; + + ID3D11ShaderResourceView *srv; + result = device->CreateShaderResourceView(mTexture, &srvDesc, &srv); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; + rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mRenderTarget[faceIndex][level] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); + } + else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mDepthStencilFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Flags = 0; + dsvDesc.Texture2DArray.MipSlice = mTopLevel + level; + dsvDesc.Texture2DArray.FirstArraySlice = faceIndex; + dsvDesc.Texture2DArray.ArraySize = 1; + + ID3D11DepthStencilView *dsv; + result = device->CreateDepthStencilView(mTexture, &dsvDesc, &dsv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mRenderTarget[faceIndex][level] = new RenderTarget11(mRenderer, dsv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(dsv); + SafeRelease(srv); + } + else + { + UNREACHABLE(); + } + } + + return mRenderTarget[faceIndex][level]; + } + else + { + return NULL; + } +} + +ID3D11ShaderResourceView *TextureStorage11_Cube::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + + // Unnormalized integer cube maps are not supported by DX11; we emulate them as an array of six 2D textures + bool unnormalizedInteger = (d3d11::GetComponentType(mTextureFormat) == GL_INT || + d3d11::GetComponentType(mTextureFormat) == GL_UNSIGNED_INT); + + if(unnormalizedInteger) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.ArraySize = 6; + } + else + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + srvDesc.TextureCube.MipLevels = mipLevels; + srvDesc.TextureCube.MostDetailedMip = mTopLevel + baseLevel; + } + + ID3D11ShaderResourceView *SRV = NULL; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + + if (result == E_OUTOFMEMORY) + { + gl::error(GL_OUT_OF_MEMORY); + } + ASSERT(SUCCEEDED(result)); + + return SRV; +} + +void TextureStorage11_Cube::generateMipmap(int faceIndex, int level) +{ + invalidateSwizzleCacheLevel(level); + + RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTargetFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level - 1)); + RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTargetFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level)); + + generateMipmapLayer(source, dest); +} + +ID3D11Resource *TextureStorage11_Cube::getSwizzleTexture() +{ + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = 6; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11Texture2D*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleTexture; +} + +ID3D11RenderTargetView *TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = getSwizzleTexture(); + if (!swizzleTexture) + { + return NULL; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.ArraySize = 6; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11RenderTargetView*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleRenderTargets[mipLevel]; + } + else + { + return NULL; + } +} + +unsigned int TextureStorage11_Cube::getTextureLevelDepth(int mipLevel) const +{ + return 6; +} + +TextureStorage11_3D::TextureStorage11_3D(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mLevelRenderTargets[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + mTextureFormat = gl_d3d11::GetTexFormat(internalformat); + mShaderResourceFormat = gl_d3d11::GetSRVFormat(internalformat); + mDepthStencilFormat = gl_d3d11::GetDSVFormat(internalformat); + mRenderTargetFormat = gl_d3d11::GetRTVFormat(internalformat); + mSwizzleTextureFormat = gl_d3d11::GetSwizzleTexFormat(internalformat); + mSwizzleShaderResourceFormat = gl_d3d11::GetSwizzleSRVFormat(internalformat); + mSwizzleRenderTargetFormat = gl_d3d11::GetSwizzleRTVFormat(internalformat); + + // If the width, height or depth are not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (width > 0 && height > 0 && depth > 0) + { + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE3D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.Depth = depth; + desc.MipLevels = ((levels > 0) ? (mTopLevel + levels) : 0); + desc.Format = mTextureFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture3D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + gl::error(GL_OUT_OF_MEMORY); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + gl::error(GL_OUT_OF_MEMORY); + } + else + { + mTexture->GetDesc(&desc); + mMipLevels = desc.MipLevels; + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mTextureDepth = desc.Depth; + } + } +} + +TextureStorage11_3D::~TextureStorage11_3D() +{ + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (RenderTargetMap::iterator i = mLevelLayerRenderTargets.begin(); i != mLevelLayerRenderTargets.end(); i++) + { + SafeDelete(i->second); + } + mLevelLayerRenderTargets.clear(); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + SafeDelete(mLevelRenderTargets[i]); + SafeRelease(mSwizzleRenderTargets[i]); + } +} + +TextureStorage11_3D *TextureStorage11_3D::makeTextureStorage11_3D(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_3D*, storage)); + return static_cast<TextureStorage11_3D*>(storage); +} + +ID3D11Resource *TextureStorage11_3D::getResource() const +{ + return mTexture; +} + +ID3D11ShaderResourceView *TextureStorage11_3D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + srvDesc.Texture3D.MostDetailedMip = baseLevel; + srvDesc.Texture3D.MipLevels = mipLevels; + + ID3D11ShaderResourceView *SRV = NULL; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + + if (result == E_OUTOFMEMORY) + { + gl::error(GL_OUT_OF_MEMORY); + } + ASSERT(SUCCEEDED(result)); + + return SRV; +} + +RenderTarget *TextureStorage11_3D::getRenderTarget(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mLevelRenderTargets[mipLevel]) + { + ID3D11ShaderResourceView *srv = getSRVLevel(mipLevel); + if (!srv) + { + return NULL; + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = 0; + rtvDesc.Texture3D.WSize = -1; + + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mLevelRenderTargets[mipLevel] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(mipLevel), getLevelHeight(mipLevel), getLevelDepth(mipLevel)); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + else + { + UNREACHABLE(); + } + } + + return mLevelRenderTargets[mipLevel]; + } + else + { + return NULL; + } +} + +RenderTarget *TextureStorage11_3D::getRenderTargetLayer(int mipLevel, int layer) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + LevelLayerKey key(mipLevel, layer); + if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + // TODO, what kind of SRV is expected here? + ID3D11ShaderResourceView *srv = NULL; + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = layer; + rtvDesc.Texture3D.WSize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mLevelLayerRenderTargets[key] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); + } + else + { + UNREACHABLE(); + } + } + + return mLevelLayerRenderTargets[key]; + } + else + { + return NULL; + } +} + +void TextureStorage11_3D::generateMipmap(int level) +{ + invalidateSwizzleCacheLevel(level); + + RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(level - 1)); + RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(level)); + + generateMipmapLayer(source, dest); +} + +ID3D11Resource *TextureStorage11_3D::getSwizzleTexture() +{ + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE3D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.Depth = mTextureDepth; + desc.MipLevels = mMipLevels; + desc.Format = mSwizzleTextureFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture3D(&desc, NULL, &mSwizzleTexture); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11Texture3D*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleTexture; +} + +ID3D11RenderTargetView *TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = getSwizzleTexture(); + if (!swizzleTexture) + { + return NULL; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = 0; + rtvDesc.Texture3D.WSize = -1; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11RenderTargetView*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleRenderTargets[mipLevel]; + } + else + { + return NULL; + } +} + +unsigned int TextureStorage11_3D::getTextureLevelDepth(int mipLevel) const +{ + return std::max(mTextureDepth >> mipLevel, 1U); +} + + +TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mSwizzleRenderTargets[level] = NULL; + } + + mTextureFormat = gl_d3d11::GetTexFormat(internalformat); + mShaderResourceFormat = gl_d3d11::GetSRVFormat(internalformat); + mDepthStencilFormat = gl_d3d11::GetDSVFormat(internalformat); + mRenderTargetFormat = gl_d3d11::GetRTVFormat(internalformat); + mSwizzleTextureFormat = gl_d3d11::GetSwizzleTexFormat(internalformat); + mSwizzleShaderResourceFormat = gl_d3d11::GetSwizzleSRVFormat(internalformat); + mSwizzleRenderTargetFormat = gl_d3d11::GetSwizzleRTVFormat(internalformat); + + // if the width, height or depth is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (width > 0 && height > 0 && depth > 0) + { + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = ((levels > 0) ? (mTopLevel + levels) : 0); + desc.ArraySize = depth; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + gl::error(GL_OUT_OF_MEMORY); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + ERR("Creating image failed."); + gl::error(GL_OUT_OF_MEMORY); + } + else + { + mTexture->GetDesc(&desc); + mMipLevels = desc.MipLevels; + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mTextureDepth = desc.ArraySize; + } + } +} + +TextureStorage11_2DArray::~TextureStorage11_2DArray() +{ + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mSwizzleRenderTargets[level]); + } + + for (RenderTargetMap::iterator i = mRenderTargets.begin(); i != mRenderTargets.end(); i++) + { + SafeDelete(i->second); + } + mRenderTargets.clear(); +} + +TextureStorage11_2DArray *TextureStorage11_2DArray::makeTextureStorage11_2DArray(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2DArray*, storage)); + return static_cast<TextureStorage11_2DArray*>(storage); +} + +ID3D11Resource *TextureStorage11_2DArray::getResource() const +{ + return mTexture; +} + +ID3D11ShaderResourceView *TextureStorage11_2DArray::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2DArray.MipLevels = mipLevels; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.ArraySize = mTextureDepth; + + ID3D11ShaderResourceView *SRV = NULL; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + + if (result == E_OUTOFMEMORY) + { + gl::error(GL_OUT_OF_MEMORY); + } + ASSERT(SUCCEEDED(result)); + + return SRV; +} + +RenderTarget *TextureStorage11_2DArray::getRenderTargetLayer(int mipLevel, int layer) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + LevelLayerKey key(mipLevel, layer); + if (mRenderTargets.find(key) == mRenderTargets.end()) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = mShaderResourceFormat; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + mipLevel; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = layer; + srvDesc.Texture2DArray.ArraySize = 1; + + ID3D11ShaderResourceView *srv; + result = device->CreateShaderResourceView(mTexture, &srvDesc, &srv); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = layer; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + SafeRelease(srv); + return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + + mRenderTargets[key] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); + } + else + { + UNREACHABLE(); + } + } + + return mRenderTargets[key]; + } + else + { + return NULL; + } +} + +void TextureStorage11_2DArray::generateMipmap(int level) +{ + invalidateSwizzleCacheLevel(level); + for (unsigned int layer = 0; layer < mTextureDepth; layer++) + { + RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTargetLayer(level - 1, layer)); + RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTargetLayer(level, layer)); + + generateMipmapLayer(source, dest); + } +} + +ID3D11Resource *TextureStorage11_2DArray::getSwizzleTexture() +{ + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = mTextureDepth; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11Texture2D*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleTexture; +} + +ID3D11RenderTargetView *TextureStorage11_2DArray::getSwizzleRenderTarget(int mipLevel) +{ + if (mipLevel >= 0 && mipLevel < getLevelCount()) + { + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = getSwizzleTexture(); + if (!swizzleTexture) + { + return NULL; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.ArraySize = mTextureDepth; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + if (result == E_OUTOFMEMORY) + { + return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11RenderTargetView*>(NULL)); + } + ASSERT(SUCCEEDED(result)); + } + + return mSwizzleRenderTargets[mipLevel]; + } + else + { + return NULL; + } +} + +unsigned int TextureStorage11_2DArray::getTextureLevelDepth(int mipLevel) const +{ + return mTextureDepth; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h new file mode 100644 index 0000000000..6be7bac8e2 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h @@ -0,0 +1,278 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureStorage11.h: Defines the abstract rx::TextureStorage11 class and its concrete derived +// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. + +#ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ +#define LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ + +#include "libGLESv2/Texture.h" +#include "libGLESv2/renderer/d3d/TextureStorage.h" + +namespace rx +{ +class RenderTarget; +class RenderTarget11; +class Renderer; +class Renderer11; +class SwapChain11; + +class TextureStorage11 : public TextureStorage +{ + public: + virtual ~TextureStorage11(); + + static TextureStorage11 *makeTextureStorage11(TextureStorage *storage); + + static DWORD GetTextureBindFlags(GLenum internalFormat, bool renderTarget); + + UINT getBindFlags() const; + + virtual ID3D11Resource *getResource() const = 0; + virtual ID3D11ShaderResourceView *getSRV(const gl::SamplerState &samplerState); + virtual RenderTarget *getRenderTarget(int level) { return NULL; } + virtual RenderTarget *getRenderTargetFace(GLenum faceTarget, int level) { return NULL; } + virtual RenderTarget *getRenderTargetLayer(int mipLevel, int layer) { return NULL; } + + virtual void generateMipmap(int level) {}; + virtual void generateMipmap(int face, int level) {}; + + virtual int getTopLevel() const; + virtual bool isRenderTarget() const; + virtual bool isManaged() const; + virtual int getLevelCount() const; + UINT getSubresourceIndex(int mipLevel, int layerTarget) const; + + void generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + void invalidateSwizzleCacheLevel(int mipLevel); + void invalidateSwizzleCache(); + + bool updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, int level, + int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth); + + protected: + TextureStorage11(Renderer *renderer, UINT bindFlags); + void generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest); + int getLevelWidth(int mipLevel) const; + int getLevelHeight(int mipLevel) const; + int getLevelDepth(int mipLevel) const; + + virtual ID3D11Resource *getSwizzleTexture() = 0; + virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel) = 0; + ID3D11ShaderResourceView *getSRVLevel(int mipLevel); + + virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) = 0; + + void verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + + virtual unsigned int getTextureLevelDepth(int mipLevel) const = 0; + + Renderer11 *mRenderer; + int mTopLevel; + unsigned int mMipLevels; + + DXGI_FORMAT mTextureFormat; + DXGI_FORMAT mShaderResourceFormat; + DXGI_FORMAT mRenderTargetFormat; + DXGI_FORMAT mDepthStencilFormat; + DXGI_FORMAT mSwizzleTextureFormat; + DXGI_FORMAT mSwizzleShaderResourceFormat; + DXGI_FORMAT mSwizzleRenderTargetFormat; + unsigned int mTextureWidth; + unsigned int mTextureHeight; + unsigned int mTextureDepth; + + struct SwizzleCacheValue + { + GLenum swizzleRed; + GLenum swizzleGreen; + GLenum swizzleBlue; + GLenum swizzleAlpha; + + SwizzleCacheValue(); + SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha); + + bool operator ==(const SwizzleCacheValue &other) const; + bool operator !=(const SwizzleCacheValue &other) const; + }; + SwizzleCacheValue mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + struct SRVKey + { + SRVKey(int baseLevel = 0, int mipLevels = 0, bool swizzle = false); + + bool operator==(const SRVKey &rhs) const; + + int baseLevel; + int mipLevels; + bool swizzle; + }; + + struct SRVPair + { + SRVKey key; + ID3D11ShaderResourceView *srv; + }; + + struct SRVCache + { + ~SRVCache(); + + ID3D11ShaderResourceView *find(const SRVKey &key) const; + ID3D11ShaderResourceView *add(const SRVKey &key, ID3D11ShaderResourceView *srv); + + std::vector<SRVPair> cache; + }; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage11); + + const UINT mBindFlags; + + SRVCache srvCache; + ID3D11ShaderResourceView *mLevelSRVs[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_2D : public TextureStorage11 +{ + public: + TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain); + TextureStorage11_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + virtual ~TextureStorage11_2D(); + + static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage); + + virtual ID3D11Resource *getResource() const; + virtual RenderTarget *getRenderTarget(int level); + + virtual void generateMipmap(int level); + + protected: + virtual ID3D11Resource *getSwizzleTexture(); + virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + + virtual unsigned int getTextureLevelDepth(int mipLevel) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2D); + + virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + + ID3D11Texture2D *mTexture; + RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_Cube : public TextureStorage11 +{ + public: + TextureStorage11_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels); + virtual ~TextureStorage11_Cube(); + + static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage); + + virtual ID3D11Resource *getResource() const; + virtual RenderTarget *getRenderTargetFace(GLenum faceTarget, int level); + + virtual void generateMipmap(int faceIndex, int level); + + protected: + virtual ID3D11Resource *getSwizzleTexture(); + virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + + virtual unsigned int getTextureLevelDepth(int mipLevel) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage11_Cube); + + virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + + ID3D11Texture2D *mTexture; + RenderTarget11 *mRenderTarget[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_3D : public TextureStorage11 +{ + public: + TextureStorage11_3D(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual ~TextureStorage11_3D(); + + static TextureStorage11_3D *makeTextureStorage11_3D(TextureStorage *storage); + + virtual ID3D11Resource *getResource() const; + virtual RenderTarget *getRenderTarget(int mipLevel); + virtual RenderTarget *getRenderTargetLayer(int mipLevel, int layer); + + virtual void generateMipmap(int level); + + protected: + virtual ID3D11Resource *getSwizzleTexture(); + virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + + virtual unsigned int getTextureLevelDepth(int mipLevel) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage11_3D); + + virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + + typedef std::pair<int, int> LevelLayerKey; + typedef std::map<LevelLayerKey, RenderTarget11*> RenderTargetMap; + RenderTargetMap mLevelLayerRenderTargets; + + RenderTarget11 *mLevelRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + ID3D11Texture3D *mTexture; + ID3D11Texture3D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_2DArray : public TextureStorage11 +{ + public: + TextureStorage11_2DArray(Renderer *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual ~TextureStorage11_2DArray(); + + static TextureStorage11_2DArray *makeTextureStorage11_2DArray(TextureStorage *storage); + + virtual ID3D11Resource *getResource() const; + virtual RenderTarget *getRenderTargetLayer(int mipLevel, int layer); + + virtual void generateMipmap(int level); + + protected: + virtual ID3D11Resource *getSwizzleTexture(); + virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + + virtual unsigned int getTextureLevelDepth(int mipLevel) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2DArray); + + virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + + typedef std::pair<int, int> LevelLayerKey; + typedef std::map<LevelLayerKey, RenderTarget11*> RenderTargetMap; + RenderTargetMap mRenderTargets; + + ID3D11Texture2D *mTexture; + + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +} + +#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h new file mode 100644 index 0000000000..590cb9f05a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h @@ -0,0 +1,42 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexArray11.h: Defines the rx::VertexArray11 class which implements rx::VertexArrayImpl. + +#ifndef LIBGLESV2_RENDERER_VERTEXARRAY11_H_ +#define LIBGLESV2_RENDERER_VERTEXARRAY11_H_ + +#include "libGLESv2/renderer/VertexArrayImpl.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ +class Renderer11; + +class VertexArray11 : public VertexArrayImpl +{ + public: + VertexArray11(rx::Renderer11 *renderer) + : VertexArrayImpl(), + mRenderer(renderer) + { + } + virtual ~VertexArray11() { } + + virtual void setElementArrayBuffer(const gl::Buffer *buffer) { } + virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { } + virtual void setAttributeDivisor(size_t idx, GLuint divisor) { } + virtual void enableAttribute(size_t idx, bool enabledState) { } + + private: + DISALLOW_COPY_AND_ASSIGN(VertexArray11); + + rx::Renderer11 *mRenderer; +}; + +} + +#endif // LIBGLESV2_RENDERER_VERTEXARRAY11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp new file mode 100644 index 0000000000..2f47ec0a67 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp @@ -0,0 +1,223 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation. + +#include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h" +#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" + +#include "libGLESv2/Buffer.h" +#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" + +namespace rx +{ + +VertexBuffer11::VertexBuffer11(rx::Renderer11 *const renderer) : mRenderer(renderer) +{ + mBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; +} + +VertexBuffer11::~VertexBuffer11() +{ + SafeRelease(mBuffer); +} + +bool VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) +{ + SafeRelease(mBuffer); + + updateSerial(); + + if (size > 0) + { + ID3D11Device* dxDevice = mRenderer->getDevice(); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = size; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + + HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); + if (FAILED(result)) + { + return false; + } + } + + mBufferSize = size; + mDynamicUsage = dynamicUsage; + return true; +} + +VertexBuffer11 *VertexBuffer11::makeVertexBuffer11(VertexBuffer *vetexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer11*, vetexBuffer)); + return static_cast<VertexBuffer11*>(vetexBuffer); +} + +bool VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) +{ + if (mBuffer) + { + gl::Buffer *buffer = attrib.buffer.get(); + int inputStride = ComputeVertexAttributeStride(attrib); + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Vertex buffer map failed with error 0x%08x", result); + return false; + } + + char* output = reinterpret_cast<char*>(mappedResource.pData) + offset; + + const char *input = NULL; + if (attrib.enabled) + { + if (buffer) + { + Buffer11 *storage = Buffer11::makeBuffer11(buffer->getImplementation()); + input = static_cast<const char*>(storage->getData()) + static_cast<int>(attrib.offset); + } + else + { + input = static_cast<const char*>(attrib.pointer); + } + } + else + { + input = reinterpret_cast<const char*>(currentValue.FloatValues); + } + + if (instances == 0 || attrib.divisor == 0) + { + input += inputStride * start; + } + + gl::VertexFormat vertexFormat(attrib, currentValue.Type); + VertexCopyFunction conversionFunc = gl_d3d11::GetVertexCopyFunction(vertexFormat); + ASSERT(conversionFunc != NULL); + conversionFunc(input, inputStride, count, output); + + dxContext->Unmap(mBuffer, 0); + + return true; + } + else + { + ERR("Vertex buffer not initialized."); + return false; + } +} + +bool VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, + GLsizei instances, unsigned int *outSpaceRequired) const +{ + unsigned int elementCount = 0; + if (attrib.enabled) + { + if (instances == 0 || attrib.divisor == 0) + { + elementCount = count; + } + else + { + if (static_cast<unsigned int>(instances) < std::numeric_limits<unsigned int>::max() - (attrib.divisor - 1)) + { + // Round up + elementCount = rx::roundUp(static_cast<unsigned int>(instances), attrib.divisor); + } + else + { + elementCount = instances / attrib.divisor; + } + } + + gl::VertexFormat vertexFormat(attrib); + unsigned int elementSize = static_cast<unsigned int>(gl_d3d11::GetVertexElementSize(vertexFormat)); + if (elementSize <= std::numeric_limits<unsigned int>::max() / elementCount) + { + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * elementCount; + } + return true; + } + else + { + return false; + } + } + else + { + const unsigned int elementSize = 4; + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * 4; + } + return true; + } +} + +unsigned int VertexBuffer11::getBufferSize() const +{ + return mBufferSize; +} + +bool VertexBuffer11::setBufferSize(unsigned int size) +{ + if (size > mBufferSize) + { + return initialize(size, mDynamicUsage); + } + else + { + return true; + } +} + +bool VertexBuffer11::discard() +{ + if (mBuffer) + { + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + ERR("Vertex buffer map failed with error 0x%08x", result); + return false; + } + + dxContext->Unmap(mBuffer, 0); + + return true; + } + else + { + ERR("Vertex buffer not initialized."); + return false; + } +} + +ID3D11Buffer *VertexBuffer11::getBuffer() const +{ + return mBuffer; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/VertexBuffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h index eceb426e82..c2a5aa7afd 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/VertexBuffer11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h @@ -9,7 +9,7 @@ #ifndef LIBGLESV2_RENDERER_VERTEXBUFFER11_H_ #define LIBGLESV2_RENDERER_VERTEXBUFFER11_H_ -#include "libGLESv2/renderer/VertexBuffer.h" +#include "libGLESv2/renderer/d3d/VertexBuffer.h" namespace rx { @@ -25,22 +25,16 @@ class VertexBuffer11 : public VertexBuffer static VertexBuffer11 *makeVertexBuffer11(VertexBuffer *vetexBuffer); - virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances, - unsigned int offset); - virtual bool storeRawData(const void* data, unsigned int size, unsigned int offset); + virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset); virtual bool getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const; - virtual bool requiresConversion(const gl::VertexAttribute &attrib) const; - virtual unsigned int getBufferSize() const; virtual bool setBufferSize(unsigned int size); virtual bool discard(); - unsigned int getVertexSize(const gl::VertexAttribute &attrib) const; - DXGI_FORMAT getDXGIFormat(const gl::VertexAttribute &attrib) const; - ID3D11Buffer *getBuffer() const; private: @@ -51,22 +45,6 @@ class VertexBuffer11 : public VertexBuffer ID3D11Buffer *mBuffer; unsigned int mBufferSize; bool mDynamicUsage; - - typedef void (*VertexConversionFunction)(const void *, unsigned int, unsigned int, void *); - struct VertexConverter - { - VertexConversionFunction conversionFunc; - bool identity; - DXGI_FORMAT dxgiFormat; - unsigned int outputElementSize; - }; - - enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 }; - - // This table is used to generate mAttributeTypes. - static const VertexConverter mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1] - - static const VertexConverter &getVertexConversion(const gl::VertexAttribute &attribute); }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp new file mode 100644 index 0000000000..c991fd4991 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp @@ -0,0 +1,1458 @@ +#include "precompiled.h" +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils11.cpp: Queries for GL image formats and their translations to D3D11 +// formats. + +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/renderer/generatemip.h" +#include "libGLESv2/renderer/loadimage.h" +#include "libGLESv2/renderer/copyimage.h" +#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/copyvertex.h" + +namespace rx +{ + +struct D3D11FormatInfo +{ + DXGI_FORMAT mTexFormat; + DXGI_FORMAT mSRVFormat; + DXGI_FORMAT mRTVFormat; + DXGI_FORMAT mDSVFormat; + + D3D11FormatInfo() + : mTexFormat(DXGI_FORMAT_UNKNOWN), mDSVFormat(DXGI_FORMAT_UNKNOWN), mRTVFormat(DXGI_FORMAT_UNKNOWN), mSRVFormat(DXGI_FORMAT_UNKNOWN) + { } + + D3D11FormatInfo(DXGI_FORMAT texFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat) + : mTexFormat(texFormat), mDSVFormat(dsvFormat), mRTVFormat(rtvFormat), mSRVFormat(srvFormat) + { } +}; + +// For sized GL internal formats, there is only one corresponding D3D11 format. This map type allows +// querying for the DXGI texture formats to use for textures, SRVs, RTVs and DSVs given a GL internal +// format. +typedef std::pair<GLenum, D3D11FormatInfo> D3D11ES3FormatPair; +typedef std::map<GLenum, D3D11FormatInfo> D3D11ES3FormatMap; + +static D3D11ES3FormatMap BuildD3D11FormatMap() +{ + D3D11ES3FormatMap map; + + // | GL internal format | | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + map.insert(D3D11ES3FormatPair(GL_NONE, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R8, D3D11FormatInfo(DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R8_SNORM, D3D11FormatInfo(DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG8, D3D11FormatInfo(DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG8_SNORM, D3D11FormatInfo(DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB8, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB8_SNORM, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB565, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA4, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB5_A1, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA8, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA8_SNORM, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB10_A2, D3D11FormatInfo(DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB10_A2UI, D3D11FormatInfo(DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_SRGB8, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_SRGB8_ALPHA8, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R16F, D3D11FormatInfo(DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG16F, D3D11FormatInfo(DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB16F, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA16F, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R32F, D3D11FormatInfo(DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG32F, D3D11FormatInfo(DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB32F, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA32F, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R11F_G11F_B10F, D3D11FormatInfo(DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB9_E5, D3D11FormatInfo(DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R8I, D3D11FormatInfo(DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R8UI, D3D11FormatInfo(DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R16I, D3D11FormatInfo(DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R16UI, D3D11FormatInfo(DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R32I, D3D11FormatInfo(DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_R32UI, D3D11FormatInfo(DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG8I, D3D11FormatInfo(DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG8UI, D3D11FormatInfo(DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG16I, D3D11FormatInfo(DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG16UI, D3D11FormatInfo(DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG32I, D3D11FormatInfo(DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RG32UI, D3D11FormatInfo(DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB8I, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB8UI, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB16I, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB16UI, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB32I, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB32UI, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA8I, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA8UI, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA16I, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA16UI, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA32I, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA32UI, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN))); + + // Unsized formats, TODO: Are types of float and half float allowed for the unsized types? Would it change the DXGI format? + map.insert(D3D11ES3FormatPair(GL_ALPHA, D3D11FormatInfo(DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE_ALPHA, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGB, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_RGBA, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_BGRA_EXT, D3D11FormatInfo(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN))); + + // From GL_EXT_texture_storage + // | GL internal format | | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + map.insert(D3D11ES3FormatPair(GL_ALPHA8_EXT, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE8_EXT, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_ALPHA32F_EXT, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE32F_EXT, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_ALPHA16F_EXT, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE16F_EXT, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE8_ALPHA8_EXT, D3D11FormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE_ALPHA32F_EXT, D3D11FormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_LUMINANCE_ALPHA16F_EXT, D3D11FormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_BGRA8_EXT, D3D11FormatInfo(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_BGRA4_ANGLEX, D3D11FormatInfo(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + map.insert(D3D11ES3FormatPair(GL_BGR5_A1_ANGLEX, D3D11FormatInfo(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ))); + + // Depth stencil formats + map.insert(D3D11ES3FormatPair(GL_DEPTH_COMPONENT16, D3D11FormatInfo(DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM ))); + map.insert(D3D11ES3FormatPair(GL_DEPTH_COMPONENT24, D3D11FormatInfo(DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ))); + map.insert(D3D11ES3FormatPair(GL_DEPTH_COMPONENT32F, D3D11FormatInfo(DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT ))); + map.insert(D3D11ES3FormatPair(GL_DEPTH24_STENCIL8, D3D11FormatInfo(DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ))); + map.insert(D3D11ES3FormatPair(GL_DEPTH32F_STENCIL8, D3D11FormatInfo(DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT_S8X24_UINT))); + map.insert(D3D11ES3FormatPair(GL_STENCIL_INDEX8, D3D11FormatInfo(DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_X24_TYPELESS_G8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ))); + + // From GL_ANGLE_depth_texture + // Since D3D11 doesn't have a D32_UNORM format, use D24S8 which has comparable precision and matches the ES3 format. + map.insert(D3D11ES3FormatPair(GL_DEPTH_COMPONENT32_OES, D3D11FormatInfo(DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ))); + + // Compressed formats, From ES 3.0.1 spec, table 3.16 + // | GL internal format | | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_R11_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_SIGNED_R11_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RG11_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_SIGNED_RG11_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGB8_ETC2, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_SRGB8_ETC2, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGBA8_ETC2_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, D3D11FormatInfo(DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + + // From GL_EXT_texture_compression_dxt1 + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, D3D11FormatInfo(DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, D3D11FormatInfo(DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + + // From GL_ANGLE_texture_compression_dxt3 + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, D3D11FormatInfo(DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + + // From GL_ANGLE_texture_compression_dxt5 + map.insert(D3D11ES3FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, D3D11FormatInfo(DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN))); + + return map; +} + +static bool GetD3D11FormatInfo(GLenum internalFormat, D3D11FormatInfo *outFormatInfo) +{ + static const D3D11ES3FormatMap formatMap = BuildD3D11FormatMap(); + D3D11ES3FormatMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + if (outFormatInfo) + { + *outFormatInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +// ES3 image loading functions vary based on the internal format and data type given, +// this map type determines the loading function from the internal format and type supplied +// to glTex*Image*D and the destination DXGI_FORMAT. Source formats and types are taken from +// Tables 3.2 and 3.3 of the ES 3 spec. +typedef std::pair<GLenum, GLenum> InternalFormatTypePair; +typedef std::pair<InternalFormatTypePair, LoadImageFunction> D3D11LoadFunctionPair; +typedef std::map<InternalFormatTypePair, LoadImageFunction> D3D11LoadFunctionMap; + +static void UnimplementedLoadFunction(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + UNIMPLEMENTED(); +} + +static void UnreachableLoadFunction(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + UNREACHABLE(); +} + +// A helper function to insert data into the D3D11LoadFunctionMap with fewer characters. +static inline void insertLoadFunction(D3D11LoadFunctionMap *map, GLenum internalFormat, GLenum type, + LoadImageFunction loadFunc) +{ + map->insert(D3D11LoadFunctionPair(InternalFormatTypePair(internalFormat, type), loadFunc)); +} + +D3D11LoadFunctionMap buildD3D11LoadFunctionMap() +{ + D3D11LoadFunctionMap map; + + // | Internal format | Type | Load function | + insertLoadFunction(&map, GL_RGBA8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_SRGB8_ALPHA8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_RGBA8_SNORM, GL_BYTE, LoadToNative<GLbyte, 4> ); + insertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, LoadRGBA4ToRGBA8 ); + insertLoadFunction(&map, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative<GLuint, 1> ); + insertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1, LoadRGB5A1ToRGBA8 ); + insertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_INT_2_10_10_10_REV, LoadRGB10A2ToRGBA8 ); + insertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT, LoadToNative<GLhalf, 4> ); + insertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT_OES, LoadToNative<GLhalf, 4> ); + insertLoadFunction(&map, GL_RGBA32F, GL_FLOAT, LoadToNative<GLfloat, 4> ); + insertLoadFunction(&map, GL_RGBA16F, GL_FLOAT, Load32FTo16F<4> ); + insertLoadFunction(&map, GL_RGBA8UI, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_RGBA8I, GL_BYTE, LoadToNative<GLbyte, 4> ); + insertLoadFunction(&map, GL_RGBA16UI, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 4> ); + insertLoadFunction(&map, GL_RGBA16I, GL_SHORT, LoadToNative<GLshort, 4> ); + insertLoadFunction(&map, GL_RGBA32UI, GL_UNSIGNED_INT, LoadToNative<GLuint, 4> ); + insertLoadFunction(&map, GL_RGBA32I, GL_INT, LoadToNative<GLint, 4> ); + insertLoadFunction(&map, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative<GLuint, 1> ); + insertLoadFunction(&map, GL_RGB8, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0xFF> ); + insertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0xFF> ); + insertLoadFunction(&map, GL_SRGB8, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0xFF> ); + insertLoadFunction(&map, GL_RGB8_SNORM, GL_BYTE, LoadToNative3To4<GLbyte, 0x7F> ); + insertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5, LoadR5G6B5ToRGBA8 ); + insertLoadFunction(&map, GL_R11F_G11F_B10F, GL_UNSIGNED_INT_10F_11F_11F_REV, LoadToNative<GLuint, 1> ); + insertLoadFunction(&map, GL_RGB9_E5, GL_UNSIGNED_INT_5_9_9_9_REV, LoadToNative<GLuint, 1> ); + insertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT, LoadToNative3To4<GLhalf, gl::Float16One>); + insertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT_OES, LoadToNative3To4<GLhalf, gl::Float16One>); + insertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT, LoadRGB16FToRG11B10F ); + insertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT_OES, LoadRGB16FToRG11B10F ); + insertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT, LoadRGB16FToRGB9E5 ); + insertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT_OES, LoadRGB16FToRGB9E5 ); + insertLoadFunction(&map, GL_RGB32F, GL_FLOAT, LoadToNative3To4<GLfloat, gl::Float32One>); + insertLoadFunction(&map, GL_RGB16F, GL_FLOAT, LoadRGB32FToRGBA16F ); + insertLoadFunction(&map, GL_R11F_G11F_B10F, GL_FLOAT, LoadRGB32FToRG11B10F ); + insertLoadFunction(&map, GL_RGB9_E5, GL_FLOAT, LoadRGB32FToRGB9E5 ); + insertLoadFunction(&map, GL_RGB8UI, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0x01> ); + insertLoadFunction(&map, GL_RGB8I, GL_BYTE, LoadToNative3To4<GLbyte, 0x01> ); + insertLoadFunction(&map, GL_RGB16UI, GL_UNSIGNED_SHORT, LoadToNative3To4<GLushort, 0x0001> ); + insertLoadFunction(&map, GL_RGB16I, GL_SHORT, LoadToNative3To4<GLshort, 0x0001> ); + insertLoadFunction(&map, GL_RGB32UI, GL_UNSIGNED_INT, LoadToNative3To4<GLuint, 0x00000001> ); + insertLoadFunction(&map, GL_RGB32I, GL_INT, LoadToNative3To4<GLint, 0x00000001> ); + insertLoadFunction(&map, GL_RG8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 2> ); + insertLoadFunction(&map, GL_RG8_SNORM, GL_BYTE, LoadToNative<GLbyte, 2> ); + insertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT, LoadToNative<GLhalf, 2> ); + insertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT_OES, LoadToNative<GLhalf, 2> ); + insertLoadFunction(&map, GL_RG32F, GL_FLOAT, LoadToNative<GLfloat, 2> ); + insertLoadFunction(&map, GL_RG16F, GL_FLOAT, Load32FTo16F<2> ); + insertLoadFunction(&map, GL_RG8UI, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 2> ); + insertLoadFunction(&map, GL_RG8I, GL_BYTE, LoadToNative<GLbyte, 2> ); + insertLoadFunction(&map, GL_RG16UI, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 2> ); + insertLoadFunction(&map, GL_RG16I, GL_SHORT, LoadToNative<GLshort, 2> ); + insertLoadFunction(&map, GL_RG32UI, GL_UNSIGNED_INT, LoadToNative<GLuint, 2> ); + insertLoadFunction(&map, GL_RG32I, GL_INT, LoadToNative<GLint, 2> ); + insertLoadFunction(&map, GL_R8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 1> ); + insertLoadFunction(&map, GL_R8_SNORM, GL_BYTE, LoadToNative<GLbyte, 1> ); + insertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT, LoadToNative<GLhalf, 1> ); + insertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT_OES, LoadToNative<GLhalf, 1> ); + insertLoadFunction(&map, GL_R32F, GL_FLOAT, LoadToNative<GLfloat, 1> ); + insertLoadFunction(&map, GL_R16F, GL_FLOAT, Load32FTo16F<1> ); + insertLoadFunction(&map, GL_R8UI, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 1> ); + insertLoadFunction(&map, GL_R8I, GL_BYTE, LoadToNative<GLbyte, 1> ); + insertLoadFunction(&map, GL_R16UI, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 1> ); + insertLoadFunction(&map, GL_R16I, GL_SHORT, LoadToNative<GLshort, 1> ); + insertLoadFunction(&map, GL_R32UI, GL_UNSIGNED_INT, LoadToNative<GLuint, 1> ); + insertLoadFunction(&map, GL_R32I, GL_INT, LoadToNative<GLint, 1> ); + insertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 1> ); + insertLoadFunction(&map, GL_DEPTH_COMPONENT24, GL_UNSIGNED_INT, LoadR32ToR24G8 ); + insertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_INT, LoadR32ToR16 ); + insertLoadFunction(&map, GL_DEPTH_COMPONENT32F, GL_FLOAT, LoadToNative<GLfloat, 1> ); + insertLoadFunction(&map, GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8, LoadR32ToR24G8 ); + insertLoadFunction(&map, GL_DEPTH32F_STENCIL8, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, LoadToNative<GLuint, 2> ); + + // Unsized formats + // Load functions are unreachable because they are converted to sized internal formats based on + // the format and type before loading takes place. + insertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_RGB, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + insertLoadFunction(&map, GL_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + + // From GL_OES_texture_float + insertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, LoadLA32FToRGBA32F ); + insertLoadFunction(&map, GL_LUMINANCE, GL_FLOAT, LoadL32FToRGBA32F ); + insertLoadFunction(&map, GL_ALPHA, GL_FLOAT, LoadA32FToRGBA32F ); + + // From GL_OES_texture_half_float + insertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, LoadLA16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT, LoadL16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F ); + insertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT, LoadA16FToRGBA16F ); + insertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); + + // From GL_EXT_texture_storage + insertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadA8ToBGRA8 ); + insertLoadFunction(&map, GL_LUMINANCE8_EXT, GL_UNSIGNED_BYTE, LoadL8ToRGBA8 ); + insertLoadFunction(&map, GL_LUMINANCE8_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadLA8ToRGBA8 ); + insertLoadFunction(&map, GL_ALPHA32F_EXT, GL_FLOAT, LoadA32FToRGBA32F ); + insertLoadFunction(&map, GL_LUMINANCE32F_EXT, GL_FLOAT, LoadL32FToRGBA32F ); + insertLoadFunction(&map, GL_LUMINANCE_ALPHA32F_EXT, GL_FLOAT, LoadLA32FToRGBA32F ); + insertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT, LoadA16FToRGBA16F ); + insertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT, LoadL16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT, LoadLA16FToRGBA16F ); + insertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F ); + + // From GL_ANGLE_depth_texture + insertLoadFunction(&map, GL_DEPTH_COMPONENT32_OES, GL_UNSIGNED_INT, LoadR32ToR24G8 ); + + // From GL_EXT_texture_format_BGRA8888 + insertLoadFunction(&map, GL_BGRA8_EXT, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, LoadRGBA4ToRGBA8 ); + insertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + insertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, LoadRGB5A1ToRGBA8 ); + insertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> ); + + // Compressed formats + // From ES 3.0.1 spec, table 3.16 + // | Internal format | Type | Load function | + insertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + insertLoadFunction(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + + // From GL_EXT_texture_compression_dxt1 + insertLoadFunction(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>); + insertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>); + + // From GL_ANGLE_texture_compression_dxt3 + insertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>); + + // From GL_ANGLE_texture_compression_dxt5 + insertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>); + + return map; +} + +// A map to determine the pixel size and mipmap generation function of a given DXGI format +struct DXGIFormatInfo +{ + GLuint mPixelBits; + GLuint mBlockWidth; + GLuint mBlockHeight; + GLenum mComponentType; + + MipGenerationFunction mMipGenerationFunction; + ColorReadFunction mColorReadFunction; + + DXGIFormatInfo() + : mPixelBits(0), mBlockWidth(0), mBlockHeight(0), mComponentType(GL_NONE), mMipGenerationFunction(NULL), + mColorReadFunction(NULL) + { } + + DXGIFormatInfo(GLuint pixelBits, GLuint blockWidth, GLuint blockHeight, GLenum componentType, + MipGenerationFunction mipFunc, ColorReadFunction readFunc) + : mPixelBits(pixelBits), mBlockWidth(blockWidth), mBlockHeight(blockHeight), mComponentType(componentType), + mMipGenerationFunction(mipFunc), mColorReadFunction(readFunc) + { } +}; + +typedef std::map<DXGI_FORMAT, DXGIFormatInfo> DXGIFormatInfoMap; + +void AddDXGIFormat(DXGIFormatInfoMap *map, DXGI_FORMAT dxgiFormat, GLuint pixelBits, GLuint blockWidth, GLuint blockHeight, + GLenum componentType, MipGenerationFunction mipFunc, ColorReadFunction readFunc) +{ + map->insert(std::make_pair(dxgiFormat, DXGIFormatInfo(pixelBits, blockWidth, blockHeight, componentType, mipFunc, readFunc))); +} + +static DXGIFormatInfoMap BuildDXGIFormatInfoMap() +{ + DXGIFormatInfoMap map; + + // | DXGI format |S |W |H |Component Type | Mip generation function | Color read function + AddDXGIFormat(&map, DXGI_FORMAT_UNKNOWN, 0, 0, 0, GL_NONE, NULL, NULL); + + AddDXGIFormat(&map, DXGI_FORMAT_A8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<A8>, ReadColor<A8, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8>, ReadColor<R8, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8>, ReadColor<R8G8, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<B8G8R8A8>, ReadColor<B8G8R8A8, GLfloat>); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_SNORM, 8, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8S>, ReadColor<R8S, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8G8S>, ReadColor<R8G8S, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8G8B8A8S>, ReadColor<R8G8B8A8S, GLfloat>); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_UINT, 8, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8>, ReadColor<R8, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16>, ReadColor<R16, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32>, ReadColor<R32, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8G8>, ReadColor<R8G8, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16G16>, ReadColor<R16G16, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32>, ReadColor<R32G32, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_UINT, 96, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32B32>, ReadColor<R32G32B32, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16G16B16A16>, ReadColor<R16G16B16A16, GLuint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_UINT, 128, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32B32A32>, ReadColor<R32G32B32A32, GLuint>); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_SINT, 8, 1, 1, GL_INT, GenerateMip<R8S>, ReadColor<R8S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16_SINT, 16, 1, 1, GL_INT, GenerateMip<R16S>, ReadColor<R16S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32_SINT, 32, 1, 1, GL_INT, GenerateMip<R32S>, ReadColor<R32S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SINT, 16, 1, 1, GL_INT, GenerateMip<R8G8S>, ReadColor<R8G8S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SINT, 32, 1, 1, GL_INT, GenerateMip<R16G16S>, ReadColor<R16G16S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_SINT, 64, 1, 1, GL_INT, GenerateMip<R32G32S>, ReadColor<R32G32S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_SINT, 96, 1, 1, GL_INT, GenerateMip<R32G32B32S>, ReadColor<R32G32B32S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SINT, 32, 1, 1, GL_INT, GenerateMip<R8G8B8A8S>, ReadColor<R8G8B8A8S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SINT, 64, 1, 1, GL_INT, GenerateMip<R16G16B16A16S>, ReadColor<R16G16B16A16S, GLint>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_SINT, 128, 1, 1, GL_INT, GenerateMip<R32G32B32A32S>, ReadColor<R32G32B32A32S, GLint>); + + AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R10G10B10A2>, ReadColor<R10G10B10A2, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R10G10B10A2>, ReadColor<R10G10B10A2, GLuint>); + + AddDXGIFormat(&map, DXGI_FORMAT_R16_FLOAT, 16, 1, 1, GL_FLOAT, GenerateMip<R16F>, ReadColor<R16F, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R16G16F>, ReadColor<R16G16F, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip<R16G16B16A16F>, ReadColor<R16G16B16A16F, GLfloat>); + + AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R32F>, ReadColor<R32F, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip<R32G32F>, ReadColor<R32G32F, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_FLOAT, 96, 1, 1, GL_FLOAT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, 128, 1, 1, GL_FLOAT, GenerateMip<R32G32B32A32F>, ReadColor<R32G32B32A32F, GLfloat>); + + AddDXGIFormat(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 32, 1, 1, GL_FLOAT, GenerateMip<R9G9B9E5>, ReadColor<R9G9B9E5, GLfloat>); + AddDXGIFormat(&map, DXGI_FORMAT_R11G11B10_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R11G11B10F>, ReadColor<R11G11B10F, GLfloat>); + + AddDXGIFormat(&map, DXGI_FORMAT_R16_TYPELESS, 16, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R24G8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 32, 1, 1, GL_UNSIGNED_INT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 64, 1, 1, GL_UNSIGNED_INT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT, 32, 1, 1, GL_FLOAT, NULL, NULL); + + AddDXGIFormat(&map, DXGI_FORMAT_BC1_UNORM, 64, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_BC2_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_BC3_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + + // Useful formats for vertex buffers + AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UNORM, 64, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SNORM, 64, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + + return map; +} + +typedef std::map<DXGI_FORMAT, GLenum> DXGIToESFormatMap; + +inline void AddDXGIToESEntry(DXGIToESFormatMap *map, DXGI_FORMAT key, GLenum value) +{ + map->insert(std::make_pair(key, value)); +} + +static DXGIToESFormatMap BuildDXGIToESFormatMap() +{ + DXGIToESFormatMap map; + + AddDXGIToESEntry(&map, DXGI_FORMAT_UNKNOWN, GL_NONE); + + AddDXGIToESEntry(&map, DXGI_FORMAT_A8_UNORM, GL_ALPHA8_EXT); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UNORM, GL_R8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UNORM, GL_RG8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM, GL_RGBA8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, GL_SRGB8_ALPHA8); + AddDXGIToESEntry(&map, DXGI_FORMAT_B8G8R8A8_UNORM, GL_BGRA8_EXT); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SNORM, GL_R8_SNORM); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SNORM, GL_RG8_SNORM); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SNORM, GL_RGBA8_SNORM); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UINT, GL_R8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UINT, GL_R16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_UINT, GL_R32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UINT, GL_RG8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_UINT, GL_RG16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_UINT, GL_RG32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_UINT, GL_RGB32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UINT, GL_RGBA8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_UINT, GL_RGBA16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_UINT, GL_RGBA32UI); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SINT, GL_R8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_SINT, GL_R16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_SINT, GL_R32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SINT, GL_RG8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_SINT, GL_RG16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_SINT, GL_RG32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_SINT, GL_RGB32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SINT, GL_RGBA8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_SINT, GL_RGBA16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_SINT, GL_RGBA32I); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UNORM, GL_RGB10_A2); + AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UINT, GL_RGB10_A2UI); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_FLOAT, GL_R16F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_FLOAT, GL_RG16F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, GL_RGBA16F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT, GL_R32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_FLOAT, GL_RG32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_FLOAT, GL_RGB32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, GL_RGBA32F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, GL_RGB9_E5); + AddDXGIToESEntry(&map, DXGI_FORMAT_R11G11B10_FLOAT, GL_R11F_G11F_B10F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_TYPELESS, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UNORM, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_D16_UNORM, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_R24G8_TYPELESS, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G8X24_TYPELESS, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_TYPELESS, GL_DEPTH_COMPONENT32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT, GL_DEPTH_COMPONENT32F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_BC1_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + AddDXGIToESEntry(&map, DXGI_FORMAT_BC2_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + AddDXGIToESEntry(&map, DXGI_FORMAT_BC3_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + + return map; +} + +static const DXGIToESFormatMap &GetDXGIToESFormatMap() +{ + static const DXGIToESFormatMap map = BuildDXGIToESFormatMap(); + return map; +} + +static const DXGIFormatInfoMap &GetDXGIFormatInfoMap() +{ + static const DXGIFormatInfoMap infoMap = BuildDXGIFormatInfoMap(); + return infoMap; +} + +static bool GetDXGIFormatInfo(DXGI_FORMAT format, DXGIFormatInfo *outFormatInfo) +{ + const DXGIFormatInfoMap &infoMap = GetDXGIFormatInfoMap(); + DXGIFormatInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + if (outFormatInfo) + { + *outFormatInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +static d3d11::DXGIFormatSet BuildAllDXGIFormatSet() +{ + d3d11::DXGIFormatSet set; + + const DXGIFormatInfoMap &infoMap = GetDXGIFormatInfoMap(); + for (DXGIFormatInfoMap::const_iterator i = infoMap.begin(); i != infoMap.end(); ++i) + { + set.insert(i->first); + } + + return set; +} + +struct D3D11FastCopyFormat +{ + DXGI_FORMAT mSourceFormat; + GLenum mDestFormat; + GLenum mDestType; + + D3D11FastCopyFormat(DXGI_FORMAT sourceFormat, GLenum destFormat, GLenum destType) + : mSourceFormat(sourceFormat), mDestFormat(destFormat), mDestType(destType) + { } + + bool operator<(const D3D11FastCopyFormat& other) const + { + return memcmp(this, &other, sizeof(D3D11FastCopyFormat)) < 0; + } +}; + +typedef std::map<D3D11FastCopyFormat, ColorCopyFunction> D3D11FastCopyMap; +typedef std::pair<D3D11FastCopyFormat, ColorCopyFunction> D3D11FastCopyPair; + +static D3D11FastCopyMap BuildFastCopyMap() +{ + D3D11FastCopyMap map; + + map.insert(D3D11FastCopyPair(D3D11FastCopyFormat(DXGI_FORMAT_B8G8R8A8_UNORM, GL_RGBA, GL_UNSIGNED_BYTE), CopyBGRAUByteToRGBAUByte)); + + return map; +} + +struct DXGIDepthStencilInfo +{ + unsigned int mDepthBits; + unsigned int mDepthOffset; + unsigned int mStencilBits; + unsigned int mStencilOffset; + + DXGIDepthStencilInfo() + : mDepthBits(0), mDepthOffset(0), mStencilBits(0), mStencilOffset(0) + { } + + DXGIDepthStencilInfo(unsigned int depthBits, unsigned int depthOffset, unsigned int stencilBits, unsigned int stencilOffset) + : mDepthBits(depthBits), mDepthOffset(depthOffset), mStencilBits(stencilBits), mStencilOffset(stencilOffset) + { } +}; + +typedef std::map<DXGI_FORMAT, DXGIDepthStencilInfo> DepthStencilInfoMap; +typedef std::pair<DXGI_FORMAT, DXGIDepthStencilInfo> DepthStencilInfoPair; + +static DepthStencilInfoMap BuildDepthStencilInfoMap() +{ + DepthStencilInfoMap map; + + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R16_TYPELESS, DXGIDepthStencilInfo(16, 0, 0, 0))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R16_UNORM, DXGIDepthStencilInfo(16, 0, 0, 0))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_D16_UNORM, DXGIDepthStencilInfo(16, 0, 0, 0))); + + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R24G8_TYPELESS, DXGIDepthStencilInfo(24, 0, 8, 24))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGIDepthStencilInfo(24, 0, 8, 24))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_D24_UNORM_S8_UINT, DXGIDepthStencilInfo(24, 0, 8, 24))); + + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R32_TYPELESS, DXGIDepthStencilInfo(32, 0, 0, 0))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R32_FLOAT, DXGIDepthStencilInfo(32, 0, 0, 0))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_D32_FLOAT, DXGIDepthStencilInfo(32, 0, 0, 0))); + + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R32G8X24_TYPELESS, DXGIDepthStencilInfo(32, 0, 8, 32))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGIDepthStencilInfo(32, 0, 8, 32))); + map.insert(DepthStencilInfoPair(DXGI_FORMAT_D32_FLOAT_S8X24_UINT, DXGIDepthStencilInfo(32, 0, 8, 32))); + + return map; +} + +static const DepthStencilInfoMap &GetDepthStencilInfoMap() +{ + static const DepthStencilInfoMap infoMap = BuildDepthStencilInfoMap(); + return infoMap; +} + +bool GetDepthStencilInfo(DXGI_FORMAT format, DXGIDepthStencilInfo *outDepthStencilInfo) +{ + const DepthStencilInfoMap& infoMap = GetDepthStencilInfoMap(); + DepthStencilInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + if (outDepthStencilInfo) + { + *outDepthStencilInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +struct SwizzleSizeType +{ + unsigned int mMaxComponentSize; + GLenum mComponentType; + + SwizzleSizeType() + : mMaxComponentSize(0), mComponentType(GL_NONE) + { } + + SwizzleSizeType(unsigned int maxComponentSize, GLenum componentType) + : mMaxComponentSize(maxComponentSize), mComponentType(componentType) + { } + + bool operator<(const SwizzleSizeType& other) const + { + return (mMaxComponentSize != other.mMaxComponentSize) ? (mMaxComponentSize < other.mMaxComponentSize) + : (mComponentType < other.mComponentType); + } +}; + +struct SwizzleFormatInfo +{ + DXGI_FORMAT mTexFormat; + DXGI_FORMAT mSRVFormat; + DXGI_FORMAT mRTVFormat; + + SwizzleFormatInfo() + : mTexFormat(DXGI_FORMAT_UNKNOWN), mSRVFormat(DXGI_FORMAT_UNKNOWN), mRTVFormat(DXGI_FORMAT_UNKNOWN) + { } + + SwizzleFormatInfo(DXGI_FORMAT texFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat) + : mTexFormat(texFormat), mSRVFormat(srvFormat), mRTVFormat(rtvFormat) + { } +}; + +typedef std::map<SwizzleSizeType, SwizzleFormatInfo> SwizzleInfoMap; +typedef std::pair<SwizzleSizeType, SwizzleFormatInfo> SwizzleInfoPair; + +static SwizzleInfoMap BuildSwizzleInfoMap() +{ + SwizzleInfoMap map; + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM))); + map.insert(SwizzleInfoPair(SwizzleSizeType(24, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_SIGNED_NORMALIZED ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM ))); + + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT ))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT ))); + + return map; +} +typedef std::pair<GLint, InitializeTextureDataFunction> InternalFormatInitializerPair; +typedef std::map<GLint, InitializeTextureDataFunction> InternalFormatInitializerMap; + +static InternalFormatInitializerMap BuildInternalFormatInitializerMap() +{ + InternalFormatInitializerMap map; + + map.insert(InternalFormatInitializerPair(GL_RGB8, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF> )); + map.insert(InternalFormatInitializerPair(GL_RGB565, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF> )); + map.insert(InternalFormatInitializerPair(GL_SRGB8, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF> )); + map.insert(InternalFormatInitializerPair(GL_RGB16F, Initialize4ComponentData<GLhalf, 0x0000, 0x0000, 0x0000, gl::Float16One>)); + map.insert(InternalFormatInitializerPair(GL_RGB32F, Initialize4ComponentData<GLfloat, 0x00000000, 0x00000000, 0x00000000, gl::Float32One>)); + map.insert(InternalFormatInitializerPair(GL_RGB8UI, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0x01> )); + map.insert(InternalFormatInitializerPair(GL_RGB8I, Initialize4ComponentData<GLbyte, 0x00, 0x00, 0x00, 0x01> )); + map.insert(InternalFormatInitializerPair(GL_RGB16UI, Initialize4ComponentData<GLushort, 0x0000, 0x0000, 0x0000, 0x0001> )); + map.insert(InternalFormatInitializerPair(GL_RGB16I, Initialize4ComponentData<GLshort, 0x0000, 0x0000, 0x0000, 0x0001> )); + map.insert(InternalFormatInitializerPair(GL_RGB32UI, Initialize4ComponentData<GLuint, 0x00000000, 0x00000000, 0x00000000, 0x00000001> )); + map.insert(InternalFormatInitializerPair(GL_RGB32I, Initialize4ComponentData<GLint, 0x00000000, 0x00000000, 0x00000000, 0x00000001> )); + + return map; +} + +static const SwizzleInfoMap &GetSwizzleInfoMap() +{ + static const SwizzleInfoMap map = BuildSwizzleInfoMap(); + return map; +} + +static const SwizzleFormatInfo GetSwizzleFormatInfo(GLenum internalFormat) +{ + // Get the maximum sized component + unsigned int maxBits = 1; + + if (gl::IsFormatCompressed(internalFormat)) + { + unsigned int compressedBitsPerBlock = gl::GetPixelBytes(internalFormat) * 8; + unsigned int blockSize = gl::GetCompressedBlockWidth(internalFormat) * + gl::GetCompressedBlockHeight(internalFormat); + maxBits = std::max(compressedBitsPerBlock / blockSize, maxBits); + } + else + { + maxBits = std::max(maxBits, gl::GetAlphaBits( internalFormat)); + maxBits = std::max(maxBits, gl::GetRedBits( internalFormat)); + maxBits = std::max(maxBits, gl::GetGreenBits( internalFormat)); + maxBits = std::max(maxBits, gl::GetBlueBits( internalFormat)); + maxBits = std::max(maxBits, gl::GetLuminanceBits(internalFormat)); + maxBits = std::max(maxBits, gl::GetDepthBits( internalFormat)); + } + + maxBits = roundUp(maxBits, 8U); + + GLenum componentType = gl::GetComponentType(internalFormat); + + const SwizzleInfoMap &map = GetSwizzleInfoMap(); + SwizzleInfoMap::const_iterator iter = map.find(SwizzleSizeType(maxBits, componentType)); + + if (iter != map.end()) + { + return iter->second; + } + else + { + UNREACHABLE(); + static const SwizzleFormatInfo defaultFormatInfo; + return defaultFormatInfo; + } +} + +static const InternalFormatInitializerMap &GetInternalFormatInitializerMap() +{ + static const InternalFormatInitializerMap map = BuildInternalFormatInitializerMap(); + return map; +} + +namespace d3d11 +{ + +MipGenerationFunction GetMipGenerationFunction(DXGI_FORMAT format) +{ + DXGIFormatInfo formatInfo; + if (GetDXGIFormatInfo(format, &formatInfo)) + { + return formatInfo.mMipGenerationFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +LoadImageFunction GetImageLoadFunction(GLenum internalFormat, GLenum type) +{ + static const D3D11LoadFunctionMap loadImageMap = buildD3D11LoadFunctionMap(); + D3D11LoadFunctionMap::const_iterator iter = loadImageMap.find(InternalFormatTypePair(internalFormat, type)); + if (iter != loadImageMap.end()) + { + return iter->second; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +GLuint GetFormatPixelBytes(DXGI_FORMAT format) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + return dxgiFormatInfo.mPixelBits / 8; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetBlockWidth(DXGI_FORMAT format) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + return dxgiFormatInfo.mBlockWidth; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetBlockHeight(DXGI_FORMAT format) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + return dxgiFormatInfo.mBlockHeight; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLenum GetComponentType(DXGI_FORMAT format) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + return dxgiFormatInfo.mComponentType; + } + else + { + UNREACHABLE(); + return GL_NONE; + } +} + +GLuint GetDepthBits(DXGI_FORMAT format) +{ + DXGIDepthStencilInfo dxgiDSInfo; + if (GetDepthStencilInfo(format, &dxgiDSInfo)) + { + return dxgiDSInfo.mDepthBits; + } + else + { + // Since the depth stencil info map does not contain all used DXGI formats, + // we should not assert that the format exists + return 0; + } +} + +GLuint GetDepthOffset(DXGI_FORMAT format) +{ + DXGIDepthStencilInfo dxgiDSInfo; + if (GetDepthStencilInfo(format, &dxgiDSInfo)) + { + return dxgiDSInfo.mDepthOffset; + } + else + { + // Since the depth stencil info map does not contain all used DXGI formats, + // we should not assert that the format exists + return 0; + } +} + +GLuint GetStencilBits(DXGI_FORMAT format) +{ + DXGIDepthStencilInfo dxgiDSInfo; + if (GetDepthStencilInfo(format, &dxgiDSInfo)) + { + return dxgiDSInfo.mStencilBits; + } + else + { + // Since the depth stencil info map does not contain all used DXGI formats, + // we should not assert that the format exists + return 0; + } +} + +GLuint GetStencilOffset(DXGI_FORMAT format) +{ + DXGIDepthStencilInfo dxgiDSInfo; + if (GetDepthStencilInfo(format, &dxgiDSInfo)) + { + return dxgiDSInfo.mStencilOffset; + } + else + { + // Since the depth stencil info map does not contain all used DXGI formats, + // we should not assert that the format exists + return 0; + } +} + +void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + int upsampleCount = 0; + + GLsizei blockWidth = dxgiFormatInfo.mBlockWidth; + GLsizei blockHeight = dxgiFormatInfo.mBlockHeight; + + // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. + if (isImage || *requestWidth < blockWidth || *requestHeight < blockHeight) + { + while (*requestWidth % blockWidth != 0 || *requestHeight % blockHeight != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + *levelOffset = upsampleCount; + } + else + { + UNREACHABLE(); + } +} + +const DXGIFormatSet &GetAllUsedDXGIFormats() +{ + static DXGIFormatSet formatSet = BuildAllDXGIFormatSet(); + return formatSet; +} + +ColorReadFunction GetColorReadFunction(DXGI_FORMAT format) +{ + DXGIFormatInfo dxgiFormatInfo; + if (GetDXGIFormatInfo(format, &dxgiFormatInfo)) + { + return dxgiFormatInfo.mColorReadFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +ColorCopyFunction GetFastCopyFunction(DXGI_FORMAT sourceFormat, GLenum destFormat, GLenum destType) +{ + static const D3D11FastCopyMap fastCopyMap = BuildFastCopyMap(); + D3D11FastCopyMap::const_iterator iter = fastCopyMap.find(D3D11FastCopyFormat(sourceFormat, destFormat, destType)); + return (iter != fastCopyMap.end()) ? iter->second : NULL; +} + +} + +namespace gl_d3d11 +{ + +DXGI_FORMAT GetTexFormat(GLenum internalFormat) +{ + D3D11FormatInfo d3d11FormatInfo; + if (GetD3D11FormatInfo(internalFormat, &d3d11FormatInfo)) + { + return d3d11FormatInfo.mTexFormat; + } + else + { + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } +} + +DXGI_FORMAT GetSRVFormat(GLenum internalFormat) +{ + D3D11FormatInfo d3d11FormatInfo; + if (GetD3D11FormatInfo(internalFormat, &d3d11FormatInfo)) + { + return d3d11FormatInfo.mSRVFormat; + } + else + { + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } +} + +DXGI_FORMAT GetRTVFormat(GLenum internalFormat) +{ + D3D11FormatInfo d3d11FormatInfo; + if (GetD3D11FormatInfo(internalFormat, &d3d11FormatInfo)) + { + return d3d11FormatInfo.mRTVFormat; + } + else + { + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } +} + +DXGI_FORMAT GetDSVFormat(GLenum internalFormat) +{ + D3D11FormatInfo d3d11FormatInfo; + if (GetD3D11FormatInfo(internalFormat, &d3d11FormatInfo)) + { + return d3d11FormatInfo.mDSVFormat; + } + else + { + return DXGI_FORMAT_UNKNOWN; + } +} + +// Given a GL internal format, this function returns the DSV format if it is depth- or stencil-renderable, +// the RTV format if it is color-renderable, and the (nonrenderable) texture format otherwise. +DXGI_FORMAT GetRenderableFormat(GLenum internalFormat) +{ + DXGI_FORMAT targetFormat = GetDSVFormat(internalFormat); + if (targetFormat == DXGI_FORMAT_UNKNOWN) + targetFormat = GetRTVFormat(internalFormat); + if (targetFormat == DXGI_FORMAT_UNKNOWN) + targetFormat = GetTexFormat(internalFormat); + + return targetFormat; +} + +DXGI_FORMAT GetSwizzleTexFormat(GLint internalFormat) +{ + if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetComponentCount(internalFormat) != 4) + { + const SwizzleFormatInfo &swizzleInfo = GetSwizzleFormatInfo(internalFormat); + return swizzleInfo.mTexFormat; + } + else + { + return GetTexFormat(internalFormat); + } +} + +DXGI_FORMAT GetSwizzleSRVFormat(GLint internalFormat) +{ + if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetComponentCount(internalFormat) != 4) + { + const SwizzleFormatInfo &swizzleInfo = GetSwizzleFormatInfo(internalFormat); + return swizzleInfo.mSRVFormat; + } + else + { + return GetSRVFormat(internalFormat); + } +} + +DXGI_FORMAT GetSwizzleRTVFormat(GLint internalFormat) +{ + if (GetRTVFormat(internalFormat) == DXGI_FORMAT_UNKNOWN || gl::GetComponentCount(internalFormat) != 4) + { + const SwizzleFormatInfo &swizzleInfo = GetSwizzleFormatInfo(internalFormat); + return swizzleInfo.mRTVFormat; + } + else + { + return GetRTVFormat(internalFormat); + } +} + +bool RequiresTextureDataInitialization(GLint internalFormat) +{ + const InternalFormatInitializerMap &map = GetInternalFormatInitializerMap(); + return map.find(internalFormat) != map.end(); +} + +InitializeTextureDataFunction GetTextureDataInitializationFunction(GLint internalFormat) +{ + const InternalFormatInitializerMap &map = GetInternalFormatInitializerMap(); + InternalFormatInitializerMap::const_iterator iter = map.find(internalFormat); + if (iter != map.end()) + { + return iter->second; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +struct D3D11VertexFormatInfo +{ + rx::VertexConversionType mConversionType; + DXGI_FORMAT mNativeFormat; + VertexCopyFunction mCopyFunction; + + D3D11VertexFormatInfo() + : mConversionType(VERTEX_CONVERT_NONE), + mNativeFormat(DXGI_FORMAT_UNKNOWN), + mCopyFunction(NULL) + {} + + D3D11VertexFormatInfo(VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) + : mConversionType(conversionType), + mNativeFormat(nativeFormat), + mCopyFunction(copyFunction) + {} +}; + +typedef std::map<gl::VertexFormat, D3D11VertexFormatInfo> D3D11VertexFormatInfoMap; + +typedef std::pair<gl::VertexFormat, D3D11VertexFormatInfo> D3D11VertexFormatPair; + +static void addVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLboolean normalized, GLuint componentCount, + VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) +{ + gl::VertexFormat inputFormat(inputType, normalized, componentCount, false); + map->insert(D3D11VertexFormatPair(inputFormat, D3D11VertexFormatInfo(conversionType, nativeFormat, copyFunction))); +} + +static void addIntegerVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLuint componentCount, + VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) +{ + gl::VertexFormat inputFormat(inputType, GL_FALSE, componentCount, true); + map->insert(D3D11VertexFormatPair(inputFormat, D3D11VertexFormatInfo(conversionType, nativeFormat, copyFunction))); +} + +static D3D11VertexFormatInfoMap BuildD3D11VertexFormatInfoMap() +{ + D3D11VertexFormatInfoMap map; + + // TODO: column legend + + // + // Float formats + // + + // GL_BYTE -- un-normalized + addVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_SINT, ©VertexData<GLbyte, 1, 0>); + addVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_SINT, ©VertexData<GLbyte, 2, 0>); + addVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_SINT, ©VertexData<GLbyte, 3, 1>); + addVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, ©VertexData<GLbyte, 4, 0>); + + // GL_BYTE -- normalized + addVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, ©VertexData<GLbyte, 1, 0>); + addVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SNORM, ©VertexData<GLbyte, 2, 0>); + addVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SNORM, ©VertexData<GLbyte, 3, INT8_MAX>); + addVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, ©VertexData<GLbyte, 4, 0>); + + // GL_UNSIGNED_BYTE -- un-normalized + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, ©VertexData<GLubyte, 1, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_UINT, ©VertexData<GLubyte, 2, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, ©VertexData<GLubyte, 3, 1>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, ©VertexData<GLubyte, 4, 0>); + + // GL_UNSIGNED_BYTE -- normalized + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, ©VertexData<GLubyte, 1, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UNORM, ©VertexData<GLubyte, 2, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, ©VertexData<GLubyte, 3, UINT8_MAX>); + addVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, ©VertexData<GLubyte, 4, 0>); + + // GL_SHORT -- un-normalized + addVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, ©VertexData<GLshort, 1, 0>); + addVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_SINT, ©VertexData<GLshort, 2, 0>); + addVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, ©VertexData<GLshort, 4, 1>); + addVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, ©VertexData<GLshort, 4, 0>); + + // GL_SHORT -- normalized + addVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, ©VertexData<GLshort, 1, 0>); + addVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SNORM, ©VertexData<GLshort, 2, 0>); + addVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, ©VertexData<GLshort, 3, INT16_MAX>); + addVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, ©VertexData<GLshort, 4, 0>); + + // GL_UNSIGNED_SHORT -- un-normalized + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, ©VertexData<GLushort, 1, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_UINT, ©VertexData<GLushort, 2, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_UINT, ©VertexData<GLushort, 3, 1>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, ©VertexData<GLushort, 4, 0>); + + // GL_UNSIGNED_SHORT -- normalized + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, ©VertexData<GLushort, 1, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UNORM, ©VertexData<GLushort, 2, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UNORM, ©VertexData<GLushort, 3, UINT16_MAX>); + addVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, ©VertexData<GLushort, 4, 0>); + + // GL_INT -- un-normalized + addVertexFormatInfo(&map, GL_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_SINT, ©VertexData<GLint, 1, 0>); + addVertexFormatInfo(&map, GL_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_SINT, ©VertexData<GLint, 2, 0>); + addVertexFormatInfo(&map, GL_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_SINT, ©VertexData<GLint, 3, 0>); + addVertexFormatInfo(&map, GL_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, ©VertexData<GLint, 4, 0>); + + // GL_INT -- normalized + addVertexFormatInfo(&map, GL_INT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, ©ToFloatVertexData<GLint, 1, true>); + addVertexFormatInfo(&map, GL_INT, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, ©ToFloatVertexData<GLint, 2, true>); + addVertexFormatInfo(&map, GL_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, ©ToFloatVertexData<GLint, 3, true>); + addVertexFormatInfo(&map, GL_INT, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, ©ToFloatVertexData<GLint, 4, true>); + + // GL_UNSIGNED_INT -- un-normalized + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, ©VertexData<GLuint, 1, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_UINT, ©VertexData<GLuint, 2, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_UINT, ©VertexData<GLuint, 3, 0>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, ©VertexData<GLuint, 4, 0>); + + // GL_UNSIGNED_INT -- normalized + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, ©ToFloatVertexData<GLuint, 1, true>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, ©ToFloatVertexData<GLuint, 2, true>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, ©ToFloatVertexData<GLuint, 3, true>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, ©ToFloatVertexData<GLuint, 4, true>); + + // GL_FIXED + addVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, ©FixedVertexData<1>); + addVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, ©FixedVertexData<2>); + addVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, ©FixedVertexData<3>); + addVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, ©FixedVertexData<4>); + + // GL_HALF_FLOAT + addVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_FLOAT, ©VertexData<GLhalf, 1, 0>); + addVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_FLOAT, ©VertexData<GLhalf, 2, 0>); + addVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_FLOAT, ©VertexData<GLhalf, 3, gl::Float16One>); + addVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, ©VertexData<GLhalf, 4, 0>); + + // GL_FLOAT + addVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, ©VertexData<GLfloat, 1, 0>); + addVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, ©VertexData<GLfloat, 2, 0>); + addVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_FLOAT, ©VertexData<GLfloat, 3, 0>); + addVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, ©VertexData<GLfloat, 4, 0>); + + // GL_INT_2_10_10_10_REV + addVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, ©PackedVertexData<true, false, true>); + addVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, ©PackedVertexData<true, true, true>); + + // GL_UNSIGNED_INT_2_10_10_10_REV + addVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, ©PackedVertexData<false, false, true>); + addVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, ©PackedUnsignedVertexData); + + // + // Integer Formats + // + + // GL_BYTE + addIntegerVertexFormatInfo(&map, GL_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, ©VertexData<GLbyte, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SINT, ©VertexData<GLbyte, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SINT, ©VertexData<GLbyte, 3, 1>); + addIntegerVertexFormatInfo(&map, GL_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SINT, ©VertexData<GLbyte, 4, 0>); + + // GL_UNSIGNED_BYTE + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UINT, ©VertexData<GLubyte, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UINT, ©VertexData<GLubyte, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UINT, ©VertexData<GLubyte, 3, 1>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UINT, ©VertexData<GLubyte, 4, 0>); + + // GL_SHORT + addIntegerVertexFormatInfo(&map, GL_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SINT, ©VertexData<GLshort, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SINT, ©VertexData<GLshort, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, ©VertexData<GLshort, 3, 1>); + addIntegerVertexFormatInfo(&map, GL_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SINT, ©VertexData<GLshort, 4, 0>); + + // GL_UNSIGNED_SHORT + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UINT, ©VertexData<GLushort, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UINT, ©VertexData<GLushort, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UINT, ©VertexData<GLushort, 3, 1>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UINT, ©VertexData<GLushort, 4, 0>); + + // GL_INT + addIntegerVertexFormatInfo(&map, GL_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, ©VertexData<GLint, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, ©VertexData<GLint, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, ©VertexData<GLint, 3, 0>); + addIntegerVertexFormatInfo(&map, GL_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, ©VertexData<GLint, 4, 0>); + + // GL_UNSIGNED_INT + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, ©VertexData<GLuint, 1, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, ©VertexData<GLuint, 2, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, ©VertexData<GLuint, 3, 0>); + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, ©VertexData<GLuint, 4, 0>); + + // GL_INT_2_10_10_10_REV + addIntegerVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, ©PackedVertexData<true, true, false>); + + // GL_UNSIGNED_INT_2_10_10_10_REV + addIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UINT, ©PackedUnsignedVertexData); + + return map; +} + +static bool GetD3D11VertexFormatInfo(const gl::VertexFormat &vertexFormat, D3D11VertexFormatInfo *outVertexFormatInfo) +{ + static const D3D11VertexFormatInfoMap vertexFormatMap = BuildD3D11VertexFormatInfoMap(); + + D3D11VertexFormatInfoMap::const_iterator iter = vertexFormatMap.find(vertexFormat); + if (iter != vertexFormatMap.end()) + { + if (outVertexFormatInfo) + { + *outVertexFormatInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +VertexCopyFunction GetVertexCopyFunction(const gl::VertexFormat &vertexFormat) +{ + D3D11VertexFormatInfo vertexFormatInfo; + if (GetD3D11VertexFormatInfo(vertexFormat, &vertexFormatInfo)) + { + return vertexFormatInfo.mCopyFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +size_t GetVertexElementSize(const gl::VertexFormat &vertexFormat) +{ + D3D11VertexFormatInfo vertexFormatInfo; + if (GetD3D11VertexFormatInfo(vertexFormat, &vertexFormatInfo)) + { + // FIXME: should not need a client version, and is not a pixel! + return d3d11::GetFormatPixelBytes(vertexFormatInfo.mNativeFormat); + } + else + { + UNREACHABLE(); + return 0; + } +} + +rx::VertexConversionType GetVertexConversionType(const gl::VertexFormat &vertexFormat) +{ + D3D11VertexFormatInfo vertexFormatInfo; + if (GetD3D11VertexFormatInfo(vertexFormat, &vertexFormatInfo)) + { + return vertexFormatInfo.mConversionType; + } + else + { + UNREACHABLE(); + return VERTEX_CONVERT_NONE; + } +} + +DXGI_FORMAT GetNativeVertexFormat(const gl::VertexFormat &vertexFormat) +{ + D3D11VertexFormatInfo vertexFormatInfo; + if (GetD3D11VertexFormatInfo(vertexFormat, &vertexFormatInfo)) + { + return vertexFormatInfo.mNativeFormat; + } + else + { + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } +} + +} + +namespace d3d11_gl +{ + +GLenum GetInternalFormat(DXGI_FORMAT format) +{ + const DXGIToESFormatMap &formatMap = GetDXGIToESFormatMap(); + DXGIToESFormatMap::const_iterator iter = formatMap.find(format); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + UNREACHABLE(); + return GL_NONE; + } +} + +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.h new file mode 100644 index 0000000000..d77fccfe9c --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.h @@ -0,0 +1,79 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils11.h: Queries for GL image formats and their translations to D3D11 +// formats. + +#ifndef LIBGLESV2_RENDERER_FORMATUTILS11_H_ +#define LIBGLESV2_RENDERER_FORMATUTILS11_H_ + +#include "libGLESv2/formatutils.h" + +namespace rx +{ + +class Renderer; + +namespace d3d11 +{ + +typedef std::set<DXGI_FORMAT> DXGIFormatSet; + +MipGenerationFunction GetMipGenerationFunction(DXGI_FORMAT format); +LoadImageFunction GetImageLoadFunction(GLenum internalFormat, GLenum type); + +GLuint GetFormatPixelBytes(DXGI_FORMAT format); +GLuint GetBlockWidth(DXGI_FORMAT format); +GLuint GetBlockHeight(DXGI_FORMAT format); +GLenum GetComponentType(DXGI_FORMAT format); + +GLuint GetDepthBits(DXGI_FORMAT format); +GLuint GetDepthOffset(DXGI_FORMAT format); +GLuint GetStencilBits(DXGI_FORMAT format); +GLuint GetStencilOffset(DXGI_FORMAT format); + +void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); + +const DXGIFormatSet &GetAllUsedDXGIFormats(); + +ColorReadFunction GetColorReadFunction(DXGI_FORMAT format); +ColorCopyFunction GetFastCopyFunction(DXGI_FORMAT sourceFormat, GLenum destFormat, GLenum destType); + +} + +namespace gl_d3d11 +{ + +DXGI_FORMAT GetTexFormat(GLenum internalFormat); +DXGI_FORMAT GetSRVFormat(GLenum internalFormat); +DXGI_FORMAT GetRTVFormat(GLenum internalFormat); +DXGI_FORMAT GetDSVFormat(GLenum internalFormat); +DXGI_FORMAT GetRenderableFormat(GLenum internalFormat); + +DXGI_FORMAT GetSwizzleTexFormat(GLint internalFormat); +DXGI_FORMAT GetSwizzleSRVFormat(GLint internalFormat); +DXGI_FORMAT GetSwizzleRTVFormat(GLint internalFormat); + +bool RequiresTextureDataInitialization(GLint internalFormat); +InitializeTextureDataFunction GetTextureDataInitializationFunction(GLint internalFormat); + +VertexCopyFunction GetVertexCopyFunction(const gl::VertexFormat &vertexFormat); +size_t GetVertexElementSize(const gl::VertexFormat &vertexFormat); +VertexConversionType GetVertexConversionType(const gl::VertexFormat &vertexFormat); +DXGI_FORMAT GetNativeVertexFormat(const gl::VertexFormat &vertexFormat); + +} + +namespace d3d11_gl +{ + +GLenum GetInternalFormat(DXGI_FORMAT format); + +} + +} + +#endif // LIBGLESV2_RENDERER_FORMATUTILS11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp new file mode 100644 index 0000000000..d3d135fe5b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp @@ -0,0 +1,634 @@ +#include "precompiled.h" +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// renderer11_utils.cpp: Conversion functions and other utility routines +// specific to the D3D11 renderer. + +#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "common/debug.h" + +namespace rx +{ + +namespace gl_d3d11 +{ + +D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha) +{ + D3D11_BLEND d3dBlend = D3D11_BLEND_ZERO; + + switch (glBlend) + { + case GL_ZERO: d3dBlend = D3D11_BLEND_ZERO; break; + case GL_ONE: d3dBlend = D3D11_BLEND_ONE; break; + case GL_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_SRC_ALPHA : D3D11_BLEND_SRC_COLOR); break; + case GL_ONE_MINUS_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_SRC_ALPHA : D3D11_BLEND_INV_SRC_COLOR); break; + case GL_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_DEST_COLOR); break; + case GL_ONE_MINUS_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_INV_DEST_COLOR); break; + case GL_SRC_ALPHA: d3dBlend = D3D11_BLEND_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3D11_BLEND_INV_SRC_ALPHA; break; + case GL_DST_ALPHA: d3dBlend = D3D11_BLEND_DEST_ALPHA; break; + case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3D11_BLEND_INV_DEST_ALPHA; break; + case GL_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; + case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; + case GL_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; + case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; + case GL_SRC_ALPHA_SATURATE: d3dBlend = D3D11_BLEND_SRC_ALPHA_SAT; break; + default: UNREACHABLE(); + } + + return d3dBlend; +} + +D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp) +{ + D3D11_BLEND_OP d3dBlendOp = D3D11_BLEND_OP_ADD; + + switch (glBlendOp) + { + case GL_FUNC_ADD: d3dBlendOp = D3D11_BLEND_OP_ADD; break; + case GL_FUNC_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_SUBTRACT; break; + case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_REV_SUBTRACT; break; + case GL_MIN: d3dBlendOp = D3D11_BLEND_OP_MIN; break; + case GL_MAX: d3dBlendOp = D3D11_BLEND_OP_MAX; break; + default: UNREACHABLE(); + } + + return d3dBlendOp; +} + +UINT8 ConvertColorMask(bool red, bool green, bool blue, bool alpha) +{ + UINT8 mask = 0; + if (red) + { + mask |= D3D11_COLOR_WRITE_ENABLE_RED; + } + if (green) + { + mask |= D3D11_COLOR_WRITE_ENABLE_GREEN; + } + if (blue) + { + mask |= D3D11_COLOR_WRITE_ENABLE_BLUE; + } + if (alpha) + { + mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; + } + return mask; +} + +D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode) +{ + D3D11_CULL_MODE cull = D3D11_CULL_NONE; + + if (cullEnabled) + { + switch (cullMode) + { + case GL_FRONT: cull = D3D11_CULL_FRONT; break; + case GL_BACK: cull = D3D11_CULL_BACK; break; + case GL_FRONT_AND_BACK: cull = D3D11_CULL_NONE; break; + default: UNREACHABLE(); + } + } + else + { + cull = D3D11_CULL_NONE; + } + + return cull; +} + +D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison) +{ + D3D11_COMPARISON_FUNC d3dComp = D3D11_COMPARISON_NEVER; + switch (comparison) + { + case GL_NEVER: d3dComp = D3D11_COMPARISON_NEVER; break; + case GL_ALWAYS: d3dComp = D3D11_COMPARISON_ALWAYS; break; + case GL_LESS: d3dComp = D3D11_COMPARISON_LESS; break; + case GL_LEQUAL: d3dComp = D3D11_COMPARISON_LESS_EQUAL; break; + case GL_EQUAL: d3dComp = D3D11_COMPARISON_EQUAL; break; + case GL_GREATER: d3dComp = D3D11_COMPARISON_GREATER; break; + case GL_GEQUAL: d3dComp = D3D11_COMPARISON_GREATER_EQUAL; break; + case GL_NOTEQUAL: d3dComp = D3D11_COMPARISON_NOT_EQUAL; break; + default: UNREACHABLE(); + } + + return d3dComp; +} + +D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled) +{ + return depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; +} + +UINT8 ConvertStencilMask(GLuint stencilmask) +{ + return static_cast<UINT8>(stencilmask); +} + +D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp) +{ + D3D11_STENCIL_OP d3dStencilOp = D3D11_STENCIL_OP_KEEP; + + switch (stencilOp) + { + case GL_ZERO: d3dStencilOp = D3D11_STENCIL_OP_ZERO; break; + case GL_KEEP: d3dStencilOp = D3D11_STENCIL_OP_KEEP; break; + case GL_REPLACE: d3dStencilOp = D3D11_STENCIL_OP_REPLACE; break; + case GL_INCR: d3dStencilOp = D3D11_STENCIL_OP_INCR_SAT; break; + case GL_DECR: d3dStencilOp = D3D11_STENCIL_OP_DECR_SAT; break; + case GL_INVERT: d3dStencilOp = D3D11_STENCIL_OP_INVERT; break; + case GL_INCR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_INCR; break; + case GL_DECR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_DECR; break; + default: UNREACHABLE(); + } + + return d3dStencilOp; +} + +D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode) +{ + bool comparison = comparisonMode != GL_NONE; + + if (maxAnisotropy > 1.0f) + { + return D3D11_ENCODE_ANISOTROPIC_FILTER(static_cast<D3D11_COMPARISON_FUNC>(comparison)); + } + else + { + D3D11_FILTER_TYPE dxMin = D3D11_FILTER_TYPE_POINT; + D3D11_FILTER_TYPE dxMip = D3D11_FILTER_TYPE_POINT; + switch (minFilter) + { + case GL_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_NEAREST_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_NEAREST_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_LINEAR; break; + case GL_LINEAR_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_LINEAR; break; + default: UNREACHABLE(); + } + + D3D11_FILTER_TYPE dxMag = D3D11_FILTER_TYPE_POINT; + switch (magFilter) + { + case GL_NEAREST: dxMag = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR: dxMag = D3D11_FILTER_TYPE_LINEAR; break; + default: UNREACHABLE(); + } + + return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, static_cast<D3D11_COMPARISON_FUNC>(comparison)); + } +} + +D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: return D3D11_TEXTURE_ADDRESS_WRAP; + case GL_CLAMP_TO_EDGE: return D3D11_TEXTURE_ADDRESS_CLAMP; + case GL_MIRRORED_REPEAT: return D3D11_TEXTURE_ADDRESS_MIRROR; + default: UNREACHABLE(); + } + + return D3D11_TEXTURE_ADDRESS_WRAP; +} + +D3D11_QUERY ConvertQueryType(GLenum queryType) +{ + switch (queryType) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: return D3D11_QUERY_OCCLUSION; + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: return D3D11_QUERY_SO_STATISTICS; + default: UNREACHABLE(); return D3D11_QUERY_EVENT; + } +} + +} + + +namespace d3d11_gl +{ + +static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, ID3D11Device *device) +{ + gl::TextureCaps textureCaps; + + DXGI_FORMAT textureFormat = gl_d3d11::GetTexFormat(internalFormat); + DXGI_FORMAT srvFormat = gl_d3d11::GetSRVFormat(internalFormat); + DXGI_FORMAT rtvFormat = gl_d3d11::GetRTVFormat(internalFormat); + DXGI_FORMAT dsvFormat = gl_d3d11::GetDSVFormat(internalFormat); + DXGI_FORMAT renderFormat = gl_d3d11::GetRenderableFormat(internalFormat); + + UINT formatSupport; + if (SUCCEEDED(device->CheckFormatSupport(textureFormat, &formatSupport))) + { + if (gl::GetDepthBits(internalFormat) > 0 || gl::GetStencilBits(internalFormat) > 0) + { + textureCaps.texturable = ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0); + } + else + { + textureCaps.texturable = ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0) && + ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURECUBE) != 0) && + ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE3D) != 0); + } + } + + if (SUCCEEDED(device->CheckFormatSupport(renderFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET) != 0)) + { + for (size_t sampleCount = 1; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sampleCount++) + { + UINT qualityCount = 0; + if (SUCCEEDED(device->CheckMultisampleQualityLevels(renderFormat, sampleCount, &qualityCount)) && + qualityCount > 0) + { + textureCaps.sampleCounts.insert(sampleCount); + } + } + } + + textureCaps.filterable = SUCCEEDED(device->CheckFormatSupport(srvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE)) != 0; + textureCaps.renderable = (SUCCEEDED(device->CheckFormatSupport(rtvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET)) != 0) || + (SUCCEEDED(device->CheckFormatSupport(dsvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL) != 0)); + + return textureCaps; +} + +static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_MAX_MAXANISOTROPY; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return 16; + + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_DEFAULT_MAX_ANISOTROPY; + + default: UNREACHABLE(); return 0; + } +} + +static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return true; + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery + + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return true; + + default: UNREACHABLE(); return false; + } +} + +static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout + + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: return true; + + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) +{ + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb509588.aspx states that shader model + // ps_2_x is required for the ddx (and other derivative functions). + + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx states that feature level + // 9.3 supports shader model ps_2_x. + + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: return true; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout + + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; + + // FIXME(geofflang): Work around NVIDIA driver bug by repacking buffers + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 1; /* D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; */ + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURECUBE_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURECUBE_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_VIEWPORT_BOUNDS_MAX; + + // No constants for D3D9 viewport size limits, use the maximum texture sizes + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +void GenerateCaps(ID3D11Device *device, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) +{ + const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); + for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) + { + gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, device); + textureCapsMap->insert(*internalFormat, textureCaps); + } + + D3D_FEATURE_LEVEL featureLevel = device->GetFeatureLevel(); + + // GL core feature limits + caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max()); + caps->max3DTextureSize = GetMaximum3DTextureSize(featureLevel); + caps->max2DTextureSize = GetMaximum2DTextureSize(featureLevel); + caps->maxCubeMapTextureSize = GetMaximumCubeMapTextureSize(featureLevel); + caps->maxArrayTextureLayers = GetMaximum2DTextureArraySize(featureLevel); + + // Unimplemented, set to minimum required + caps->maxLODBias = 2.0f; + + // No specific limits on render target size, maximum 2D texture size is equivalent + caps->maxRenderbufferSize = caps->max2DTextureSize; + + // Maximum draw buffers and color attachments are the same, max color attachments could eventually be + // increased to 16 + caps->maxDrawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel); + caps->maxColorAttachments = GetMaximumSimultaneousRenderTargets(featureLevel); + + // D3D11 has the same limit for viewport width and height + caps->maxViewportWidth = GetMaximumViewportSize(featureLevel); + caps->maxViewportHeight = caps->maxViewportWidth; + + // Choose a reasonable maximum, enforced in the shader. + caps->minAliasedPointSize = 1.0f; + caps->maxAliasedPointSize = 1024.0f; + + // Wide lines not supported + caps->minAliasedLineWidth = 1.0f; + caps->maxAliasedLineWidth = 1.0f; + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUint = true; + extensions->packedDepthStencil = true; + extensions->getProgramBinary = true; + extensions->rgb8rgba8 = true; + extensions->readFormatBGRA = true; + extensions->pixelBufferObject = true; + extensions->mapBuffer = true; + extensions->mapBufferRange = true; + extensions->textureNPOT = GetNPOTTextureSupport(featureLevel); + extensions->drawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel) > 1; + extensions->textureStorage = true; + extensions->textureFilterAnisotropic = true; + extensions->maxTextureAnisotropy = GetMaximumAnisotropy(featureLevel); + extensions->occlusionQueryBoolean = GetOcclusionQuerySupport(featureLevel); + extensions->fence = GetEventQuerySupport(featureLevel); + extensions->timerQuery = false; // Unimplemented + extensions->robustness = true; + extensions->blendMinMax = true; + extensions->framebufferBlit = true; + extensions->framebufferMultisample = true; + extensions->instancedArrays = GetInstancingSupport(featureLevel); + extensions->packReverseRowOrder = true; + extensions->standardDerivatives = GetDerivativeInstructionSupport(featureLevel); + extensions->shaderTextureLOD = true; + extensions->fragDepth = true; + extensions->textureUsage = true; // This could be false since it has no effect in D3D11 + extensions->translatedShaderSource = true; +} + +} + +namespace d3d11 +{ + +void GenerateInitialTextureData(GLint internalFormat, GLuint width, GLuint height, GLuint depth, + GLuint mipLevels, std::vector<D3D11_SUBRESOURCE_DATA> *outSubresourceData, + std::vector< std::vector<BYTE> > *outData) +{ + InitializeTextureDataFunction initializeFunc = gl_d3d11::GetTextureDataInitializationFunction(internalFormat); + DXGI_FORMAT dxgiFormat = gl_d3d11::GetTexFormat(internalFormat); + + outSubresourceData->resize(mipLevels); + outData->resize(mipLevels); + + for (unsigned int i = 0; i < mipLevels; i++) + { + unsigned int mipWidth = std::max(width >> i, 1U); + unsigned int mipHeight = std::max(height >> i, 1U); + unsigned int mipDepth = std::max(depth >> i, 1U); + + unsigned int rowWidth = d3d11::GetFormatPixelBytes(dxgiFormat) * mipWidth; + unsigned int imageSize = rowWidth * height; + + outData->at(i).resize(rowWidth * mipHeight * mipDepth); + initializeFunc(mipWidth, mipHeight, mipDepth, outData->at(i).data(), rowWidth, imageSize); + + outSubresourceData->at(i).pSysMem = outData->at(i).data(); + outSubresourceData->at(i).SysMemPitch = rowWidth; + outSubresourceData->at(i).SysMemSlicePitch = imageSize; + } +} + +void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v) +{ + vertex->x = x; + vertex->y = y; + vertex->u = u; + vertex->v = v; +} + +void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, + unsigned int layer, float u, float v, float s) +{ + vertex->x = x; + vertex->y = y; + vertex->l = layer; + vertex->u = u; + vertex->v = v; + vertex->s = s; +} + +HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) +{ +#if defined(_DEBUG) + return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name); +#else + return S_OK; +#endif +} + +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h new file mode 100644 index 0000000000..4de9bfa86d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h @@ -0,0 +1,173 @@ +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// renderer11_utils.h: Conversion functions and other utility routines +// specific to the D3D11 renderer. + +#ifndef LIBGLESV2_RENDERER_RENDERER11_UTILS_H +#define LIBGLESV2_RENDERER_RENDERER11_UTILS_H + +#include "libGLESv2/angletypes.h" +#include "libGLESv2/Caps.h" + +namespace rx +{ + +namespace gl_d3d11 +{ + +D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha); +D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp); +UINT8 ConvertColorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha); + +D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode); + +D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison); +D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled); +UINT8 ConvertStencilMask(GLuint stencilmask); +D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp); + +D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode); +D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap); + +D3D11_QUERY ConvertQueryType(GLenum queryType); + +} + +namespace d3d11_gl +{ + +void GenerateCaps(ID3D11Device *device, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions); + +} + +namespace d3d11 +{ + +void GenerateInitialTextureData(GLint internalFormat, GLuint width, GLuint height, GLuint depth, + GLuint mipLevels, std::vector<D3D11_SUBRESOURCE_DATA> *outSubresourceData, + std::vector< std::vector<BYTE> > *outData); + +struct PositionTexCoordVertex +{ + float x, y; + float u, v; +}; +void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v); + +struct PositionLayerTexCoord3DVertex +{ + float x, y; + unsigned int l; + float u, v, s; +}; +void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, + unsigned int layer, float u, float v, float s); + +template <typename T> +struct PositionDepthColorVertex +{ + float x, y, z; + T r, g, b, a; +}; + +template <typename T> +void SetPositionDepthColorVertex(PositionDepthColorVertex<T>* vertex, float x, float y, float z, + const gl::Color<T> &color) +{ + vertex->x = x; + vertex->y = y; + vertex->z = z; + vertex->r = color.red; + vertex->g = color.green; + vertex->b = color.blue; + vertex->a = color.alpha; +} + +HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name); + +template <typename outType> +outType* DynamicCastComObject(IUnknown* object) +{ + outType *outObject = NULL; + HRESULT result = object->QueryInterface(__uuidof(outType), reinterpret_cast<void**>(&outObject)); + if (SUCCEEDED(result)) + { + return outObject; + } + else + { + SafeRelease(outObject); + return NULL; + } +} + +inline bool isDeviceLostError(HRESULT errorCode) +{ + switch (errorCode) + { + case DXGI_ERROR_DEVICE_HUNG: + case DXGI_ERROR_DEVICE_REMOVED: + case DXGI_ERROR_DEVICE_RESET: + case DXGI_ERROR_DRIVER_INTERNAL_ERROR: + case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: + return true; + default: + return false; + } +} + +template <unsigned int N> +inline ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11VertexShader *vs = NULL; + HRESULT result = device->CreateVertexShader(byteCode, N, NULL, &vs); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(vs, name); + return vs; +} + +template <unsigned int N> +inline ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11GeometryShader *gs = NULL; + HRESULT result = device->CreateGeometryShader(byteCode, N, NULL, &gs); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(gs, name); + return gs; +} + +template <unsigned int N> +inline ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11PixelShader *ps = NULL; + HRESULT result = device->CreatePixelShader(byteCode, N, NULL, &ps); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(ps, name); + return ps; +} + +// Copy data to small D3D11 buffers, such as for small constant buffers, which use one struct to +// represent an entire buffer. +template <class T> +inline void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value) +{ + D3D11_MAPPED_SUBRESOURCE mappedResource; + context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + + memcpy(mappedResource.pData, &value, sizeof(T)); + + context->Unmap(constantBuffer, 0); +} + +} + +} + +#endif // LIBGLESV2_RENDERER_RENDERER11_UTILS_H diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl new file mode 100644 index 0000000000..20e6623a30 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl @@ -0,0 +1,76 @@ +Buffer<float4> Buffer4F : register(t0); +Buffer<int4> Buffer4I : register(t0); +Buffer<uint4> Buffer4UI : register(t0); + +struct VS_OUTPUT +{ + float4 position : SV_Position; + uint index : TEXCOORD0; + uint slice : LAYER; +}; + +struct GS_OUTPUT +{ + float4 position : SV_Position; + uint index : TEXCOORD0; + uint slice : SV_RenderTargetArrayIndex; +}; + +cbuffer BufferCopyParams : register(b0) +{ + uint FirstPixelOffset; + uint PixelsPerRow; + uint RowStride; + uint RowsPerSlice; + float2 PositionOffset; + float2 PositionScale; + int2 TexLocationOffset; + int2 TexLocationScale; +} + +void ComputePositionAndIndex(uint vertexID, out VS_OUTPUT outVertex) +{ + uint PixelsPerSlice = PixelsPerRow * RowsPerSlice; + uint SliceStride = RowStride * RowsPerSlice; + + uint slice = vertexID / PixelsPerSlice; + uint sliceOffset = slice * PixelsPerSlice; + uint row = (vertexID - sliceOffset) / PixelsPerRow; + uint col = vertexID - sliceOffset - (row * PixelsPerRow); + + float2 coords = float2(float(col), float(row)); + + outVertex.position = float4(PositionOffset + PositionScale * coords, 0.0f, 1.0f); + outVertex.index = FirstPixelOffset + slice * SliceStride + row * RowStride + col; + outVertex.slice = slice; +} + +void VS_BufferToTexture(in uint vertexID : SV_VertexID, out VS_OUTPUT outVertex) +{ + ComputePositionAndIndex(vertexID, outVertex); +} + +[maxvertexcount(1)] +void GS_BufferToTexture(point VS_OUTPUT inVertex[1], inout PointStream<GS_OUTPUT> outStream) +{ + GS_OUTPUT outVertex; + outVertex.position = inVertex[0].position; + outVertex.index = inVertex[0].index; + outVertex.slice = inVertex[0].slice; + outStream.Append(outVertex); +} + +float4 PS_BufferToTexture_4F(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4F.Load(inIndex); +} + +int4 PS_BufferToTexture_4I(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4I.Load(inIndex); +} + +uint4 PS_BufferToTexture_4UI(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4UI.Load(inIndex); +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl new file mode 100644 index 0000000000..b4cf38076e --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl @@ -0,0 +1,106 @@ +// Assume we are in SM4+, which has 8 color outputs + +void VS_ClearFloat( in float3 inPosition : POSITION, in float4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out float4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputFloat +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; +#if SM4 + float4 color4 : SV_TARGET4; + float4 color5 : SV_TARGET5; + float4 color6 : SV_TARGET6; + float4 color7 : SV_TARGET7; +#endif +}; + +PS_OutputFloat PS_ClearFloat(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) +{ + PS_OutputFloat outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; +#if SM4 + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; +#endif + return outColor; +} + + +void VS_ClearUint( in float3 inPosition : POSITION, in uint4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out uint4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputUint +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + uint4 color3 : SV_TARGET3; + uint4 color4 : SV_TARGET4; + uint4 color5 : SV_TARGET5; + uint4 color6 : SV_TARGET6; + uint4 color7 : SV_TARGET7; +}; + +PS_OutputUint PS_ClearUint(in float4 inPosition : SV_POSITION, in uint4 inColor : COLOR) +{ + PS_OutputUint outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; + return outColor; +} + + +void VS_ClearSint( in float3 inPosition : POSITION, in int4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out int4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputSint +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + int4 color3 : SV_TARGET3; + int4 color4 : SV_TARGET4; + int4 color5 : SV_TARGET5; + int4 color6 : SV_TARGET6; + int4 color7 : SV_TARGET7; +}; + +PS_OutputSint PS_ClearSint(in float4 inPosition : SV_POSITION, in int4 inColor : COLOR) +{ + PS_OutputSint outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; + return outColor; +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl new file mode 100644 index 0000000000..8671c39fb7 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl @@ -0,0 +1,111 @@ +Texture2D<float4> TextureF : register(t0); +Texture2D<uint4> TextureUI : register(t0); +Texture2D<int4> TextureI : register(t0); + +SamplerState Sampler : register(s0); + +void VS_Passthrough2D( in float2 inPosition : POSITION, in float2 inTexCoord : TEXCOORD0, + out float4 outPosition : SV_POSITION, out float2 outTexCoord : TEXCOORD0) +{ + outPosition = float4(inPosition, 0.0f, 1.0f); + outTexCoord = inTexCoord; +} + +float PS_PassthroughDepth2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_DEPTH +{ + return TextureF.Sample(Sampler, inTexCoord).r; +} + +float4 PS_PassthroughRGBA2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, inTexCoord).rgba; +} + +uint4 PS_PassthroughRGBA2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return TextureUI.Load(int3(size * inTexCoord, 0)).rgba; +} + +int4 PS_PassthroughRGBA2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return TextureI.Load(int3(size * inTexCoord, 0)).rgba; +} + +float4 PS_PassthroughRGB2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rgb, 1.0f); +} + +uint4 PS_PassthroughRGB2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).rgb, 0); +} + +int4 PS_PassthroughRGB2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).rgb, 0); +} + +float4 PS_PassthroughRG2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rg, 0.0f, 1.0f); +} + +uint4 PS_PassthroughRG2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).rg, 0, 0); +} + +int4 PS_PassthroughRG2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).rg, 0, 0); +} + +float4 PS_PassthroughR2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).r, 0.0f, 0.0f, 1.0f); +} + +uint4 PS_PassthroughR2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).r, 0, 0, 0); +} + +int4 PS_PassthroughR2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).r, 0, 0, 0); +} + +float4 PS_PassthroughLum2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rrr, 1.0f); +} + +float4 PS_PassthroughLumAlpha2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, inTexCoord).rrra; +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl new file mode 100644 index 0000000000..c23c9032ec --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl @@ -0,0 +1,146 @@ +Texture3D<float4> TextureF : register(t0); +Texture3D<uint4> TextureUI : register(t0); +Texture3D<int4> TextureI : register(t0); + +SamplerState Sampler : register(s0); + +struct VS_INPUT +{ + float2 Position : POSITION; + uint Layer : LAYER; + float3 TexCoord : TEXCOORD; +}; + +struct VS_OUTPUT +{ + float4 Position : SV_POSITION; + uint Layer : LAYER; + float3 TexCoord : TEXCOORD; +}; + +struct GS_OUTPUT +{ + float4 Position : SV_POSITION; + uint Layer : SV_RENDERTARGETARRAYINDEX; + float3 TexCoord : TEXCOORD; +}; + +VS_OUTPUT VS_Passthrough3D(VS_INPUT input) +{ + VS_OUTPUT output; + + output.Position = float4(input.Position, 0.0f, 1.0f); + output.Layer = input.Layer; + output.TexCoord = input.TexCoord; + + return output; +} + +[maxvertexcount(3)] +void GS_Passthrough3D(triangle VS_OUTPUT input[3], inout TriangleStream<GS_OUTPUT> outputStream) +{ + GS_OUTPUT output; + + for (int i = 0; i < 3; i++) + { + output.Position = input[i].Position; + output.Layer = input[i].Layer; + output.TexCoord = input[i].TexCoord; + + outputStream.Append(output); + } +} + +float4 PS_PassthroughRGBA3D(GS_OUTPUT input) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, input.TexCoord).rgba; +} + +uint4 PS_PassthroughRGBA3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return TextureUI.Load(int4(size * input.TexCoord, 0)).rgba; +} + +int4 PS_PassthroughRGBA3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return TextureI.Load(int4(size * input.TexCoord, 0)).rgba; +} + +float4 PS_PassthroughRGB3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rgb, 1.0f); +} + +uint4 PS_PassthroughRGB3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).rgb, 0); +} + +int4 PS_PassthroughRGB3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).rgb, 0); +} + +float4 PS_PassthroughRG3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rg, 0.0f, 1.0f); +} + +uint4 PS_PassthroughRG3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).rg, 0, 0); +} + +int4 PS_PassthroughRG3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).rg, 0, 0); +} + +float4 PS_PassthroughR3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).r, 0.0f, 0.0f, 1.0f); +} + +uint4 PS_PassthroughR3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).r, 0, 0, 0); +} + +int4 PS_PassthroughR3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).r, 0, 0, 0); +} + +float4 PS_PassthroughLum3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rrr, 1.0f); +} + +float4 PS_PassthroughLumAlpha3D(GS_OUTPUT input) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, input.TexCoord).rrra; +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Swizzle11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Swizzle11.hlsl new file mode 100644 index 0000000000..505e222137 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Swizzle11.hlsl @@ -0,0 +1,99 @@ +Texture2D<float4> TextureF2D : register(t0); +Texture2D<uint4> TextureUI2D : register(t0); +Texture2D<int4> TextureI2D : register(t0); + +Texture3D<float4> TextureF3D : register(t0); +Texture3D<uint4> TextureUI3D : register(t0); +Texture3D<int4> TextureI3D : register(t0); + +Texture2DArray<float4> TextureF2DArray : register(t0); +Texture2DArray<uint4> TextureUI2DArray : register(t0); +Texture2DArray<int4> TextureI2DArray : register(t0); + +SamplerState Sampler : register(s0); + +cbuffer SwizzleProperties : register(b0) +{ + uint4 SwizzleIndices : packoffset(c0); +} + +float4 SwizzleLookup(in float4 sample) +{ + float lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return float4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +int4 SwizzleLookup(in int4 sample) +{ + int lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return int4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +uint4 SwizzleLookup(in uint4 sample) +{ + uint lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return uint4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +float4 PS_SwizzleF2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF2D.Sample(Sampler, inTexCoord)); +} + +int4 PS_SwizzleI2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI2D.GetDimensions(size.x, size.y); + + return SwizzleLookup(TextureI2D.Load(int3(size * inTexCoord, 0))); +} + +uint4 PS_SwizzleUI2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI2D.GetDimensions(size.x, size.y); + + return SwizzleLookup(TextureUI2D.Load(int3(size * inTexCoord, 0))); +} + +float4 PS_SwizzleF3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF3D.Sample(Sampler, inTexCoord)); +} + +int4 PS_SwizzleI3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureI3D.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureI3D.Load(int4(size * inTexCoord, 0))); +} + +uint4 PS_SwizzleUI3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureUI3D.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureUI3D.Load(int4(size * inTexCoord, 0))); +} + +float4 PS_SwizzleF2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF2DArray.Sample(Sampler, float3(inTexCoord.xy, inLayer))); +} + +int4 PS_SwizzleI2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureI2DArray.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureI2DArray.Load(int4(size.xy * inTexCoord.xy, inLayer, 0))); +} + +uint4 PS_SwizzleUI2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureUI2DArray.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureUI2DArray.Load(int4(size.xy * inTexCoord.xy, inLayer, 0))); +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Blit.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp index d73df6418d..f486e5a4cc 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Blit.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp @@ -5,70 +5,68 @@ // found in the LICENSE file. // -// Blit.cpp: Surface copy utility class. +// Blit9.cpp: Surface copy utility class. -#include "libGLESv2/renderer/d3d9/Blit.h" +#include "libGLESv2/renderer/d3d/d3d9/Blit9.h" #include "libGLESv2/main.h" -#include "libGLESv2/renderer/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d9/TextureStorage9.h" -#include "libGLESv2/renderer/d3d9/RenderTarget9.h" -#include "libGLESv2/renderer/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" +#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" #include "libGLESv2/Framebuffer.h" -#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/FramebufferAttachment.h" namespace { -#include "libGLESv2/renderer/d3d9/shaders/compiled/standardvs.h" -#include "libGLESv2/renderer/d3d9/shaders/compiled/flipyvs.h" -#include "libGLESv2/renderer/d3d9/shaders/compiled/passthroughps.h" -#include "libGLESv2/renderer/d3d9/shaders/compiled/luminanceps.h" -#include "libGLESv2/renderer/d3d9/shaders/compiled/componentmaskps.h" +#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/standardvs.h" +#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/flipyvs.h" +#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/passthroughps.h" +#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/luminanceps.h" +#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h" const BYTE* const g_shaderCode[] = { - g_vs20_standardvs, - g_vs20_flipyvs, - g_ps20_passthroughps, - g_ps20_luminanceps, - g_ps20_componentmaskps + g_vs20_VS_standard, + g_vs20_VS_flipy, + g_ps20_PS_passthrough, + g_ps20_PS_luminance, + g_ps20_PS_componentmask }; const size_t g_shaderSize[] = { - sizeof(g_vs20_standardvs), - sizeof(g_vs20_flipyvs), - sizeof(g_ps20_passthroughps), - sizeof(g_ps20_luminanceps), - sizeof(g_ps20_componentmaskps) + sizeof(g_vs20_VS_standard), + sizeof(g_vs20_VS_flipy), + sizeof(g_ps20_PS_passthrough), + sizeof(g_ps20_PS_luminance), + sizeof(g_ps20_PS_componentmask) }; } namespace rx { -Blit::Blit(rx::Renderer9 *renderer) +Blit9::Blit9(rx::Renderer9 *renderer) : mRenderer(renderer), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedStateBlock(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL) { initGeometry(); memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); } -Blit::~Blit() +Blit9::~Blit9() { - if (mSavedStateBlock) mSavedStateBlock->Release(); - if (mQuadVertexBuffer) mQuadVertexBuffer->Release(); - if (mQuadVertexDeclaration) mQuadVertexDeclaration->Release(); + SafeRelease(mSavedStateBlock); + SafeRelease(mQuadVertexBuffer); + SafeRelease(mQuadVertexDeclaration); for (int i = 0; i < SHADER_COUNT; i++) { - if (mCompiledShaders[i]) - { - mCompiledShaders[i]->Release(); - } + SafeRelease(mCompiledShaders[i]); } } -void Blit::initGeometry() +void Blit9::initGeometry() { static const float quad[] = { @@ -116,7 +114,7 @@ void Blit::initGeometry() } template <class D3DShaderType> -bool Blit::setShader(ShaderId source, const char *profile, +bool Blit9::setShader(ShaderId source, const char *profile, D3DShaderType *(rx::Renderer9::*createShader)(const DWORD *, size_t length), HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) { @@ -154,17 +152,17 @@ bool Blit::setShader(ShaderId source, const char *profile, return true; } -bool Blit::setVertexShader(ShaderId shader) +bool Blit9::setVertexShader(ShaderId shader) { return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &rx::Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader); } -bool Blit::setPixelShader(ShaderId shader) +bool Blit9::setPixelShader(ShaderId shader) { return setShader<IDirect3DPixelShader9>(shader, "ps_2_0", &rx::Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader); } -RECT Blit::getSurfaceRect(IDirect3DSurface9 *surface) const +RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const { D3DSURFACE_DESC desc; surface->GetDesc(&desc); @@ -178,7 +176,7 @@ RECT Blit::getSurfaceRect(IDirect3DSurface9 *surface) const return rect; } -bool Blit::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) +bool Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) { IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source)); if (!texture) @@ -204,18 +202,18 @@ bool Blit::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) render(); - texture->Release(); + SafeRelease(texture); restoreState(); return true; } -bool Blit::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level) +bool Blit9::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level) { RenderTarget9 *renderTarget = NULL; IDirect3DSurface9 *source = NULL; - gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0); + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); if (colorbuffer) { @@ -240,18 +238,18 @@ bool Blit::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum des if (destSurface) { result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); - destSurface->Release(); + SafeRelease(destSurface); } - source->Release(); + SafeRelease(source); return result; } -bool Blit::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level) +bool Blit9::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level) { RenderTarget9 *renderTarget = NULL; IDirect3DSurface9 *source = NULL; - gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0); + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); if (colorbuffer) { @@ -276,14 +274,14 @@ bool Blit::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum des if (destSurface) { result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); - destSurface->Release(); + SafeRelease(destSurface); } - source->Release(); + SafeRelease(source); return result; } -bool Blit::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) +bool Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) { if (!dest) { @@ -316,7 +314,7 @@ bool Blit::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFo return true; } -bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) +bool Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) { IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect); if (!texture) @@ -339,14 +337,14 @@ bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLen render(); } - texture->Release(); + SafeRelease(texture); restoreState(); return true; } -bool Blit::setFormatConvertShaders(GLenum destFormat) +bool Blit9::setFormatConvertShaders(GLenum destFormat) { bool okay = setVertexShader(SHADER_VS_STANDARD); @@ -356,6 +354,8 @@ bool Blit::setFormatConvertShaders(GLenum destFormat) case GL_RGBA: case GL_BGRA_EXT: case GL_RGB: + case GL_RG_EXT: + case GL_RED_EXT: case GL_ALPHA: okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK); break; @@ -375,41 +375,99 @@ bool Blit::setFormatConvertShaders(GLenum destFormat) // The meaning of this constant depends on the shader that was selected. // See the shader assembly code above for details. - float psConst0[4] = { 0, 0, 0, 0 }; + // Allocate one array for both registers and split it into two float4's. + float psConst[8] = { 0 }; + float *multConst = &psConst[0]; + float *addConst = &psConst[4]; switch (destFormat) { default: UNREACHABLE(); case GL_RGBA: case GL_BGRA_EXT: - psConst0[X] = 1; - psConst0[Z] = 1; + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 1; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; break; case GL_RGB: - psConst0[X] = 1; - psConst0[W] = 1; + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 1; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_RG_EXT: + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_RED_EXT: + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; break; case GL_ALPHA: - psConst0[Z] = 1; + multConst[X] = 0; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; break; case GL_LUMINANCE: - psConst0[Y] = 1; + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; break; case GL_LUMINANCE_ALPHA: - psConst0[X] = 1; + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; break; } - mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst0, 1); + mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2); return true; } -IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect) +IDirect3DTexture9 *Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect) { if (!surface) { @@ -437,26 +495,26 @@ IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - texture->Release(); + SafeRelease(texture); return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); } mRenderer->endScene(); result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE); - textureSurface->Release(); + SafeRelease(textureSurface); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - texture->Release(); + SafeRelease(texture); return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); } return texture; } -void Blit::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset) +void Blit9::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset) { IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -473,7 +531,7 @@ void Blit::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset) device->SetVertexShaderConstantF(0, halfPixelAdjust, 1); } -void Blit::setCommonBlitState() +void Blit9::setCommonBlitState() { IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -503,7 +561,7 @@ void Blit::setCommonBlitState() } } -void Blit::render() +void Blit9::render() { IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -514,7 +572,7 @@ void Blit::render() hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); } -void Blit::saveState() +void Blit9::saveState() { IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -530,12 +588,12 @@ void Blit::saveState() setCommonBlitState(); - static const float dummyConst[4] = { 0, 0, 0, 0 }; + static const float dummyConst[8] = { 0 }; device->SetVertexShader(NULL); - device->SetVertexShaderConstantF(0, dummyConst, 1); + device->SetVertexShaderConstantF(0, dummyConst, 2); device->SetPixelShader(NULL); - device->SetPixelShaderConstantF(0, dummyConst, 1); + device->SetPixelShaderConstantF(0, dummyConst, 2); D3DVIEWPORT9 dummyVp; dummyVp.X = 0; @@ -566,23 +624,15 @@ void Blit::saveState() } } -void Blit::restoreState() +void Blit9::restoreState() { IDirect3DDevice9 *device = mRenderer->getDevice(); device->SetDepthStencilSurface(mSavedDepthStencil); - if (mSavedDepthStencil != NULL) - { - mSavedDepthStencil->Release(); - mSavedDepthStencil = NULL; - } + SafeRelease(mSavedDepthStencil); device->SetRenderTarget(0, mSavedRenderTarget); - if (mSavedRenderTarget != NULL) - { - mSavedRenderTarget->Release(); - mSavedRenderTarget = NULL; - } + SafeRelease(mSavedRenderTarget); ASSERT(mSavedStateBlock != NULL); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Blit.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h index 3718028e66..3635bca932 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Blit.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h @@ -4,10 +4,10 @@ // found in the LICENSE file. // -// Blit.cpp: Surface copy utility class. +// Blit9.cpp: Surface copy utility class. -#ifndef LIBGLESV2_BLIT_H_ -#define LIBGLESV2_BLIT_H_ +#ifndef LIBGLESV2_BLIT9_H_ +#define LIBGLESV2_BLIT9_H_ #include "common/angleutils.h" @@ -22,11 +22,11 @@ class Renderer9; class TextureStorageInterface2D; class TextureStorageInterfaceCube; -class Blit +class Blit9 { public: - explicit Blit(Renderer9 *renderer); - ~Blit(); + explicit Blit9(Renderer9 *renderer); + ~Blit9(); // Copy from source surface to dest surface. // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) @@ -87,8 +87,8 @@ class Blit IDirect3DSurface9 *mSavedRenderTarget; IDirect3DSurface9 *mSavedDepthStencil; - DISALLOW_COPY_AND_ASSIGN(Blit); + DISALLOW_COPY_AND_ASSIGN(Blit9); }; } -#endif // LIBGLESV2_BLIT_H_ +#endif // LIBGLESV2_BLIT9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp new file mode 100644 index 0000000000..347bde0c65 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp @@ -0,0 +1,126 @@ +#include "precompiled.h" +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer9.cpp Defines the Buffer9 class. + +#include "libGLESv2/renderer/d3d/d3d9/Buffer9.h" +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +Buffer9::Buffer9(rx::Renderer9 *renderer) + : BufferD3D(), + mRenderer(renderer), + mSize(0) +{ + +} + +Buffer9::~Buffer9() +{ + +} + +Buffer9 *Buffer9::makeBuffer9(BufferImpl *buffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Buffer9*, buffer)); + return static_cast<Buffer9*>(buffer); +} + +void Buffer9::clear() +{ + mSize = 0; +} + +void Buffer9::setData(const void* data, size_t size, GLenum usage) +{ + if (size > mMemory.size()) + { + if (!mMemory.resize(size)) + { + return gl::error(GL_OUT_OF_MEMORY); + } + } + + mSize = size; + if (data) + { + memcpy(mMemory.data(), data, size); + } + + mIndexRangeCache.clear(); + + invalidateStaticData(); + + if (usage == GL_STATIC_DRAW) + { + initializeStaticData(); + } +} + +void *Buffer9::getData() +{ + return mMemory.data(); +} + +void Buffer9::setSubData(const void* data, size_t size, size_t offset) +{ + if (offset + size > mMemory.size()) + { + if (!mMemory.resize(offset + size)) + { + return gl::error(GL_OUT_OF_MEMORY); + } + } + + mSize = std::max(mSize, offset + size); + if (data) + { + memcpy(mMemory.data() + offset, data, size); + } + + mIndexRangeCache.invalidateRange(offset, size); + + invalidateStaticData(); +} + +void Buffer9::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +{ + Buffer9* sourceBuffer = makeBuffer9(source); + if (sourceBuffer) + { + memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size); + } + + invalidateStaticData(); +} + +// We do not suppot buffer mapping in D3D9 +GLvoid* Buffer9::map(size_t offset, size_t length, GLbitfield access) +{ + UNREACHABLE(); + return NULL; +} + +void Buffer9::unmap() +{ + UNREACHABLE(); +} + +void Buffer9::markTransformFeedbackUsage() +{ + UNREACHABLE(); +} + +Renderer* Buffer9::getRenderer() +{ + return mRenderer; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h new file mode 100644 index 0000000000..ec25ec30c9 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h @@ -0,0 +1,53 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer9.h: Defines the rx::Buffer9 class which implements rx::BufferImpl via rx::BufferD3D. + +#ifndef LIBGLESV2_RENDERER_BUFFER9_H_ +#define LIBGLESV2_RENDERER_BUFFER9_H_ + +#include "libGLESv2/renderer/d3d/BufferD3D.h" +#include "libGLESv2/renderer/d3d/MemoryBuffer.h" +#include "libGLESv2/angletypes.h" + +namespace rx +{ +class Renderer9; + +class Buffer9 : public BufferD3D +{ + public: + Buffer9(rx::Renderer9 *renderer); + virtual ~Buffer9(); + + static Buffer9 *makeBuffer9(BufferImpl *buffer); + + // BufferD3D implementation + virtual size_t getSize() const { return mSize; } + virtual void clear(); + virtual bool supportsDirectBinding() const { return false; } + virtual Renderer* getRenderer(); + + // BufferImpl implementation + virtual void setData(const void* data, size_t size, GLenum usage); + virtual void *getData(); + virtual void setSubData(const void* data, size_t size, size_t offset); + virtual void copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + virtual GLvoid* map(size_t offset, size_t length, GLbitfield access); + virtual void unmap(); + virtual void markTransformFeedbackUsage(); + + private: + DISALLOW_COPY_AND_ASSIGN(Buffer9); + + rx::Renderer9 *mRenderer; + MemoryBuffer mMemory; + size_t mSize; +}; + +} + +#endif // LIBGLESV2_RENDERER_BUFFER9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp new file mode 100644 index 0000000000..d2437cadf3 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp @@ -0,0 +1,73 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence9.cpp: Defines the rx::Fence9 class. + +#include "libGLESv2/renderer/d3d/d3d9/Fence9.h" +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +Fence9::Fence9(rx::Renderer9 *renderer) +{ + mRenderer = renderer; + mQuery = NULL; +} + +Fence9::~Fence9() +{ + SafeRelease(mQuery); +} + +bool Fence9::isSet() const +{ + return mQuery != NULL; +} + +void Fence9::set() +{ + if (!mQuery) + { + mQuery = mRenderer->allocateEventQuery(); + if (!mQuery) + { + return gl::error(GL_OUT_OF_MEMORY); + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_END); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); +} + +bool Fence9::test(bool flushCommandBuffer) +{ + ASSERT(mQuery); + + DWORD getDataFlags = (flushCommandBuffer ? D3DGETDATA_FLUSH : 0); + HRESULT result = mQuery->GetData(NULL, 0, getDataFlags); + + if (d3d9::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::error(GL_OUT_OF_MEMORY, true); + } + + ASSERT(result == S_OK || result == S_FALSE); + + return (result == S_OK); +} + +bool Fence9::hasError() const +{ + return mRenderer->isDeviceLost(); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Fence9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h index 9f17641e51..e923a2178c 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Fence9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h @@ -21,11 +21,10 @@ class Fence9 : public FenceImpl explicit Fence9(rx::Renderer9 *renderer); virtual ~Fence9(); - GLboolean isFence(); - void setFence(GLenum condition); - GLboolean testFence(); - void finishFence(); - void getFenceiv(GLenum pname, GLint *params); + bool isSet() const; + void set(); + bool test(bool flushCommandBuffer); + bool hasError() const; private: DISALLOW_COPY_AND_ASSIGN(Fence9); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Image9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp index cd12d8cc9e..e237c3b6e1 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Image9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp @@ -1,3 +1,4 @@ + #include "precompiled.h" // // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. @@ -8,17 +9,18 @@ // Image9.cpp: Implements the rx::Image9 class, which acts as the interface to // the actual underlying surfaces of a Texture. -#include "libGLESv2/renderer/d3d9/Image9.h" +#include "libGLESv2/renderer/d3d/d3d9/Image9.h" #include "libGLESv2/main.h" #include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/renderer/d3d9/Renderer9.h" -#include "libGLESv2/renderer/d3d9/RenderTarget9.h" -#include "libGLESv2/renderer/d3d9/TextureStorage9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" +#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" -#include "libGLESv2/renderer/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/generatemip.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" namespace rx { @@ -34,10 +36,7 @@ Image9::Image9() Image9::~Image9() { - if (mSurface) - { - mSurface->Release(); - } + SafeRelease(mSurface); } void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface) @@ -54,6 +53,9 @@ void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sour ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width); ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height); + MipGenerationFunction mipFunction = d3d9::GetMipGenerationFunction(sourceDesc.Format); + ASSERT(mipFunction != NULL); + D3DLOCKED_RECT sourceLocked = {0}; result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY); ASSERT(SUCCEEDED(result)); @@ -62,37 +64,17 @@ void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sour result = destSurface->LockRect(&destLocked, NULL, 0); ASSERT(SUCCEEDED(result)); - const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(sourceLocked.pBits); - unsigned char *destData = reinterpret_cast<unsigned char*>(destLocked.pBits); + const uint8_t *sourceData = reinterpret_cast<const uint8_t*>(sourceLocked.pBits); + uint8_t *destData = reinterpret_cast<uint8_t*>(destLocked.pBits); if (sourceData && destData) { - switch (sourceDesc.Format) - { - case D3DFMT_L8: - GenerateMip<L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); - break; - case D3DFMT_A8L8: - GenerateMip<A8L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); - break; - case D3DFMT_A8R8G8B8: - case D3DFMT_X8R8G8B8: - GenerateMip<A8R8G8B8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); - break; - case D3DFMT_A16B16G16R16F: - GenerateMip<A16B16G16R16F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); - break; - case D3DFMT_A32B32G32R32F: - GenerateMip<A32B32G32R32F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); - break; - default: - UNREACHABLE(); - break; - } - - destSurface->UnlockRect(); - sourceSurface->UnlockRect(); + mipFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0, + destData, destLocked.Pitch, 0); } + + destSurface->UnlockRect(); + sourceSurface->UnlockRect(); } Image9 *Image9::makeImage9(Image *img) @@ -126,8 +108,10 @@ void Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *so D3DSURFACE_DESC desc; source->GetDesc(&desc); - int rows = d3d9::IsCompressedFormat(desc.Format) ? desc.Height / 4 : desc.Height; - int bytes = d3d9::ComputeRowSize(desc.Format, desc.Width); + int blockHeight = d3d9::GetBlockHeight(desc.Format); + int rows = desc.Height / blockHeight; + + int bytes = d3d9::GetBlockSize(desc.Format, desc.Width, blockHeight); ASSERT(bytes <= sourceLock.Pitch && bytes <= destLock.Pitch); for(int i = 0; i < rows; i++) @@ -141,10 +125,17 @@ void Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *so else UNREACHABLE(); } -bool Image9::redefine(rx::Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease) +bool Image9::redefine(rx::Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) { + // 3D textures are not supported by the D3D9 backend. + ASSERT(depth <= 1); + + // Only 2D and cube texture are supported by the D3D9 backend. + ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP); + if (mWidth != width || mHeight != height || + mDepth != depth || mInternalFormat != internalformat || forceRelease) { @@ -152,16 +143,16 @@ bool Image9::redefine(rx::Renderer *renderer, GLint internalformat, GLsizei widt mWidth = width; mHeight = height; + mDepth = depth; mInternalFormat = internalformat; + // compute the d3d format that will be used - mD3DFormat = mRenderer->ConvertTextureInternalFormat(internalformat); - mActualFormat = d3d9_gl::GetEquivalentFormat(mD3DFormat); + mD3DFormat = gl_d3d9::GetTextureFormat(internalformat); + mActualFormat = d3d9_gl::GetInternalFormat(mD3DFormat); + mRenderable = gl_d3d9::GetRenderFormat(internalformat) != D3DFMT_UNKNOWN; - if (mSurface) - { - mSurface->Release(); - mSurface = NULL; - } + SafeRelease(mSurface); + mDirty = gl_d3d9::RequiresTextureDataInitialization(mInternalFormat); return true; } @@ -180,14 +171,13 @@ void Image9::createSurface() IDirect3DSurface9 *newSurface = NULL; const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM; const D3DFORMAT d3dFormat = getD3DFormat(); - ASSERT(d3dFormat != D3DFMT_INTZ); // We should never get here for depth textures if (mWidth != 0 && mHeight != 0) { int levelToFetch = 0; GLsizei requestWidth = mWidth; GLsizei requestHeight = mHeight; - gl::MakeValidSize(true, gl::IsCompressed(mInternalFormat), &requestWidth, &requestHeight, &levelToFetch); + d3d9::MakeValidSize(true, d3dFormat, &requestWidth, &requestHeight, &levelToFetch); IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -202,7 +192,27 @@ void Image9::createSurface() } newTexture->GetSurfaceLevel(levelToFetch, &newSurface); - newTexture->Release(); + SafeRelease(newTexture); + + if (gl_d3d9::RequiresTextureDataInitialization(mInternalFormat)) + { + InitializeTextureDataFunction initializeFunc = gl_d3d9::GetTextureDataInitializationFunction(mInternalFormat); + + RECT entireRect; + entireRect.left = 0; + entireRect.right = mWidth; + entireRect.top = 0; + entireRect.bottom = mHeight; + + D3DLOCKED_RECT lockedRect; + result = newSurface->LockRect(&lockedRect, &entireRect, 0); + ASSERT(SUCCEEDED(result)); + + initializeFunc(mWidth, mHeight, 1, reinterpret_cast<uint8_t*>(lockedRect.pBits), lockedRect.Pitch, 0); + + result = newSurface->UnlockRect(); + ASSERT(SUCCEEDED(result)); + } } mSurface = newSurface; @@ -232,15 +242,11 @@ void Image9::unlock() if (mSurface) { HRESULT result = mSurface->UnlockRect(); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); } } -bool Image9::isRenderableFormat() const -{ - return TextureStorage9::IsTextureFormatRenderable(getD3DFormat()); -} - D3DFORMAT Image9::getD3DFormat() const { // this should only happen if the image hasn't been redefined first @@ -250,6 +256,13 @@ D3DFORMAT Image9::getD3DFormat() const return mD3DFormat; } +bool Image9::isDirty() const +{ + // Make sure to that this image is marked as dirty even if the staging texture hasn't been created yet + // if initialization is required before use. + return (mSurface || gl_d3d9::RequiresTextureDataInitialization(mInternalFormat)) && mDirty; +} + IDirect3DSurface9 *Image9::getSurface() { createSurface(); @@ -280,7 +293,7 @@ void Image9::setManagedSurface(IDirect3DSurface9 *surface) if (mSurface) { copyLockableSurfaces(surface, mSurface); - mSurface->Release(); + SafeRelease(mSurface); } mSurface = surface; @@ -288,22 +301,38 @@ void Image9::setManagedSurface(IDirect3DSurface9 *surface) } } -bool Image9::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +bool Image9::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { ASSERT(getSurface() != NULL); TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance()); - return updateSurface(storage9->getSurfaceLevel(level, true), xoffset, yoffset, width, height); + return copyToSurface(storage9->getSurfaceLevel(level, true), xoffset, yoffset, width, height); } -bool Image9::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +bool Image9::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { ASSERT(getSurface() != NULL); TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance()); - return updateSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height); + return copyToSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height); +} + +bool Image9::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) +{ + // 3D textures are not supported by the D3D9 backend. + UNREACHABLE(); + return false; } -bool Image9::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +bool Image9::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height) { + // 2D array textures are not supported by the D3D9 backend. + UNREACHABLE(); + return false; +} + +bool Image9::copyToSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + ASSERT(width > 0 && height > 0); + if (!destSurface) return false; @@ -334,26 +363,35 @@ bool Image9::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint copyLockableSurfaces(surf, sourceSurface); result = device->UpdateSurface(surf, &rect, destSurface, &point); ASSERT(SUCCEEDED(result)); - surf->Release(); + SafeRelease(surf); } } else { // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); } } - destSurface->Release(); + SafeRelease(destSurface); return true; } // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input // into the target pixel rectangle. -void Image9::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLint unpackAlignment, const void *input) +void Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input) { + // 3D textures are not supported by the D3D9 backend. + ASSERT(zoffset == 0 && depth == 1); + + GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, type, width, unpackAlignment); + + LoadImageFunction loadFunction = d3d9::GetImageLoadFunction(mInternalFormat); + ASSERT(loadFunction != NULL); + RECT lockRect = { xoffset, yoffset, @@ -367,100 +405,30 @@ void Image9::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei heigh return; } - - GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment); - - switch (mInternalFormat) - { - case GL_ALPHA8_EXT: -#if defined(__SSE2__) - if (gl::supportsSSE2()) - { - loadAlphaDataToBGRASSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits); - } - else -#endif - { - loadAlphaDataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - } - break; - case GL_LUMINANCE8_EXT: - loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_L8); - break; - case GL_ALPHA32F_EXT: - loadAlphaFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_LUMINANCE32F_EXT: - loadLuminanceFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_ALPHA16F_EXT: - loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_LUMINANCE16F_EXT: - loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_LUMINANCE8_ALPHA8_EXT: - loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_A8L8); - break; - case GL_LUMINANCE_ALPHA32F_EXT: - loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_LUMINANCE_ALPHA16F_EXT: - loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_RGB8_OES: - loadRGBUByteDataToBGRX(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_RGB565: - loadRGB565DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_RGBA8_OES: -#if defined(__SSE2__) - if (gl::supportsSSE2()) - { - loadRGBAUByteDataToBGRASSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits); - } - else -#endif - { - loadRGBAUByteDataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - } - break; - case GL_RGBA4: - loadRGBA4444DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_RGB5_A1: - loadRGBA5551DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_BGRA8_EXT: - loadBGRADataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D - case GL_RGB32F_EXT: - loadRGBFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_RGB16F_EXT: - loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_RGBA32F_EXT: - loadRGBAFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - case GL_RGBA16F_EXT: - loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits); - break; - default: UNREACHABLE(); - } + loadFunction(width, height, depth, + reinterpret_cast<const uint8_t*>(input), inputRowPitch, 0, + reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0); unlock(); } -void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, +void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, const void *input) { - ASSERT(xoffset % 4 == 0); - ASSERT(yoffset % 4 == 0); + // 3D textures are not supported by the D3D9 backend. + ASSERT(zoffset == 0 && depth == 1); + + GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, 1); + GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, GL_UNSIGNED_BYTE, width, height, 1); + + ASSERT(xoffset % d3d9::GetBlockWidth(mD3DFormat) == 0); + ASSERT(yoffset % d3d9::GetBlockHeight(mD3DFormat) == 0); - RECT lockRect = { + LoadImageFunction loadFunction = d3d9::GetImageLoadFunction(mInternalFormat); + ASSERT(loadFunction != NULL); + + RECT lockRect = + { xoffset, yoffset, xoffset + width, yoffset + height }; @@ -472,23 +440,22 @@ void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLs return; } - GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat); - GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat); - int rows = inputSize / inputPitch; - for (int i = 0; i < rows; ++i) - { - memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)input + i * inputPitch), inputPitch); - } + loadFunction(width, height, depth, + reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch, + reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0); unlock(); } // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures -void Image9::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { + // ES3.0 only behaviour to copy into a 3d texture + ASSERT(zoffset == 0); + RenderTarget9 *renderTarget = NULL; IDirect3DSurface9 *surface = NULL; - gl::Renderbuffer *colorbuffer = source->getColorbuffer(0); + gl::FramebufferAttachment *colorbuffer = source->getColorbuffer(0); if (colorbuffer) { @@ -517,7 +484,7 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, if (FAILED(result)) { ERR("Could not create matching destination surface."); - surface->Release(); + SafeRelease(surface); return gl::error(GL_OUT_OF_MEMORY); } @@ -526,8 +493,8 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, if (FAILED(result)) { ERR("GetRenderTargetData unexpectedly failed."); - renderTargetData->Release(); - surface->Release(); + SafeRelease(renderTargetData); + SafeRelease(surface); return gl::error(GL_OUT_OF_MEMORY); } @@ -540,8 +507,8 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, if (FAILED(result)) { ERR("Failed to lock the source surface (rectangle might be invalid)."); - renderTargetData->Release(); - surface->Release(); + SafeRelease(renderTargetData); + SafeRelease(surface); return gl::error(GL_OUT_OF_MEMORY); } @@ -552,8 +519,8 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, { ERR("Failed to lock the destination surface (rectangle might be invalid)."); renderTargetData->UnlockRect(); - renderTargetData->Release(); - surface->Release(); + SafeRelease(renderTargetData); + SafeRelease(surface); return gl::error(GL_OUT_OF_MEMORY); } @@ -727,8 +694,8 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, unlock(); renderTargetData->UnlockRect(); - renderTargetData->Release(); - surface->Release(); + SafeRelease(renderTargetData); + SafeRelease(surface); mDirty = true; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Image9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h index 2fbbca3124..2d1536f24b 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Image9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,7 +10,7 @@ #ifndef LIBGLESV2_RENDERER_IMAGE9_H_ #define LIBGLESV2_RENDERER_IMAGE9_H_ -#include "libGLESv2/renderer/Image.h" +#include "libGLESv2/renderer/d3d/ImageD3D.h" #include "common/debug.h" namespace gl @@ -25,7 +25,7 @@ class Renderer9; class TextureStorageInterface2D; class TextureStorageInterfaceCube; -class Image9 : public Image +class Image9 : public ImageD3D { public: Image9(); @@ -37,32 +37,33 @@ class Image9 : public Image static void generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface); static void copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source); - virtual bool redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease); + virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease); - virtual bool isRenderableFormat() const; D3DFORMAT getD3DFormat() const; - virtual bool isDirty() const {return mSurface && mDirty;} + virtual bool isDirty() const; IDirect3DSurface9 *getSurface(); virtual void setManagedSurface(TextureStorageInterface2D *storage, int level); virtual void setManagedSurface(TextureStorageInterfaceCube *storage, int face, int level); - virtual bool updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - virtual bool updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - - virtual void loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLint unpackAlignment, const void *input); - virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + virtual bool copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + virtual bool copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + virtual bool copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); + virtual bool copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height); + + virtual void loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input); + virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, const void *input); - virtual void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset,GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); private: DISALLOW_COPY_AND_ASSIGN(Image9); void createSurface(); void setManagedSurface(IDirect3DSurface9 *surface); - bool updateSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + bool copyToSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); HRESULT lock(D3DLOCKED_RECT *lockedRect, const RECT *rect); void unlock(); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/IndexBuffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp index 7cb5d13a18..472e6981a8 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/IndexBuffer9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp @@ -1,14 +1,14 @@ #include "precompiled.h" // -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Indexffer9.cpp: Defines the D3D9 IndexBuffer implementation. -#include "libGLESv2/renderer/d3d9/IndexBuffer9.h" -#include "libGLESv2/renderer/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" namespace rx { @@ -23,20 +23,12 @@ IndexBuffer9::IndexBuffer9(Renderer9 *const renderer) : mRenderer(renderer) IndexBuffer9::~IndexBuffer9() { - if (mIndexBuffer) - { - mIndexBuffer->Release(); - mIndexBuffer = NULL; - } + SafeRelease(mIndexBuffer); } bool IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) { - if (mIndexBuffer) - { - mIndexBuffer->Release(); - mIndexBuffer = NULL; - } + SafeRelease(mIndexBuffer); updateSerial(); @@ -49,7 +41,7 @@ bool IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bool dy } else if (indexType == GL_UNSIGNED_INT) { - if (mRenderer->get32BitIndexSupport()) + if (mRenderer->getRendererExtensions().elementIndexUint) { format = D3DFMT_INDEX32; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/IndexBuffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h index 6801867532..cfc20e1c64 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/IndexBuffer9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h @@ -9,7 +9,7 @@ #ifndef LIBGLESV2_RENDERER_INDEXBUFFER9_H_ #define LIBGLESV2_RENDERER_INDEXBUFFER9_H_ -#include "libGLESv2/renderer/IndexBuffer.h" +#include "libGLESv2/renderer/d3d/IndexBuffer.h" namespace rx { diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Query9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp index 72781cbc39..3c6f1d0d43 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Query9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp @@ -8,10 +8,10 @@ // Query9.cpp: Defines the rx::Query9 class which implements rx::QueryImpl. -#include "libGLESv2/renderer/d3d9/Query9.h" +#include "libGLESv2/renderer/d3d/d3d9/Query9.h" #include "libGLESv2/main.h" -#include "libGLESv2/renderer/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" namespace rx { @@ -24,11 +24,7 @@ Query9::Query9(rx::Renderer9 *renderer, GLenum type) : QueryImpl(type) Query9::~Query9() { - if (mQuery) - { - mQuery->Release(); - mQuery = NULL; - } + SafeRelease(mQuery); } void Query9::begin() @@ -42,17 +38,16 @@ void Query9::begin() } HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); } void Query9::end() { - if (mQuery == NULL) - { - return gl::error(GL_INVALID_OPERATION); - } + ASSERT(mQuery); HRESULT result = mQuery->Issue(D3DISSUE_END); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); mStatus = GL_FALSE; @@ -122,4 +117,9 @@ GLboolean Query9::testQuery() return GL_TRUE; // prevent blocking when query is null } +bool Query9::isStarted() const +{ + return (mQuery != NULL); +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Query9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h index 47eef89336..62906230c4 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Query9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h @@ -21,10 +21,11 @@ class Query9 : public QueryImpl Query9(rx::Renderer9 *renderer, GLenum type); virtual ~Query9(); - void begin(); - void end(); - GLuint getResult(); - GLboolean isResultAvailable(); + virtual void begin(); + virtual void end(); + virtual GLuint getResult(); + virtual GLboolean isResultAvailable(); + virtual bool isStarted() const; private: DISALLOW_COPY_AND_ASSIGN(Query9); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp new file mode 100644 index 0000000000..49bd9b4000 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp @@ -0,0 +1,139 @@ +#include "precompiled.h" +// +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderTarget9.cpp: Implements a D3D9-specific wrapper for IDirect3DSurface9 +// pointers retained by renderbuffers. + +#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" + +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/main.h" + +namespace rx +{ + +// TODO: AddRef the incoming surface to take ownership instead of expecting that its ref is being given. +RenderTarget9::RenderTarget9(Renderer *renderer, IDirect3DSurface9 *surface) +{ + mRenderer = Renderer9::makeRenderer9(renderer); + mRenderTarget = surface; + + if (mRenderTarget) + { + D3DSURFACE_DESC description; + mRenderTarget->GetDesc(&description); + + mWidth = description.Width; + mHeight = description.Height; + mDepth = 1; + + mInternalFormat = d3d9_gl::GetInternalFormat(description.Format); + mActualFormat = d3d9_gl::GetInternalFormat(description.Format); + mSamples = d3d9_gl::GetSamplesCount(description.MultiSampleType); + } +} + +RenderTarget9::RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples) +{ + mRenderer = Renderer9::makeRenderer9(renderer); + mRenderTarget = NULL; + + D3DFORMAT renderFormat = gl_d3d9::GetRenderFormat(internalFormat); + int supportedSamples = mRenderer->getNearestSupportedSamples(renderFormat, samples); + + if (supportedSamples == -1) + { + gl::error(GL_OUT_OF_MEMORY); + + return; + } + + HRESULT result = D3DERR_INVALIDCALL; + + if (width > 0 && height > 0) + { + IDirect3DDevice9 *device = mRenderer->getDevice(); + + bool requiresInitialization = false; + + if (gl::GetDepthBits(internalFormat) > 0 || + gl::GetStencilBits(internalFormat) > 0) + { + result = device->CreateDepthStencilSurface(width, height, renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &mRenderTarget, NULL); + } + else + { + requiresInitialization = gl_d3d9::RequiresTextureDataInitialization(internalFormat); + + result = device->CreateRenderTarget(width, height, renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &mRenderTarget, NULL); + } + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + gl::error(GL_OUT_OF_MEMORY); + + return; + } + + ASSERT(SUCCEEDED(result)); + + if (requiresInitialization) + { + // This format requires that the data be initialized before the render target can be used + // Unfortunately this requires a Get call on the d3d device but it is far better than having + // to mark the render target as lockable and copy data to the gpu. + IDirect3DSurface9 *prevRenderTarget = NULL; + device->GetRenderTarget(0, &prevRenderTarget); + device->SetRenderTarget(0, mRenderTarget); + device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); + device->SetRenderTarget(0, prevRenderTarget); + } + } + + mWidth = width; + mHeight = height; + mDepth = 1; + mInternalFormat = internalFormat; + mSamples = supportedSamples; + mActualFormat = d3d9_gl::GetInternalFormat(renderFormat); +} + +RenderTarget9::~RenderTarget9() +{ + SafeRelease(mRenderTarget); +} + +RenderTarget9 *RenderTarget9::makeRenderTarget9(RenderTarget *target) +{ + ASSERT(HAS_DYNAMIC_TYPE(rx::RenderTarget9*, target)); + return static_cast<rx::RenderTarget9*>(target); +} + +void RenderTarget9::invalidate(GLint x, GLint y, GLsizei width, GLsizei height) +{ + // Currently a no-op +} + +IDirect3DSurface9 *RenderTarget9::getSurface() +{ + // Caller is responsible for releasing the returned surface reference. + // TODO: remove the AddRef to match RenderTarget11 + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/RenderTarget9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h index faf8ad1c6d..68d7adb49e 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/RenderTarget9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h @@ -21,10 +21,13 @@ class RenderTarget9 : public RenderTarget { public: RenderTarget9(Renderer *renderer, IDirect3DSurface9 *surface); - RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum format, GLsizei samples); + RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples); virtual ~RenderTarget9(); static RenderTarget9 *makeRenderTarget9(RenderTarget *renderTarget); + + virtual void invalidate(GLint x, GLint y, GLsizei width, GLsizei height); + IDirect3DSurface9 *getSurface(); private: diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp index 97a10d64bf..491c27a6ab 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Renderer9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp @@ -1,32 +1,39 @@ #include "precompiled.h" // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer. +#include "common/utilities.h" + #include "libGLESv2/main.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/Texture.h" #include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/Renderbuffer.h" #include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/renderer/IndexDataManager.h" -#include "libGLESv2/renderer/d3d9/Renderer9.h" -#include "libGLESv2/renderer/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d9/ShaderExecutable9.h" -#include "libGLESv2/renderer/d3d9/SwapChain9.h" -#include "libGLESv2/renderer/d3d9/TextureStorage9.h" -#include "libGLESv2/renderer/d3d9/Image9.h" -#include "libGLESv2/renderer/d3d9/Blit.h" -#include "libGLESv2/renderer/d3d9/RenderTarget9.h" -#include "libGLESv2/renderer/d3d9/VertexBuffer9.h" -#include "libGLESv2/renderer/d3d9/IndexBuffer9.h" -#include "libGLESv2/renderer/d3d9/BufferStorage9.h" -#include "libGLESv2/renderer/d3d9/Query9.h" -#include "libGLESv2/renderer/d3d9/Fence9.h" +#include "libGLESv2/renderer/d3d/IndexDataManager.h" +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h" +#include "libGLESv2/renderer/d3d/d3d9/SwapChain9.h" +#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" +#include "libGLESv2/renderer/d3d/d3d9/Image9.h" +#include "libGLESv2/renderer/d3d/d3d9/Blit9.h" +#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" +#include "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h" +#include "libGLESv2/renderer/d3d/d3d9/Buffer9.h" +#include "libGLESv2/renderer/d3d/d3d9/Query9.h" +#include "libGLESv2/renderer/d3d/d3d9/Fence9.h" +#include "libGLESv2/renderer/d3d/d3d9/VertexArray9.h" +#include "libGLESv2/angletypes.h" #include "libEGL/Display.h" @@ -43,6 +50,13 @@ #define ANGLE_ENABLE_D3D9EX 1 #endif // !defined(ANGLE_ENABLE_D3D9EX) +#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) +#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 +#endif + +const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z'))); +const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N','U','L','L'))); + namespace rx { static const D3DFORMAT RenderTargetFormats[] = @@ -80,7 +94,9 @@ enum MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4 }; -Renderer9::Renderer9(egl::Display *display, HDC hDc, bool softwareDevice) : Renderer(display), mDc(hDc), mSoftwareDevice(softwareDevice) +Renderer9::Renderer9(egl::Display *display, EGLNativeDisplayType hDc, EGLint requestedDisplay) + : Renderer(display), + mDc(hDc) { mD3d9Module = NULL; @@ -117,6 +133,10 @@ Renderer9::Renderer9(egl::Display *display, HDC hDc, bool softwareDevice) : Rend mNullColorbufferCache[i].height = 0; mNullColorbufferCache[i].buffer = NULL; } + + mAppliedVertexShader = NULL; + mAppliedPixelShader = NULL; + mAppliedProgramSerial = 0; } Renderer9::~Renderer9() @@ -130,10 +150,10 @@ Renderer9::~Renderer9() } } - deinitialize(); + release(); } -void Renderer9::deinitialize() +void Renderer9::release() { releaseDeviceResources(); @@ -142,22 +162,15 @@ void Renderer9::deinitialize() SafeRelease(mD3d9); SafeRelease(mD3d9Ex); + mCompiler.release(); + if (mDeviceWindow) { DestroyWindow(mDeviceWindow); mDeviceWindow = NULL; } - if (mD3d9Module) - { - mD3d9Module = NULL; - } - - while (!mMultiSampleSupport.empty()) - { - delete [] mMultiSampleSupport.begin()->second; - mMultiSampleSupport.erase(mMultiSampleSupport.begin()); - } + mD3d9Module = NULL; } Renderer9 *Renderer9::makeRenderer9(Renderer *renderer) @@ -168,21 +181,13 @@ Renderer9 *Renderer9::makeRenderer9(Renderer *renderer) EGLint Renderer9::initialize() { - if (!initializeCompiler()) + if (!mCompiler.initialize()) { return EGL_NOT_INITIALIZED; } - if (mSoftwareDevice) - { - TRACE_EVENT0("gpu", "GetModuleHandle_swiftshader"); - mD3d9Module = GetModuleHandle(TEXT("swiftshader_d3d9.dll")); - } - else - { - TRACE_EVENT0("gpu", "GetModuleHandle_d3d9"); - mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); - } + TRACE_EVENT0("gpu", "GetModuleHandle_d3d9"); + mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); if (mD3d9Module == NULL) { @@ -251,7 +256,7 @@ EGLint Renderer9::initialize() } // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported. - // This is required by Texture2D::convertToRenderTarget. + // This is required by Texture2D::ensureRenderTarget. if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0) { ERR("Renderer does not support stretctrect from textures!\n"); @@ -263,15 +268,6 @@ EGLint Renderer9::initialize() mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier); } - // ATI cards on XP have problems with non-power-of-two textures. - mSupportsNonPower2Textures = !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && - !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && - !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && - !(getComparableOSVersion() < versionWindowsVista && mAdapterIdentifier.VendorId == VENDOR_ID_AMD); - - // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec - mSupportsTextureFilterAnisotropy = ((mDeviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) && (mDeviceCaps.MaxAnisotropy >= 2)); - mMinSwapInterval = 4; mMaxSwapInterval = 0; @@ -301,48 +297,17 @@ EGLint Renderer9::initialize() mMaxSwapInterval = std::max(mMaxSwapInterval, 4); } - int max = 0; - { - TRACE_EVENT0("gpu", "getMultiSampleSupport"); - for (unsigned int i = 0; i < ArraySize(RenderTargetFormats); ++i) - { - bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1]; - getMultiSampleSupport(RenderTargetFormats[i], multisampleArray); - mMultiSampleSupport[RenderTargetFormats[i]] = multisampleArray; - - for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j) - { - if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max) - { - max = j; - } - } - } - } + mMaxSupportedSamples = 0; + const d3d9::D3DFormatSet &d3d9Formats = d3d9::GetAllUsedD3DFormats(); + for (d3d9::D3DFormatSet::const_iterator i = d3d9Formats.begin(); i != d3d9Formats.end(); ++i) { - TRACE_EVENT0("gpu", "getMultiSampleSupport2"); - for (unsigned int i = 0; i < ArraySize(DepthStencilFormats); ++i) - { - if (DepthStencilFormats[i] == D3DFMT_UNKNOWN) - continue; - - bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1]; - getMultiSampleSupport(DepthStencilFormats[i], multisampleArray); - mMultiSampleSupport[DepthStencilFormats[i]] = multisampleArray; - - for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j) - { - if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max) - { - max = j; - } - } - } + TRACE_EVENT0("gpu", "getMultiSampleSupport"); + MultisampleSupportInfo support = getMultiSampleSupport(*i); + mMultiSampleSupport[*i] = support; + mMaxSupportedSamples = std::max(mMaxSupportedSamples, support.maxSupportedSamples); } - mMaxSupportedSamples = max; - static const TCHAR windowName[] = TEXT("AngleHiddenWindow"); static const TCHAR className[] = TEXT("STATIC"); @@ -378,7 +343,7 @@ EGLint Renderer9::initialize() if (mD3d9Ex) { TRACE_EVENT0("gpu", "mDevice_QueryInterface"); - result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx); + result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**)&mDeviceEx); ASSERT(SUCCEEDED(result)); } @@ -388,36 +353,6 @@ EGLint Renderer9::initialize() mPixelShaderCache.initialize(mDevice); } - // Check occlusion query support - IDirect3DQuery9 *occlusionQuery = NULL; - { - TRACE_EVENT0("gpu", "device_CreateQuery"); - if (SUCCEEDED(mDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery) - { - occlusionQuery->Release(); - mOcclusionQuerySupport = true; - } - else - { - mOcclusionQuerySupport = false; - } - } - - // Check event query support - IDirect3DQuery9 *eventQuery = NULL; - { - TRACE_EVENT0("gpu", "device_CreateQuery2"); - if (SUCCEEDED(mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery) - { - eventQuery->Release(); - mEventQuerySupport = true; - } - else - { - mEventQuerySupport = false; - } - } - D3DDISPLAYMODE currentDisplayMode; mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); @@ -428,72 +363,10 @@ EGLint Renderer9::initialize() SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F)); - // Check depth texture support - // we use INTZ for depth textures in Direct3D9 - // we also want NULL texture support to ensure the we can make depth-only FBOs - // see http://aras-p.info/texts/D3D9GPUHacks.html - mDepthTextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, - D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_INTZ)) && - SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, - D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL)); - - // Check 32 bit floating point texture support - mFloat32FilterSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, - D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && - SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, - D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); - - mFloat32RenderSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, - D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && - SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, - D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); - - if (!mFloat32FilterSupport && !mFloat32RenderSupport) - { - mFloat32TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, - D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && - SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, - D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); - } - else - { - mFloat32TextureSupport = true; - } - - // Check 16 bit floating point texture support - mFloat16FilterSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, - D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && - SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, - D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); - - mFloat16RenderSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, - D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && - SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, - D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); - - if (!mFloat16FilterSupport && !mFloat16RenderSupport) - { - mFloat16TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, - D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && - SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, - D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); - } - else - { - mFloat16TextureSupport = true; - } - - // Check DXT texture support - mDXT1TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1)); - mDXT3TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3)); - mDXT5TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5)); - - // Check luminance[alpha] texture support - mLuminanceTextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8)); - mLuminanceAlphaTextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8)); - initializeDevice(); + d3d9::InitializeVertexTranslations(this); + return EGL_SUCCESS; } @@ -520,7 +393,7 @@ void Renderer9::initializeDevice() mSceneStarted = false; ASSERT(!mBlit && !mVertexDataManager && !mIndexDataManager); - mBlit = new Blit(this); + mBlit = new Blit9(this); mVertexDataManager = new rx::VertexDataManager(this); mIndexDataManager = new rx::IndexDataManager(this); } @@ -585,10 +458,11 @@ int Renderer9::generateConfigs(ConfigDesc **configDescList) if (SUCCEEDED(result)) { ConfigDesc newConfig; - newConfig.renderTargetFormat = d3d9_gl::ConvertBackBufferFormat(renderTargetFormat); - newConfig.depthStencilFormat = d3d9_gl::ConvertDepthStencilFormat(depthStencilFormat); + newConfig.renderTargetFormat = d3d9_gl::GetInternalFormat(renderTargetFormat); + newConfig.depthStencilFormat = d3d9_gl::GetInternalFormat(depthStencilFormat); newConfig.multiSample = 0; // FIXME: enumerate multi-sampling newConfig.fastConfig = (currentDisplayMode.Format == renderTargetFormat); + newConfig.es3Capable = false; (*configDescList)[numConfigs++] = newConfig; } @@ -681,6 +555,7 @@ IDirect3DQuery9* Renderer9::allocateEventQuery() if (mEventQueryPool.empty()) { HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); } else @@ -696,7 +571,7 @@ void Renderer9::freeEventQuery(IDirect3DQuery9* query) { if (mEventQueryPool.size() > 1000) { - query->Release(); + SafeRelease(query); } else { @@ -736,9 +611,14 @@ IndexBuffer *Renderer9::createIndexBuffer() return new IndexBuffer9(this); } -BufferStorage *Renderer9::createBufferStorage() +BufferImpl *Renderer9::createBuffer() { - return new BufferStorage9(); + return new Buffer9(this); +} + +VertexArrayImpl *Renderer9::createVertexArray() +{ + return new VertexArray9(this); } QueryImpl *Renderer9::createQuery(GLenum type) @@ -751,6 +631,26 @@ FenceImpl *Renderer9::createFence() return new Fence9(this); } +bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const +{ + // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. + return false; +} + +bool Renderer9::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +{ + // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. + UNREACHABLE(); + return false; +} + +void Renderer9::generateSwizzle(gl::Texture *texture) +{ + // Swizzled textures are not available in ES2 or D3D9 + UNREACHABLE(); +} + void Renderer9::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState) { bool *forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates; @@ -769,8 +669,8 @@ void Renderer9::setSamplerState(gl::SamplerType type, int index, const gl::Sampl gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy); mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); - mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.lodOffset); - if (mSupportsTextureFilterAnisotropy) + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.baseLevel); + if (getRendererExtensions().textureFilterAnisotropic) { mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy); } @@ -814,6 +714,12 @@ void Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture appliedSerials[index] = serial; } +bool Renderer9::setUniformBuffers(const gl::Buffer* /*vertexUniformBuffers*/[], const gl::Buffer* /*fragmentUniformBuffers*/[]) +{ + // No effect in ES2/D3D9 + return true; +} + void Renderer9::setRasterizerState(const gl::RasterizerState &rasterState) { bool rasterStateChanged = mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0; @@ -852,10 +758,11 @@ void Renderer9::setRasterizerState(const gl::RasterizerState &rasterState) mForceSetRasterState = false; } -void Renderer9::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::Color &blendColor, unsigned int sampleMask) +void Renderer9::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) { bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0; - bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::Color)) != 0; + bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0; bool sampleMaskChanged = mForceSetBlendState || sampleMask != mCurSampleMask; if (blendStateChanged || blendColorChanged) @@ -906,6 +813,9 @@ void Renderer9::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState FIXME("Sample alpha to coverage is unimplemented."); } + gl::FramebufferAttachment *attachment = framebuffer->getFirstColorbuffer(); + GLenum internalFormat = attachment ? attachment->getInternalFormat() : GL_NONE; + // Set the color mask bool zeroColorMaskAllowed = getAdapterVendor() != VENDOR_ID_AMD; // Apparently some ATI cards have a bug where a draw with a zero color @@ -914,8 +824,10 @@ void Renderer9::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState // drawing is done. // http://code.google.com/p/angleproject/issues/detail?id=169 - DWORD colorMask = gl_d3d9::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen, - blendState.colorMaskBlue, blendState.colorMaskAlpha); + DWORD colorMask = gl_d3d9::ConvertColorMask(gl::GetRedBits(internalFormat) > 0 && blendState.colorMaskRed, + gl::GetGreenBits(internalFormat) > 0 && blendState.colorMaskGreen, + gl::GetBlueBits(internalFormat) > 0 && blendState.colorMaskBlue, + gl::GetAlphaBits(internalFormat) > 0 && blendState.colorMaskAlpha); if (colorMask == 0 && !zeroColorMaskAllowed) { // Enable green channel, but set blending so nothing will be drawn. @@ -984,13 +896,10 @@ void Renderer9::setDepthStencilState(const gl::DepthStencilState &depthStencilSt const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF; const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK; const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK; - if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask || - stencilRef != stencilBackRef || - depthStencilState.stencilMask != depthStencilState.stencilBackMask) - { - ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are invalid under WebGL."); - return gl::error(GL_INVALID_OPERATION); - } + + ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask); + ASSERT(stencilRef == stencilBackRef); + ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask); // get the maximum size of the stencil ref unsigned int maxStencil = (1 << mCurStencilSize) - 1; @@ -1188,14 +1097,15 @@ bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count) mPrimitiveCount = count - 2; break; default: - return gl::error(GL_INVALID_ENUM, false); + UNREACHABLE(); + return false; } return mPrimitiveCount > 0; } -gl::Renderbuffer *Renderer9::getNullColorbuffer(gl::Renderbuffer *depthbuffer) +gl::FramebufferAttachment *Renderer9::getNullColorbuffer(gl::FramebufferAttachment *depthbuffer) { if (!depthbuffer) { @@ -1218,7 +1128,8 @@ gl::Renderbuffer *Renderer9::getNullColorbuffer(gl::Renderbuffer *depthbuffer) } } - gl::Renderbuffer *nullbuffer = new gl::Renderbuffer(this, 0, new gl::Colorbuffer(this, width, height, GL_NONE, 0)); + gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(0, new gl::Colorbuffer(this, width, height, GL_NONE, 0)); + gl::RenderbufferAttachment *nullbuffer = new gl::RenderbufferAttachment(nullRenderbuffer); // add nullbuffer to the cache NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0]; @@ -1243,29 +1154,25 @@ bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer) { // if there is no color attachment we must synthesize a NULL colorattachment // to keep the D3D runtime happy. This should only be possible if depth texturing. - gl::Renderbuffer *renderbufferObject = NULL; - if (framebuffer->getColorbufferType(0) != GL_NONE) + gl::FramebufferAttachment *attachment = framebuffer->getColorbuffer(0); + if (!attachment) { - renderbufferObject = framebuffer->getColorbuffer(0); + attachment = getNullColorbuffer(framebuffer->getDepthbuffer()); } - else - { - renderbufferObject = getNullColorbuffer(framebuffer->getDepthbuffer()); - } - if (!renderbufferObject) + if (!attachment) { ERR("unable to locate renderbuffer for FBO."); return false; } bool renderTargetChanged = false; - unsigned int renderTargetSerial = renderbufferObject->getSerial(); + unsigned int renderTargetSerial = attachment->getSerial(); if (renderTargetSerial != mAppliedRenderTargetSerial) { // Apply the render target on the device IDirect3DSurface9 *renderTargetSurface = NULL; - RenderTarget *renderTarget = renderbufferObject->getRenderTarget(); + RenderTarget *renderTarget = attachment->getRenderTarget(); if (renderTarget) { renderTargetSurface = RenderTarget9::makeRenderTarget9(renderTarget)->getSurface(); @@ -1278,35 +1185,22 @@ bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer) } mDevice->SetRenderTarget(0, renderTargetSurface); - renderTargetSurface->Release(); + SafeRelease(renderTargetSurface); mAppliedRenderTargetSerial = renderTargetSerial; renderTargetChanged = true; } - gl::Renderbuffer *depthStencil = NULL; + gl::FramebufferAttachment *depthStencil = framebuffer->getDepthbuffer(); unsigned int depthbufferSerial = 0; unsigned int stencilbufferSerial = 0; - if (framebuffer->getDepthbufferType() != GL_NONE) + if (depthStencil) { - depthStencil = framebuffer->getDepthbuffer(); - if (!depthStencil) - { - ERR("Depth stencil pointer unexpectedly null."); - return false; - } - depthbufferSerial = depthStencil->getSerial(); } - else if (framebuffer->getStencilbufferType() != GL_NONE) + else if (framebuffer->getStencilbuffer()) { depthStencil = framebuffer->getStencilbuffer(); - if (!depthStencil) - { - ERR("Depth stencil pointer unexpectedly null."); - return false; - } - stencilbufferSerial = depthStencil->getSerial(); } @@ -1335,7 +1229,7 @@ bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer) } mDevice->SetDepthStencilSurface(depthStencilSurface); - depthStencilSurface->Release(); + SafeRelease(depthStencilSurface); depthSize = depthStencil->getDepthSize(); stencilSize = depthStencil->getStencilSize(); @@ -1366,25 +1260,27 @@ bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer) { mForceSetScissor = true; mForceSetViewport = true; + mForceSetBlendState = true; - mRenderTargetDesc.width = renderbufferObject->getWidth(); - mRenderTargetDesc.height = renderbufferObject->getHeight(); - mRenderTargetDesc.format = renderbufferObject->getActualFormat(); + mRenderTargetDesc.width = attachment->getWidth(); + mRenderTargetDesc.height = attachment->getHeight(); + mRenderTargetDesc.format = attachment->getActualFormat(); mRenderTargetDescInitialized = true; } return true; } -GLenum Renderer9::applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances) +GLenum Renderer9::applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], + GLint first, GLsizei count, GLsizei instances) { TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; - GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, programBinary, first, count, attributes, instances); + GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances); if (err != GL_NO_ERROR) { return err; } - + return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, &mRepeatDraw); } @@ -1410,10 +1306,17 @@ GLenum Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArr return err; } -void Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances) +void Renderer9::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) { + UNREACHABLE(); +} + +void Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) +{ + ASSERT(!transformFeedbackActive); + startScene(); - + if (mode == GL_LINE_LOOP) { drawLineLoop(count, GL_NONE, NULL, 0, NULL); @@ -1448,7 +1351,8 @@ void Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances) } } -void Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/) +void Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/) { startScene(); @@ -1476,14 +1380,14 @@ void Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, if (type != GL_NONE && elementArrayBuffer) { gl::Buffer *indexBuffer = elementArrayBuffer; - BufferStorage *storage = indexBuffer->getStorage(); + BufferImpl *storage = indexBuffer->getImplementation(); intptr_t offset = reinterpret_cast<intptr_t>(indices); indices = static_cast<const GLubyte*>(storage->getData()) + offset; } unsigned int startIndex = 0; - if (get32BitIndexSupport()) + if (getRendererExtensions().elementIndexUint) { if (!mLineLoopIB) { @@ -1498,15 +1402,15 @@ void Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, } } + // Checked by Renderer9::applyPrimitiveType + ASSERT(count >= 0); + if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int))) { ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); return gl::error(GL_OUT_OF_MEMORY); } - // Checked by Renderer9::applyPrimitiveType - ASSERT(count >= 0); - const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int); if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT)) { @@ -1674,7 +1578,7 @@ void Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indi if (elementArrayBuffer) { - BufferStorage *storage = elementArrayBuffer->getStorage(); + BufferImpl *storage = elementArrayBuffer->getImplementation(); intptr_t offset = reinterpret_cast<intptr_t>(indices); indices = static_cast<const GLubyte*>(storage->getData()) + offset; } @@ -1688,34 +1592,51 @@ void Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indi } } -void Renderer9::applyShaders(gl::ProgramBinary *programBinary) +void Renderer9::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive) { - unsigned int programBinarySerial = programBinary->getSerial(); - if (programBinarySerial != mAppliedProgramBinarySerial) - { - ShaderExecutable *vertexExe = programBinary->getVertexExecutable(); - ShaderExecutable *pixelExe = programBinary->getPixelExecutable(); + ASSERT(!transformFeedbackActive); + ASSERT(!rasterizerDiscard); - IDirect3DVertexShader9 *vertexShader = NULL; - if (vertexExe) vertexShader = ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader(); + ShaderExecutable *vertexExe = programBinary->getVertexExecutableForInputLayout(inputLayout); + ShaderExecutable *pixelExe = programBinary->getPixelExecutableForFramebuffer(framebuffer); - IDirect3DPixelShader9 *pixelShader = NULL; - if (pixelExe) pixelShader = ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader(); + IDirect3DVertexShader9 *vertexShader = (vertexExe ? ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader() : NULL); + IDirect3DPixelShader9 *pixelShader = (pixelExe ? ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader() : NULL); - mDevice->SetPixelShader(pixelShader); + if (vertexShader != mAppliedVertexShader) + { mDevice->SetVertexShader(vertexShader); + mAppliedVertexShader = vertexShader; + } + + if (pixelShader != mAppliedPixelShader) + { + mDevice->SetPixelShader(pixelShader); + mAppliedPixelShader = pixelShader; + } + + // D3D9 has a quirk where creating multiple shaders with the same content + // can return the same shader pointer. Because GL programs store different data + // per-program, checking the program serial guarantees we upload fresh + // uniform data even if our shader pointers are the same. + // https://code.google.com/p/angleproject/issues/detail?id=661 + unsigned int programSerial = programBinary->getSerial(); + if (programSerial != mAppliedProgramSerial) + { programBinary->dirtyAllUniforms(); mDxUniformsDirty = true; - - mAppliedProgramBinarySerial = programBinarySerial; + mAppliedProgramSerial = programSerial; } } -void Renderer9::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray) +void Renderer9::applyUniforms(const gl::ProgramBinary &programBinary) { - for (std::vector<gl::Uniform*>::const_iterator ub = uniformArray->begin(), ue = uniformArray->end(); ub != ue; ++ub) + const std::vector<gl::LinkedUniform*> &uniformArray = programBinary.getUniforms(); + + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) { - gl::Uniform *targetUniform = *ub; + gl::LinkedUniform *targetUniform = uniformArray[uniformIndex]; if (targetUniform->dirty) { @@ -1751,8 +1672,6 @@ void Renderer9::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray default: UNREACHABLE(); } - - targetUniform->dirty = false; } } @@ -1765,20 +1684,20 @@ void Renderer9::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray } } -void Renderer9::applyUniformnfv(gl::Uniform *targetUniform, const GLfloat *v) +void Renderer9::applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v) { - if (targetUniform->psRegisterIndex >= 0) + if (targetUniform->isReferencedByFragmentShader()) { mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, targetUniform->registerCount); } - if (targetUniform->vsRegisterIndex >= 0) + if (targetUniform->isReferencedByVertexShader()) { mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, targetUniform->registerCount); } } -void Renderer9::applyUniformniv(gl::Uniform *targetUniform, const GLint *v) +void Renderer9::applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v) { ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; @@ -1794,7 +1713,7 @@ void Renderer9::applyUniformniv(gl::Uniform *targetUniform, const GLint *v) applyUniformnfv(targetUniform, (GLfloat*)vector); } -void Renderer9::applyUniformnbv(gl::Uniform *targetUniform, const GLint *v) +void Renderer9::applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v) { ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; @@ -1812,27 +1731,68 @@ void Renderer9::applyUniformnbv(gl::Uniform *targetUniform, const GLint *v) void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) { - D3DCOLOR color = D3DCOLOR_ARGB(gl::unorm<8>(clearParams.colorClearValue.alpha), - gl::unorm<8>(clearParams.colorClearValue.red), - gl::unorm<8>(clearParams.colorClearValue.green), - gl::unorm<8>(clearParams.colorClearValue.blue)); + if (clearParams.colorClearType != GL_FLOAT) + { + // Clearing buffers with non-float values is not supported by Renderer9 and ES 2.0 + UNREACHABLE(); + return; + } + + bool clearColor = clearParams.clearColor[0]; + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + if (clearParams.clearColor[i] != clearColor) + { + // Clearing individual buffers other than buffer zero is not supported by Renderer9 and ES 2.0 + UNREACHABLE(); + return; + } + } + float depth = gl::clamp01(clearParams.depthClearValue); - int stencil = clearParams.stencilClearValue & 0x000000FF; + DWORD stencil = clearParams.stencilClearValue & 0x000000FF; unsigned int stencilUnmasked = 0x0; - if ((clearParams.mask & GL_STENCIL_BUFFER_BIT) && frameBuffer->hasStencil()) + if (clearParams.clearStencil && frameBuffer->hasStencil()) { - unsigned int stencilSize = gl::GetStencilSize(frameBuffer->getStencilbuffer()->getActualFormat()); + unsigned int stencilSize = gl::GetStencilBits(frameBuffer->getStencilbuffer()->getActualFormat()); stencilUnmasked = (0x1 << stencilSize) - 1; } - bool alphaUnmasked = (gl::GetAlphaSize(mRenderTargetDesc.format) == 0) || clearParams.colorMaskAlpha; - - const bool needMaskedStencilClear = (clearParams.mask & GL_STENCIL_BUFFER_BIT) && + const bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; - const bool needMaskedColorClear = (clearParams.mask & GL_COLOR_BUFFER_BIT) && - !(clearParams.colorMaskRed && clearParams.colorMaskGreen && - clearParams.colorMaskBlue && alphaUnmasked); + + bool needMaskedColorClear = false; + D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0); + if (clearColor) + { + gl::FramebufferAttachment *attachment = frameBuffer->getFirstColorbuffer(); + GLenum internalFormat = attachment->getInternalFormat(); + GLenum actualFormat = attachment->getActualFormat(); + + GLuint internalRedBits = gl::GetRedBits(internalFormat); + GLuint internalGreenBits = gl::GetGreenBits(internalFormat); + GLuint internalBlueBits = gl::GetBlueBits(internalFormat); + GLuint internalAlphaBits = gl::GetAlphaBits(internalFormat); + + GLuint actualRedBits = gl::GetRedBits(actualFormat); + GLuint actualGreenBits = gl::GetGreenBits(actualFormat); + GLuint actualBlueBits = gl::GetBlueBits(actualFormat); + GLuint actualAlphaBits = gl::GetAlphaBits(actualFormat); + + color = D3DCOLOR_ARGB(gl::unorm<8>((internalAlphaBits == 0 && actualAlphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), + gl::unorm<8>((internalRedBits == 0 && actualRedBits > 0) ? 0.0f : clearParams.colorFClearValue.red), + gl::unorm<8>((internalGreenBits == 0 && actualGreenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), + gl::unorm<8>((internalBlueBits == 0 && actualBlueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue)); + + if ((internalRedBits > 0 && !clearParams.colorMaskRed) || + (internalGreenBits > 0 && !clearParams.colorMaskGreen) || + (internalBlueBits > 0 && !clearParams.colorMaskBlue) || + (internalAlphaBits > 0 && !clearParams.colorMaskAlpha)) + { + needMaskedColorClear = true; + } + } if (needMaskedColorClear || needMaskedStencilClear) { @@ -1893,7 +1853,7 @@ void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *f mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); - if (clearParams.mask & GL_COLOR_BUFFER_BIT) + if (clearColor) { mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, gl_d3d9::ConvertColorMask(clearParams.colorMaskRed, @@ -1906,7 +1866,7 @@ void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *f mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); } - if (stencilUnmasked != 0x0 && (clearParams.mask & GL_STENCIL_BUFFER_BIT)) + if (stencilUnmasked != 0x0 && clearParams.clearStencil) { mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); @@ -1962,7 +1922,7 @@ void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *f startScene(); mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4])); - if (clearParams.mask & GL_DEPTH_BUFFER_BIT) + if (clearParams.clearDepth) { mDevice->SetRenderState(D3DRS_ZENABLE, TRUE); mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); @@ -1974,18 +1934,18 @@ void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *f mMaskedClearSavedState->Apply(); } } - else if (clearParams.mask) + else if (clearColor || clearParams.clearDepth || clearParams.clearStencil) { DWORD dxClearFlags = 0; - if (clearParams.mask & GL_COLOR_BUFFER_BIT) + if (clearColor) { dxClearFlags |= D3DCLEAR_TARGET; } - if (clearParams.mask & GL_DEPTH_BUFFER_BIT) + if (clearParams.clearDepth) { dxClearFlags |= D3DCLEAR_ZBUFFER; } - if (clearParams.mask & GL_STENCIL_BUFFER_BIT) + if (clearParams.clearStencil) { dxClearFlags |= D3DCLEAR_STENCIL; } @@ -2020,7 +1980,9 @@ void Renderer9::markAllStateDirty() } mAppliedIBSerial = 0; - mAppliedProgramBinarySerial = 0; + mAppliedVertexShader = NULL; + mAppliedPixelShader = NULL; + mAppliedProgramSerial = 0; mDxUniformsDirty = true; mVertexDeclarationCache.markStateDirty(); @@ -2028,11 +1990,11 @@ void Renderer9::markAllStateDirty() void Renderer9::releaseDeviceResources() { - while (!mEventQueryPool.empty()) + for (size_t i = 0; i < mEventQueryPool.size(); i++) { - mEventQueryPool.back()->Release(); - mEventQueryPool.pop_back(); + SafeRelease(mEventQueryPool[i]); } + mEventQueryPool.clear(); SafeRelease(mMaskedClearSavedState); @@ -2048,10 +2010,8 @@ void Renderer9::releaseDeviceResources() { SafeDelete(mNullColorbufferCache[i].buffer); } - } - void Renderer9::notifyDeviceLost() { mDeviceLost = true; @@ -2221,7 +2181,7 @@ bool Renderer9::resetRemovedDevice() // The hardware adapter has been removed. Application must destroy the device, do enumeration of // adapters and create another Direct3D device. If application continues rendering without // calling Reset, the rendering calls will succeed. Applies to Direct3D 9Ex only. - deinitialize(); + release(); return (initialize() == EGL_SUCCESS); } @@ -2255,84 +2215,30 @@ GUID Renderer9::getAdapterIdentifier() const return mAdapterIdentifier.DeviceIdentifier; } -void Renderer9::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray) -{ - for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++) - { - HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format, - TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL); - - multiSampleArray[multiSampleIndex] = SUCCEEDED(result); - } -} - -bool Renderer9::getBGRATextureSupport() const -{ - // DirectX 9 always supports BGRA - return true; -} - -bool Renderer9::getDXT1TextureSupport() -{ - return mDXT1TextureSupport; -} - -bool Renderer9::getDXT3TextureSupport() -{ - return mDXT3TextureSupport; -} - -bool Renderer9::getDXT5TextureSupport() +Renderer9::MultisampleSupportInfo Renderer9::getMultiSampleSupport(D3DFORMAT format) { - return mDXT5TextureSupport; -} - -bool Renderer9::getDepthTextureSupport() const -{ - return mDepthTextureSupport; -} - -bool Renderer9::getFloat32TextureSupport(bool *filtering, bool *renderable) -{ - *filtering = mFloat32FilterSupport; - *renderable = mFloat32RenderSupport; - return mFloat32TextureSupport; -} - -bool Renderer9::getFloat16TextureSupport(bool *filtering, bool *renderable) -{ - *filtering = mFloat16FilterSupport; - *renderable = mFloat16RenderSupport; - return mFloat16TextureSupport; -} - -bool Renderer9::getLuminanceTextureSupport() -{ - return mLuminanceTextureSupport; -} + MultisampleSupportInfo support = { 0 }; -bool Renderer9::getLuminanceAlphaTextureSupport() -{ - return mLuminanceAlphaTextureSupport; -} - -bool Renderer9::getTextureFilterAnisotropySupport() const -{ - return mSupportsTextureFilterAnisotropy; -} - -float Renderer9::getTextureMaxAnisotropy() const -{ - if (mSupportsTextureFilterAnisotropy) + for (unsigned int multiSampleIndex = 0; multiSampleIndex < ArraySize(support.supportedSamples); multiSampleIndex++) { - return static_cast<float>(mDeviceCaps.MaxAnisotropy); + HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format, TRUE, + (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL); + + if (SUCCEEDED(result)) + { + support.supportedSamples[multiSampleIndex] = true; + if (multiSampleIndex != D3DMULTISAMPLE_NONMASKABLE) + { + support.maxSupportedSamples = std::max(support.maxSupportedSamples, multiSampleIndex); + } + } + else + { + support.supportedSamples[multiSampleIndex] = false; + } } - return 1.0f; -} -bool Renderer9::getEventQuerySupport() -{ - return mEventQuerySupport; + return support; } unsigned int Renderer9::getMaxVertexTextureImageUnits() const @@ -2373,68 +2279,79 @@ unsigned int Renderer9::getMaxVaryingVectors() const return (getMajorShaderModel() >= 3) ? MAX_VARYING_VECTORS_SM3 : MAX_VARYING_VECTORS_SM2; } -bool Renderer9::getNonPower2TextureSupport() const +unsigned int Renderer9::getMaxVertexShaderUniformBuffers() const { - return mSupportsNonPower2Textures; + return 0; } -bool Renderer9::getOcclusionQuerySupport() const +unsigned int Renderer9::getMaxFragmentShaderUniformBuffers() const { - return mOcclusionQuerySupport; + return 0; } -bool Renderer9::getInstancingSupport() const +unsigned int Renderer9::getReservedVertexUniformBuffers() const { - return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); + return 0; } -bool Renderer9::getShareHandleSupport() const +unsigned int Renderer9::getReservedFragmentUniformBuffers() const { - // PIX doesn't seem to support using share handles, so disable them. - return (mD3d9Ex != NULL) && !gl::perfActive(); + return 0; } -bool Renderer9::getDerivativeInstructionSupport() const +unsigned int Renderer9::getMaxTransformFeedbackBuffers() const { - return (mDeviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0; + return 0; } -bool Renderer9::getPostSubBufferSupport() const +unsigned int Renderer9::getMaxTransformFeedbackSeparateComponents() const { - return true; + return 0; } -int Renderer9::getMajorShaderModel() const +unsigned int Renderer9::getMaxTransformFeedbackInterleavedComponents() const { - return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion); + return 0; +} + +unsigned int Renderer9::getMaxUniformBufferSize() const +{ + return 0; } -float Renderer9::getMaxPointSize() const +bool Renderer9::getShareHandleSupport() const +{ + // PIX doesn't seem to support using share handles, so disable them. + return (mD3d9Ex != NULL) && !gl::perfActive(); +} + +bool Renderer9::getPostSubBufferSupport() const { - // Point size clamped at 1.0f for SM2 - return getMajorShaderModel() == 3 ? mDeviceCaps.MaxPointSize : 1.0f; + return true; } -int Renderer9::getMaxViewportDimension() const +int Renderer9::getMaxRecommendedElementsIndices() const { - int maxTextureDimension = std::min(std::min(getMaxTextureWidth(), getMaxTextureHeight()), - (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE); - return maxTextureDimension; + // ES3 only + UNREACHABLE(); + return 0; } -int Renderer9::getMaxTextureWidth() const +int Renderer9::getMaxRecommendedElementsVertices() const { - return (int)mDeviceCaps.MaxTextureWidth; + // ES3 only + UNREACHABLE(); + return 0; } -int Renderer9::getMaxTextureHeight() const +bool Renderer9::getSRGBTextureSupport() const { - return (int)mDeviceCaps.MaxTextureHeight; + return false; } -bool Renderer9::get32BitIndexSupport() const +int Renderer9::getMajorShaderModel() const { - return mDeviceCaps.MaxVertexIndex >= (1 << 16); + return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion); } DWORD Renderer9::getCapsDeclTypes() const @@ -2457,6 +2374,53 @@ int Renderer9::getMaxSupportedSamples() const return mMaxSupportedSamples; } +GLsizei Renderer9::getMaxSupportedFormatSamples(GLenum internalFormat) const +{ + D3DFORMAT format = gl_d3d9::GetTextureFormat(internalFormat); + MultisampleSupportMap::const_iterator itr = mMultiSampleSupport.find(format); + return (itr != mMultiSampleSupport.end()) ? mMaxSupportedSamples : 0; +} + +GLsizei Renderer9::getNumSampleCounts(GLenum internalFormat) const +{ + D3DFORMAT format = gl_d3d9::GetTextureFormat(internalFormat); + MultisampleSupportMap::const_iterator iter = mMultiSampleSupport.find(format); + + unsigned int numCounts = 0; + if (iter != mMultiSampleSupport.end()) + { + const MultisampleSupportInfo& info = iter->second; + for (int i = 0; i < D3DMULTISAMPLE_16_SAMPLES; i++) + { + if (i != D3DMULTISAMPLE_NONMASKABLE && info.supportedSamples[i]) + { + numCounts++; + } + } + } + + return numCounts; +} + +void Renderer9::getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const +{ + D3DFORMAT format = gl_d3d9::GetTextureFormat(internalFormat); + MultisampleSupportMap::const_iterator iter = mMultiSampleSupport.find(format); + + if (iter != mMultiSampleSupport.end()) + { + const MultisampleSupportInfo& info = iter->second; + int bufPos = 0; + for (int i = D3DMULTISAMPLE_16_SAMPLES; i >= 0 && bufPos < bufSize; i--) + { + if (i != D3DMULTISAMPLE_NONMASKABLE && info.supportedSamples[i]) + { + params[bufPos++] = i; + } + } + } +} + int Renderer9::getNearestSupportedSamples(D3DFORMAT format, int requested) const { if (requested == 0) @@ -2464,7 +2428,7 @@ int Renderer9::getNearestSupportedSamples(D3DFORMAT format, int requested) const return requested; } - std::map<D3DFORMAT, bool *>::const_iterator itr = mMultiSampleSupport.find(format); + MultisampleSupportMap::const_iterator itr = mMultiSampleSupport.find(format); if (itr == mMultiSampleSupport.end()) { if (format == D3DFMT_UNKNOWN) @@ -2472,9 +2436,9 @@ int Renderer9::getNearestSupportedSamples(D3DFORMAT format, int requested) const return -1; } - for (int i = requested; i <= D3DMULTISAMPLE_16_SAMPLES; ++i) + for (unsigned int i = requested; i < ArraySize(itr->second.supportedSamples); ++i) { - if (itr->second[i] && i != D3DMULTISAMPLE_NONMASKABLE) + if (itr->second.supportedSamples[i] && i != D3DMULTISAMPLE_NONMASKABLE) { return i; } @@ -2483,59 +2447,6 @@ int Renderer9::getNearestSupportedSamples(D3DFORMAT format, int requested) const return -1; } -unsigned int Renderer9::getMaxRenderTargets() const -{ - // we do not support MRT in d3d9 - return 1; -} - -D3DFORMAT Renderer9::ConvertTextureInternalFormat(GLint internalformat) -{ - switch (internalformat) - { - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT32_OES: - case GL_DEPTH24_STENCIL8_OES: - return D3DFMT_INTZ; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - return D3DFMT_DXT1; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - return D3DFMT_DXT3; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - return D3DFMT_DXT5; - case GL_RGBA32F_EXT: - case GL_RGB32F_EXT: - case GL_ALPHA32F_EXT: - case GL_LUMINANCE32F_EXT: - case GL_LUMINANCE_ALPHA32F_EXT: - return D3DFMT_A32B32G32R32F; - case GL_RGBA16F_EXT: - case GL_RGB16F_EXT: - case GL_ALPHA16F_EXT: - case GL_LUMINANCE16F_EXT: - case GL_LUMINANCE_ALPHA16F_EXT: - return D3DFMT_A16B16G16R16F; - case GL_LUMINANCE8_EXT: - if (getLuminanceTextureSupport()) - { - return D3DFMT_L8; - } - break; - case GL_LUMINANCE8_ALPHA8_EXT: - if (getLuminanceAlphaTextureSupport()) - { - return D3DFMT_A8L8; - } - break; - case GL_RGB8_OES: - case GL_RGB565: - return D3DFMT_X8R8G8B8; - } - - return D3DFMT_A8R8G8B8; -} - bool Renderer9::copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source) { bool result = false; @@ -2545,19 +2456,21 @@ bool Renderer9::copyToRenderTarget(TextureStorageInterface2D *dest, TextureStora TextureStorage9_2D *source9 = TextureStorage9_2D::makeTextureStorage9_2D(source->getStorageInstance()); TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(dest->getStorageInstance()); - int levels = source9->levelCount(); + int levels = source9->getLevelCount(); for (int i = 0; i < levels; ++i) { IDirect3DSurface9 *srcSurf = source9->getSurfaceLevel(i, false); IDirect3DSurface9 *dstSurf = dest9->getSurfaceLevel(i, false); - + result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged()); - if (srcSurf) srcSurf->Release(); - if (dstSurf) dstSurf->Release(); + SafeRelease(srcSurf); + SafeRelease(dstSurf); if (!result) + { return false; + } } } @@ -2572,7 +2485,7 @@ bool Renderer9::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureSto { TextureStorage9_Cube *source9 = TextureStorage9_Cube::makeTextureStorage9_Cube(source->getStorageInstance()); TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(dest->getStorageInstance()); - int levels = source9->levelCount(); + int levels = source9->getLevelCount(); for (int f = 0; f < 6; f++) { for (int i = 0; i < levels; i++) @@ -2582,11 +2495,13 @@ bool Renderer9::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureSto result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged()); - if (srcSurf) srcSurf->Release(); - if (dstSurf) dstSurf->Release(); + SafeRelease(srcSurf); + SafeRelease(dstSurf); if (!result) + { return false; + } } } } @@ -2594,6 +2509,20 @@ bool Renderer9::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureSto return result; } +bool Renderer9::copyToRenderTarget(TextureStorageInterface3D *dest, TextureStorageInterface3D *source) +{ + // 3D textures are not available in the D3D9 backend. + UNREACHABLE(); + return false; +} + +bool Renderer9::copyToRenderTarget(TextureStorageInterface2DArray *dest, TextureStorageInterface2DArray *source) +{ + // 2D array textures are not supported by the D3D9 backend. + UNREACHABLE(); + return false; +} + D3DPOOL Renderer9::getBufferPool(DWORD usage) const { if (mD3d9Ex != NULL) @@ -2635,15 +2564,33 @@ bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sou return mBlit->copy(framebuffer, rect, destFormat, xoffset, yoffset, storage, target, level); } +bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface3D *storage, GLint level) +{ + // 3D textures are not available in the D3D9 backend. + UNREACHABLE(); + return false; +} + +bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level) +{ + // 2D array textures are not available in the D3D9 backend. + UNREACHABLE(); + return false; +} + bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &readRect, gl::Framebuffer *drawFramebuffer, const gl::Rectangle &drawRect, - bool blitRenderTarget, bool blitDepthStencil) + const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) { + ASSERT(filter == GL_NEAREST); + endScene(); if (blitRenderTarget) { - gl::Renderbuffer *readBuffer = readFramebuffer->getColorbuffer(0); - gl::Renderbuffer *drawBuffer = drawFramebuffer->getColorbuffer(0); + gl::FramebufferAttachment *readBuffer = readFramebuffer->getColorbuffer(0); + gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getColorbuffer(0); RenderTarget9 *readRenderTarget = NULL; RenderTarget9 *drawRenderTarget = NULL; IDirect3DSurface9* readSurface = NULL; @@ -2673,6 +2620,9 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle & return gl::error(GL_OUT_OF_MEMORY, false); } + gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); + gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + RECT srcRect; srcRect.left = readRect.x; srcRect.right = readRect.x + readRect.width; @@ -2685,10 +2635,79 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle & dstRect.top = drawRect.y; dstRect.bottom = drawRect.y + drawRect.height; + // Clip the rectangles to the scissor rectangle + if (scissor) + { + if (dstRect.left < scissor->x) + { + srcRect.left += (scissor->x - dstRect.left); + dstRect.left = scissor->x; + } + if (dstRect.top < scissor->y) + { + srcRect.top += (scissor->y - dstRect.top); + dstRect.top = scissor->y; + } + if (dstRect.right > scissor->x + scissor->width) + { + srcRect.right -= (dstRect.right - (scissor->x + scissor->width)); + dstRect.right = scissor->x + scissor->width; + } + if (dstRect.bottom > scissor->y + scissor->height) + { + srcRect.bottom -= (dstRect.bottom - (scissor->y + scissor->height)); + dstRect.bottom = scissor->y + scissor->height; + } + } + + // Clip the rectangles to the destination size + if (dstRect.left < 0) + { + srcRect.left += -dstRect.left; + dstRect.left = 0; + } + if (dstRect.right > dstSize.width) + { + srcRect.right -= (dstRect.right - dstSize.width); + dstRect.right = dstSize.width; + } + if (dstRect.top < 0) + { + srcRect.top += -dstRect.top; + dstRect.top = 0; + } + if (dstRect.bottom > dstSize.height) + { + srcRect.bottom -= (dstRect.bottom - dstSize.height); + dstRect.bottom = dstSize.height; + } + + // Clip the rectangles to the source size + if (srcRect.left < 0) + { + dstRect.left += -srcRect.left; + srcRect.left = 0; + } + if (srcRect.right > srcSize.width) + { + dstRect.right -= (srcRect.right - srcSize.width); + srcRect.right = srcSize.width; + } + if (srcRect.top < 0) + { + dstRect.top += -srcRect.top; + srcRect.top = 0; + } + if (srcRect.bottom > srcSize.height) + { + dstRect.bottom -= (srcRect.bottom - srcSize.height); + srcRect.bottom = srcSize.height; + } + HRESULT result = mDevice->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE); - readSurface->Release(); - drawSurface->Release(); + SafeRelease(readSurface); + SafeRelease(drawSurface); if (FAILED(result)) { @@ -2697,10 +2716,10 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle & } } - if (blitDepthStencil) + if (blitDepth || blitStencil) { - gl::Renderbuffer *readBuffer = readFramebuffer->getDepthOrStencilbuffer(); - gl::Renderbuffer *drawBuffer = drawFramebuffer->getDepthOrStencilbuffer(); + gl::FramebufferAttachment *readBuffer = readFramebuffer->getDepthOrStencilbuffer(); + gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getDepthOrStencilbuffer(); RenderTarget9 *readDepthStencil = NULL; RenderTarget9 *drawDepthStencil = NULL; IDirect3DSurface9* readSurface = NULL; @@ -2732,8 +2751,8 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle & HRESULT result = mDevice->StretchRect(readSurface, NULL, drawSurface, NULL, D3DTEXF_NONE); - readSurface->Release(); - drawSurface->Release(); + SafeRelease(readSurface); + SafeRelease(drawSurface); if (FAILED(result)) { @@ -2745,18 +2764,20 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle & return true; } -void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, - GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels) +void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void* pixels) { + ASSERT(pack.pixelBuffer.get() == NULL); + RenderTarget9 *renderTarget = NULL; IDirect3DSurface9 *surface = NULL; - gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0); + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); if (colorbuffer) { renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget()); } - + if (renderTarget) { surface = renderTarget->getSurface(); @@ -2774,13 +2795,13 @@ void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsiz if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) { UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target - surface->Release(); + SafeRelease(surface); return gl::error(GL_OUT_OF_MEMORY); } HRESULT result; IDirect3DSurface9 *systemSurface = NULL; - bool directToPixels = !packReverseRowOrder && packAlignment <= 4 && getShareHandleSupport() && + bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && getShareHandleSupport() && x == 0 && y == 0 && UINT(width) == desc.Width && UINT(height) == desc.Height && desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE; if (directToPixels) @@ -2802,18 +2823,17 @@ void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsiz if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - surface->Release(); + SafeRelease(surface); return gl::error(GL_OUT_OF_MEMORY); } } result = mDevice->GetRenderTargetData(surface, systemSurface); - surface->Release(); - surface = NULL; + SafeRelease(surface); if (FAILED(result)) { - systemSurface->Release(); + SafeRelease(systemSurface); // It turns out that D3D will sometimes produce more error // codes than those documented. @@ -2832,7 +2852,7 @@ void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsiz if (directToPixels) { - systemSurface->Release(); + SafeRelease(systemSurface); return; } @@ -2848,17 +2868,14 @@ void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsiz if (FAILED(result)) { UNREACHABLE(); - systemSurface->Release(); + SafeRelease(systemSurface); return; // No sensible error to generate } - unsigned char *dest = (unsigned char*)pixels; - unsigned short *dest16 = (unsigned short*)pixels; - unsigned char *source; int inputPitch; - if (packReverseRowOrder) + if (pack.reverseRowOrder) { source = ((unsigned char*)lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); inputPitch = -lock.Pitch; @@ -2869,231 +2886,67 @@ void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsiz inputPitch = lock.Pitch; } - unsigned int fastPixelSize = 0; + GLenum sourceInternalFormat = d3d9_gl::GetInternalFormat(desc.Format); + GLenum sourceFormat = gl::GetFormat(sourceInternalFormat); + GLenum sourceType = gl::GetType(sourceInternalFormat); - if (desc.Format == D3DFMT_A8R8G8B8 && - format == GL_BGRA_EXT && - type == GL_UNSIGNED_BYTE) - { - fastPixelSize = 4; - } - else if ((desc.Format == D3DFMT_A4R4G4B4 && - format == GL_BGRA_EXT && - type == GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT) || - (desc.Format == D3DFMT_A1R5G5B5 && - format == GL_BGRA_EXT && - type == GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT)) - { - fastPixelSize = 2; - } - else if (desc.Format == D3DFMT_A16B16G16R16F && - format == GL_RGBA && - type == GL_HALF_FLOAT_OES) - { - fastPixelSize = 8; - } - else if (desc.Format == D3DFMT_A32B32G32R32F && - format == GL_RGBA && - type == GL_FLOAT) - { - fastPixelSize = 16; - } + GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat); - for (int j = 0; j < rect.bottom - rect.top; j++) + if (sourceFormat == format && sourceType == type) { - if (fastPixelSize != 0) + // Direct copy possible + unsigned char *dest = static_cast<unsigned char*>(pixels); + for (int y = 0; y < rect.bottom - rect.top; y++) { - // Fast path for formats which require no translation: - // D3DFMT_A8R8G8B8 to BGRA/UNSIGNED_BYTE - // D3DFMT_A4R4G4B4 to BGRA/UNSIGNED_SHORT_4_4_4_4_REV_EXT - // D3DFMT_A1R5G5B5 to BGRA/UNSIGNED_SHORT_1_5_5_5_REV_EXT - // D3DFMT_A16B16G16R16F to RGBA/HALF_FLOAT_OES - // D3DFMT_A32B32G32R32F to RGBA/FLOAT - // - // Note that buffers with no alpha go through the slow path below. - memcpy(dest + j * outputPitch, - source + j * inputPitch, - (rect.right - rect.left) * fastPixelSize); - continue; - } - else if (desc.Format == D3DFMT_A8R8G8B8 && - format == GL_RGBA && - type == GL_UNSIGNED_BYTE) - { - // Fast path for swapping red with blue - for (int i = 0; i < rect.right - rect.left; i++) - { - unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); - *(unsigned int*)(dest + 4 * i + j * outputPitch) = - (argb & 0xFF00FF00) | // Keep alpha and green - (argb & 0x00FF0000) >> 16 | // Move red to blue - (argb & 0x000000FF) << 16; // Move blue to red - } - continue; + memcpy(dest + y * outputPitch, source + y * inputPitch, (rect.right - rect.left) * sourcePixelSize); } + } + else + { + GLenum destInternalFormat = gl::GetSizedInternalFormat(format, type); + GLuint destPixelSize = gl::GetPixelBytes(destInternalFormat); + GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat); - for (int i = 0; i < rect.right - rect.left; i++) + ColorCopyFunction fastCopyFunc = d3d9::GetFastCopyFunction(desc.Format, format, type); + if (fastCopyFunc) { - float r; - float g; - float b; - float a; - - switch (desc.Format) + // Fast copy is possible through some special function + for (int y = 0; y < rect.bottom - rect.top; y++) { - case D3DFMT_R5G6B5: - { - unsigned short rgb = *(unsigned short*)(source + 2 * i + j * inputPitch); - - a = 1.0f; - b = (rgb & 0x001F) * (1.0f / 0x001F); - g = (rgb & 0x07E0) * (1.0f / 0x07E0); - r = (rgb & 0xF800) * (1.0f / 0xF800); - } - break; - case D3DFMT_A1R5G5B5: - { - unsigned short argb = *(unsigned short*)(source + 2 * i + j * inputPitch); - - a = (argb & 0x8000) ? 1.0f : 0.0f; - b = (argb & 0x001F) * (1.0f / 0x001F); - g = (argb & 0x03E0) * (1.0f / 0x03E0); - r = (argb & 0x7C00) * (1.0f / 0x7C00); - } - break; - case D3DFMT_A8R8G8B8: - { - unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); - - a = (argb & 0xFF000000) * (1.0f / 0xFF000000); - b = (argb & 0x000000FF) * (1.0f / 0x000000FF); - g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00); - r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000); - } - break; - case D3DFMT_X8R8G8B8: - { - unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * inputPitch); - - a = 1.0f; - b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF); - g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00); - r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000); - } - break; - case D3DFMT_A2R10G10B10: + for (int x = 0; x < rect.right - rect.left; x++) { - unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); + void *dest = static_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize; + void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize; - a = (argb & 0xC0000000) * (1.0f / 0xC0000000); - b = (argb & 0x000003FF) * (1.0f / 0x000003FF); - g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00); - r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000); + fastCopyFunc(src, dest); } - break; - case D3DFMT_A32B32G32R32F: - { - // float formats in D3D are stored rgba, rather than the other way round - r = *((float*)(source + 16 * i + j * inputPitch) + 0); - g = *((float*)(source + 16 * i + j * inputPitch) + 1); - b = *((float*)(source + 16 * i + j * inputPitch) + 2); - a = *((float*)(source + 16 * i + j * inputPitch) + 3); - } - break; - case D3DFMT_A16B16G16R16F: - { - // float formats in D3D are stored rgba, rather than the other way round - r = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 0)); - g = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 1)); - b = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 2)); - a = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 3)); - } - break; - default: - UNIMPLEMENTED(); // FIXME - UNREACHABLE(); - return; } + } + else + { + ColorReadFunction readFunc = d3d9::GetColorReadFunction(desc.Format); + ColorWriteFunction writeFunc = gl::GetColorWriteFunction(format, type); + + gl::ColorF temp; - switch (format) + for (int y = 0; y < rect.bottom - rect.top; y++) { - case GL_RGBA: - switch (type) + for (int x = 0; x < rect.right - rect.left; x++) { - case GL_UNSIGNED_BYTE: - dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f); - dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); - dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f); - dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f); - break; - default: UNREACHABLE(); - } - break; - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: - dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * b + 0.5f); - dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); - dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * r + 0.5f); - dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f); - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: - // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section - // this type is packed as follows: - // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - // -------------------------------------------------------------------------------- - // | 4th | 3rd | 2nd | 1st component | - // -------------------------------------------------------------------------------- - // in the case of BGRA_EXT, B is the first component, G the second, and so forth. - dest16[i + j * outputPitch / sizeof(unsigned short)] = - ((unsigned short)(15 * a + 0.5f) << 12)| - ((unsigned short)(15 * r + 0.5f) << 8) | - ((unsigned short)(15 * g + 0.5f) << 4) | - ((unsigned short)(15 * b + 0.5f) << 0); - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: - // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section - // this type is packed as follows: - // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - // -------------------------------------------------------------------------------- - // | 4th | 3rd | 2nd | 1st component | - // -------------------------------------------------------------------------------- - // in the case of BGRA_EXT, B is the first component, G the second, and so forth. - dest16[i + j * outputPitch / sizeof(unsigned short)] = - ((unsigned short)( a + 0.5f) << 15) | - ((unsigned short)(31 * r + 0.5f) << 10) | - ((unsigned short)(31 * g + 0.5f) << 5) | - ((unsigned short)(31 * b + 0.5f) << 0); - break; - default: UNREACHABLE(); - } - break; - case GL_RGB: - switch (type) - { - case GL_UNSIGNED_SHORT_5_6_5: - dest16[i + j * outputPitch / sizeof(unsigned short)] = - ((unsigned short)(31 * b + 0.5f) << 0) | - ((unsigned short)(63 * g + 0.5f) << 5) | - ((unsigned short)(31 * r + 0.5f) << 11); - break; - case GL_UNSIGNED_BYTE: - dest[3 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f); - dest[3 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); - dest[3 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f); - break; - default: UNREACHABLE(); + void *dest = reinterpret_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize; + void *src = source + y * inputPitch + x * sourcePixelSize; + + // readFunc and writeFunc will be using the same type of color, CopyTexImage + // will not allow the copy otherwise. + readFunc(src, &temp); + writeFunc(&temp, dest); } - break; - default: UNREACHABLE(); } } } systemSurface->UnlockRect(); - - systemSurface->Release(); + SafeRelease(systemSurface); } RenderTarget *Renderer9::createRenderTarget(SwapChain *swapChain, bool depth) @@ -3114,14 +2967,19 @@ RenderTarget *Renderer9::createRenderTarget(SwapChain *swapChain, bool depth) return renderTarget; } -RenderTarget *Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth) +RenderTarget *Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples) { RenderTarget9 *renderTarget = new RenderTarget9(this, width, height, format, samples); return renderTarget; } -ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type) +ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers) { + // Transform feedback is not supported in ES2 or D3D9 + ASSERT(transformFeedbackVaryings.size() == 0); + ShaderExecutable9 *executable = NULL; switch (type) @@ -3152,8 +3010,13 @@ ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, return executable; } -ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, D3DWorkaroundType workaround) +ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround) { + // Transform feedback is not supported in ES2 or D3D9 + ASSERT(transformFeedbackVaryings.size() == 0); + const char *profile = NULL; switch (type) @@ -3169,20 +3032,67 @@ ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const cha return NULL; } - // ANGLE issue 486: - // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by disabling optimization - UINT optimizationFlags = (workaround == ANGLE_D3D_WORKAROUND_SM3_OPTIMIZER ? D3DCOMPILE_SKIP_OPTIMIZATION : ANGLE_COMPILE_OPTIMIZATION_LEVEL); + UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL; + + if (workaround == ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION) + { + flags = D3DCOMPILE_SKIP_OPTIMIZATION; + } + else if (workaround == ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION) + { + flags = D3DCOMPILE_OPTIMIZATION_LEVEL3; + } + else ASSERT(workaround == ANGLE_D3D_WORKAROUND_NONE); + + if (gl::perfActive()) + { +#ifndef NDEBUG + flags = D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + flags |= D3DCOMPILE_DEBUG; + + std::string sourcePath = getTempPath(); + std::string sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(shaderHLSL); + writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); + } + + // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. + // Try the default flags first and if compilation fails, try some alternatives. + const UINT extraFlags[] = + { + flags, + flags | D3DCOMPILE_AVOID_FLOW_CONTROL, + flags | D3DCOMPILE_PREFER_FLOW_CONTROL + }; - ID3DBlob *binary = (ID3DBlob*)compileToBinary(infoLog, shaderHLSL, profile, optimizationFlags, true); + const static char *extraFlagNames[] = + { + "default", + "avoid flow control", + "prefer flow control" + }; + + int attempts = ArraySize(extraFlags); + + ID3DBlob *binary = (ID3DBlob*)mCompiler.compileToBinary(infoLog, shaderHLSL, profile, extraFlags, extraFlagNames, attempts); if (!binary) + { return NULL; + } - ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type); - binary->Release(); + ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers); + SafeRelease(binary); return executable; } +rx::UniformStorage *Renderer9::createUniformStorage(size_t storageSize) +{ + return new UniformStorage(storageSize); +} + bool Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) { return mBlit->boxFilter(source, dest); @@ -3223,7 +3133,7 @@ bool Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *s { Image9::copyLockableSurfaces(surf, source); result = mDevice->UpdateSurface(surf, NULL, dest, NULL); - surf->Release(); + SafeRelease(surf); } } else @@ -3260,14 +3170,50 @@ TextureStorage *Renderer9::createTextureStorage2D(SwapChain *swapChain) return new TextureStorage9_2D(this, swapChain9); } -TextureStorage *Renderer9::createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height) +TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) { - return new TextureStorage9_2D(this, levels, internalformat, usage, forceRenderable, width, height); + return new TextureStorage9_2D(this, internalformat, renderTarget, width, height, levels); } -TextureStorage *Renderer9::createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size) +TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) { - return new TextureStorage9_Cube(this, levels, internalformat, usage, forceRenderable, size); + return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels); +} + +TextureStorage *Renderer9::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + // 3D textures are not supported by the D3D9 backend. + UNREACHABLE(); + + return NULL; +} + +TextureStorage *Renderer9::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + // 2D array textures are not supported by the D3D9 backend. + UNREACHABLE(); + + return NULL; +} + +Texture2DImpl *Renderer9::createTexture2D() +{ + return new TextureD3D_2D(this); +} + +TextureCubeImpl *Renderer9::createTextureCube() +{ + return new TextureD3D_Cube(this); +} + +Texture3DImpl *Renderer9::createTexture3D() +{ + return new TextureD3D_3D(this); +} + +Texture2DArrayImpl *Renderer9::createTexture2DArray() +{ + return new TextureD3D_2DArray(this); } bool Renderer9::getLUID(LUID *adapterLuid) const @@ -3284,4 +3230,25 @@ bool Renderer9::getLUID(LUID *adapterLuid) const return false; } +GLenum Renderer9::getNativeTextureFormat(GLenum internalFormat) const +{ + return d3d9_gl::GetInternalFormat(gl_d3d9::GetTextureFormat(internalFormat)); +} + +rx::VertexConversionType Renderer9::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +{ + return d3d9::GetVertexConversionType(vertexFormat); +} + +GLenum Renderer9::getVertexComponentType(const gl::VertexFormat &vertexFormat) const +{ + D3DDECLTYPE declType = d3d9::GetNativeVertexFormat(vertexFormat); + return d3d9::GetDeclTypeComponentType(declType); +} + +void Renderer9::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const +{ + d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps, outExtensions); +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Renderer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h index 24fd2bdd84..070623c9db 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Renderer9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,15 +10,16 @@ #define LIBGLESV2_RENDERER_RENDERER9_H_ #include "common/angleutils.h" -#include "libGLESv2/mathutil.h" -#include "libGLESv2/renderer/ShaderCache.h" -#include "libGLESv2/renderer/d3d9/VertexDeclarationCache.h" +#include "common/mathutil.h" +#include "libGLESv2/renderer/d3d/HLSLCompiler.h" +#include "libGLESv2/renderer/d3d/d3d9/ShaderCache.h" +#include "libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h" #include "libGLESv2/renderer/Renderer.h" #include "libGLESv2/renderer/RenderTarget.h" namespace gl { -class Renderbuffer; +class FramebufferAttachment; } namespace rx @@ -27,11 +28,12 @@ class VertexDataManager; class IndexDataManager; class StreamingIndexBufferInterface; struct TranslatedAttribute; +class Blit9; class Renderer9 : public Renderer { public: - Renderer9(egl::Display *display, HDC hDc, bool softwareDevice); + Renderer9(egl::Display *display, EGLNativeDisplayType hDc, EGLint requestedDisplay); virtual ~Renderer9(); static Renderer9 *makeRenderer9(Renderer *renderer); @@ -57,22 +59,14 @@ class Renderer9 : public Renderer IDirect3DPixelShader9 *createPixelShader(const DWORD *function, size_t length); HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer); HRESULT createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer); -#if 0 - void *createTexture2D(); - void *createTextureCube(); - void *createQuery(); - void *createIndexBuffer(); - void *createVertexbuffer(); - - // state setup - void applyShaders(); - void applyConstants(); -#endif + virtual void generateSwizzle(gl::Texture *texture); virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler); virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture); + virtual bool setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]); + virtual void setRasterizerState(const gl::RasterizerState &rasterState); - virtual void setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::Color &blendColor, + virtual void setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, unsigned int sampleMask); virtual void setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, int stencilBackRef, bool frontFaceCCW); @@ -82,14 +76,19 @@ class Renderer9 : public Renderer bool ignoreViewport); virtual bool applyRenderTarget(gl::Framebuffer *frameBuffer); - virtual void applyShaders(gl::ProgramBinary *programBinary); - virtual void applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray); + virtual void applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive); + virtual void applyUniforms(const gl::ProgramBinary &programBinary); virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount); - virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances); + virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], + GLint first, GLsizei count, GLsizei instances); virtual GLenum applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); - virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances); - virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); + virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]); + + virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive); + virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); virtual void clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); @@ -101,21 +100,11 @@ class Renderer9 : public Renderer virtual bool testDeviceLost(bool notify); virtual bool testDeviceResettable(); - // Renderer capabilities IDirect3DDevice9 *getDevice() { return mDevice; } virtual DWORD getAdapterVendor() const; virtual std::string getRendererDescription() const; virtual GUID getAdapterIdentifier() const; - virtual bool getBGRATextureSupport() const; - virtual bool getDXT1TextureSupport(); - virtual bool getDXT3TextureSupport(); - virtual bool getDXT5TextureSupport(); - virtual bool getEventQuerySupport(); - virtual bool getFloat32TextureSupport(bool *filtering, bool *renderable); - virtual bool getFloat16TextureSupport(bool *filtering, bool *renderable); - virtual bool getLuminanceTextureSupport(); - virtual bool getLuminanceAlphaTextureSupport(); virtual unsigned int getMaxVertexTextureImageUnits() const; virtual unsigned int getMaxCombinedTextureImageUnits() const; virtual unsigned int getReservedVertexUniformVectors() const; @@ -123,93 +112,122 @@ class Renderer9 : public Renderer virtual unsigned int getMaxVertexUniformVectors() const; virtual unsigned int getMaxFragmentUniformVectors() const; virtual unsigned int getMaxVaryingVectors() const; - virtual bool getNonPower2TextureSupport() const; - virtual bool getDepthTextureSupport() const; - virtual bool getOcclusionQuerySupport() const; - virtual bool getInstancingSupport() const; - virtual bool getTextureFilterAnisotropySupport() const; - virtual float getTextureMaxAnisotropy() const; + virtual unsigned int getMaxVertexShaderUniformBuffers() const; + virtual unsigned int getMaxFragmentShaderUniformBuffers() const; + virtual unsigned int getReservedVertexUniformBuffers() const; + virtual unsigned int getReservedFragmentUniformBuffers() const; + virtual unsigned int getMaxTransformFeedbackBuffers() const; + virtual unsigned int getMaxTransformFeedbackSeparateComponents() const; + virtual unsigned int getMaxTransformFeedbackInterleavedComponents() const; + virtual unsigned int getMaxUniformBufferSize() const; virtual bool getShareHandleSupport() const; - virtual bool getDerivativeInstructionSupport() const; virtual bool getPostSubBufferSupport() const; + virtual int getMaxRecommendedElementsIndices() const; + virtual int getMaxRecommendedElementsVertices() const; + virtual bool getSRGBTextureSupport() const; virtual int getMajorShaderModel() const; - virtual float getMaxPointSize() const; - virtual int getMaxViewportDimension() const; - virtual int getMaxTextureWidth() const; - virtual int getMaxTextureHeight() const; - virtual bool get32BitIndexSupport() const; DWORD getCapsDeclTypes() const; virtual int getMinSwapInterval() const; virtual int getMaxSwapInterval() const; virtual GLsizei getMaxSupportedSamples() const; + virtual GLsizei getMaxSupportedFormatSamples(GLenum internalFormat) const; + virtual GLsizei getNumSampleCounts(GLenum internalFormat) const; + virtual void getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const; int getNearestSupportedSamples(D3DFORMAT format, int requested) const; - - virtual unsigned int getMaxRenderTargets() const; - - D3DFORMAT ConvertTextureInternalFormat(GLint internalformat); // Pixel operations virtual bool copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source); virtual bool copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source); + virtual bool copyToRenderTarget(TextureStorageInterface3D *dest, TextureStorageInterface3D *source); + virtual bool copyToRenderTarget(TextureStorageInterface2DArray *dest, TextureStorageInterface2DArray *source); virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level); virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level); + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface3D *storage, GLint level); + virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level); virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - bool blitRenderTarget, bool blitDepthStencil); - virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, - GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels); + const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter); + virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void* pixels); // RenderTarget creation virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth); - virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth); + virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples); // Shader operations - virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type); - virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, D3DWorkaroundType workaround); + virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers); + virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround); + virtual UniformStorage *createUniformStorage(size_t storageSize); // Image operations virtual Image *createImage(); virtual void generateMipmap(Image *dest, Image *source); virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain); - virtual TextureStorage *createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height); - virtual TextureStorage *createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size); + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels); + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + + // Texture creation + virtual Texture2DImpl *createTexture2D(); + virtual TextureCubeImpl *createTextureCube(); + virtual Texture3DImpl *createTexture3D(); + virtual Texture2DArrayImpl *createTexture2DArray(); // Buffer creation + virtual BufferImpl *createBuffer(); virtual VertexBuffer *createVertexBuffer(); virtual IndexBuffer *createIndexBuffer(); - virtual BufferStorage *createBufferStorage(); + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray(); // Query and Fence creation virtual QueryImpl *createQuery(GLenum type); virtual FenceImpl *createFence(); + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; + virtual bool fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + // D3D9-renderer specific methods bool boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); D3DPOOL getTexturePool(DWORD usage) const; virtual bool getLUID(LUID *adapterLuid) const; + virtual GLenum getNativeTextureFormat(GLenum internalFormat) const; + virtual rx::VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; private: DISALLOW_COPY_AND_ASSIGN(Renderer9); - void deinitialize(); + virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const; - void applyUniformnfv(gl::Uniform *targetUniform, const GLfloat *v); - void applyUniformniv(gl::Uniform *targetUniform, const GLint *v); - void applyUniformnbv(gl::Uniform *targetUniform, const GLint *v); + void release(); + + void applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v); + void applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v); + void applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v); void drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); void drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); - void getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray); bool copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); - gl::Renderbuffer *getNullColorbuffer(gl::Renderbuffer *depthbuffer); + gl::FramebufferAttachment *getNullColorbuffer(gl::FramebufferAttachment *depthbuffer); D3DPOOL getBufferPool(DWORD usage) const; @@ -226,13 +244,14 @@ class Renderer9 : public Renderer UINT mAdapter; D3DDEVTYPE mDeviceType; - bool mSoftwareDevice; // FIXME: Deprecate IDirect3D9 *mD3d9; // Always valid after successful initialization. IDirect3D9Ex *mD3d9Ex; // Might be null if D3D9Ex is not supported. IDirect3DDevice9 *mDevice; IDirect3DDevice9Ex *mDeviceEx; // Might be null if D3D9Ex is not supported. - Blit *mBlit; + HLSLCompiler mCompiler; + + Blit9 *mBlit; HWND mDeviceWindow; @@ -245,34 +264,21 @@ class Renderer9 : public Renderer GLsizei mRepeatDraw; bool mSceneStarted; - bool mSupportsNonPower2Textures; - bool mSupportsTextureFilterAnisotropy; int mMinSwapInterval; int mMaxSwapInterval; - bool mOcclusionQuerySupport; - bool mEventQuerySupport; bool mVertexTextureSupport; - bool mDepthTextureSupport; - - bool mFloat32TextureSupport; - bool mFloat32FilterSupport; - bool mFloat32RenderSupport; - - bool mFloat16TextureSupport; - bool mFloat16FilterSupport; - bool mFloat16RenderSupport; - - bool mDXT1TextureSupport; - bool mDXT3TextureSupport; - bool mDXT5TextureSupport; - - bool mLuminanceTextureSupport; - bool mLuminanceAlphaTextureSupport; + struct MultisampleSupportInfo + { + bool supportedSamples[D3DMULTISAMPLE_16_SAMPLES + 1]; + unsigned int maxSupportedSamples; + }; + typedef std::map<D3DFORMAT, MultisampleSupportInfo> MultisampleSupportMap; + MultisampleSupportMap mMultiSampleSupport; + unsigned int mMaxSupportedSamples; - std::map<D3DFORMAT, bool *> mMultiSampleSupport; - GLsizei mMaxSupportedSamples; + MultisampleSupportInfo getMultiSampleSupport(D3DFORMAT format); // current render target states unsigned int mAppliedRenderTargetSerial; @@ -308,7 +314,7 @@ class Renderer9 : public Renderer bool mForceSetBlendState; gl::BlendState mCurBlendState; - gl::Color mCurBlendColor; + gl::ColorF mCurBlendColor; GLuint mCurSampleMask; // Currently applied sampler states @@ -323,8 +329,10 @@ class Renderer9 : public Renderer unsigned int mCurPixelTextureSerials[gl::MAX_TEXTURE_IMAGE_UNITS]; unsigned int mAppliedIBSerial; - unsigned int mAppliedProgramBinarySerial; - + IDirect3DVertexShader9 *mAppliedVertexShader; + IDirect3DPixelShader9 *mAppliedPixelShader; + unsigned int mAppliedProgramSerial; + rx::dx_VertexConstants mVertexConstants; rx::dx_PixelConstants mPixelConstants; bool mDxUniformsDirty; @@ -346,7 +354,7 @@ class Renderer9 : public Renderer UINT lruCount; int width; int height; - gl::Renderbuffer *buffer; + gl::FramebufferAttachment *buffer; } mNullColorbufferCache[NUM_NULL_COLORBUFFER_CACHE_ENTRIES]; UINT mMaxNullColorbufferLRU; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h index 4391ac271a..a03528c9b5 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderCache.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h @@ -53,7 +53,7 @@ class ShaderCache // Random eviction policy. if (mMap.size() >= kMaxMapSize) { - mMap.begin()->second->Release(); + SafeRelease(mMap.begin()->second); mMap.erase(mMap.begin()); } @@ -67,7 +67,7 @@ class ShaderCache { for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it) { - it->second->Release(); + SafeRelease(it->second); } mMap.clear(); @@ -88,15 +88,7 @@ class ShaderCache return mDevice->CreatePixelShader(function, shader); } -#ifndef HASH_MAP -# ifdef _MSC_VER -# define HASH_MAP stdext::hash_map -# else -# define HASH_MAP std::unordered_map -# endif -#endif - - typedef HASH_MAP<std::string, ShaderObject*> Map; + typedef std::unordered_map<std::string, ShaderObject*> Map; Map mMap; IDirect3DDevice9 *mDevice; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/ShaderExecutable9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.cpp index 5decf9664d..c10ddbf6ce 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/ShaderExecutable9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.cpp @@ -8,7 +8,7 @@ // ShaderExecutable9.cpp: Implements a D3D9-specific class to contain shader // executable implementation details. -#include "libGLESv2/renderer/d3d9/ShaderExecutable9.h" +#include "libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h" #include "common/debug.h" @@ -31,14 +31,8 @@ ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirec ShaderExecutable9::~ShaderExecutable9() { - if (mVertexExecutable) - { - mVertexExecutable->Release(); - } - if (mPixelExecutable) - { - mPixelExecutable->Release(); - } + SafeRelease(mVertexExecutable); + SafeRelease(mPixelExecutable); } ShaderExecutable9 *ShaderExecutable9::makeShaderExecutable9(ShaderExecutable *executable) diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/ShaderExecutable9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h index fa1e6c2844..fa1e6c2844 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/ShaderExecutable9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/SwapChain9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp index dd8895d18d..c6567b635f 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/SwapChain9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp @@ -1,15 +1,16 @@ #include "precompiled.h" // -// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain. -#include "libGLESv2/renderer/d3d9/SwapChain9.h" -#include "libGLESv2/renderer/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/SwapChain9.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" namespace rx { @@ -35,38 +36,16 @@ SwapChain9::~SwapChain9() void SwapChain9::release() { - if (mSwapChain) - { - mSwapChain->Release(); - mSwapChain = NULL; - } - - if (mBackBuffer) - { - mBackBuffer->Release(); - mBackBuffer = NULL; - } - - if (mDepthStencil) - { - mDepthStencil->Release(); - mDepthStencil = NULL; - } - - if (mRenderTarget) - { - mRenderTarget->Release(); - mRenderTarget = NULL; - } - - if (mOffscreenTexture) - { - mOffscreenTexture->Release(); - mOffscreenTexture = NULL; - } + SafeRelease(mSwapChain); + SafeRelease(mBackBuffer); + SafeRelease(mDepthStencil); + SafeRelease(mRenderTarget); + SafeRelease(mOffscreenTexture); if (mWindow) + { mShareHandle = NULL; + } } static DWORD convertInterval(EGLint interval) @@ -111,29 +90,10 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI // Release specific resources to free up memory for the new render target, while the // old render target still exists for the purpose of preserving its contents. - if (mSwapChain) - { - mSwapChain->Release(); - mSwapChain = NULL; - } - - if (mBackBuffer) - { - mBackBuffer->Release(); - mBackBuffer = NULL; - } - - if (mOffscreenTexture) - { - mOffscreenTexture->Release(); - mOffscreenTexture = NULL; - } - - if (mDepthStencil) - { - mDepthStencil->Release(); - mDepthStencil = NULL; - } + SafeRelease(mSwapChain); + SafeRelease(mBackBuffer); + SafeRelease(mOffscreenTexture); + SafeRelease(mDepthStencil); HANDLE *pShareHandle = NULL; if (!mWindow && mRenderer->getShareHandleSupport()) @@ -142,8 +102,8 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI } result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, - gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat), D3DPOOL_DEFAULT, - &mOffscreenTexture, pShareHandle); + gl_d3d9::GetTextureFormat(mBackBufferFormat), + D3DPOOL_DEFAULT, &mOffscreenTexture, pShareHandle); if (FAILED(result)) { ERR("Could not create offscreen texture: %08lX", result); @@ -187,15 +147,15 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE); ASSERT(SUCCEEDED(result)); - oldRenderTarget->Release(); + SafeRelease(oldRenderTarget); } if (mWindow) { D3DPRESENT_PARAMETERS presentParameters = {0}; - presentParameters.AutoDepthStencilFormat = gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat); + presentParameters.AutoDepthStencilFormat = gl_d3d9::GetRenderFormat(mDepthBufferFormat); presentParameters.BackBufferCount = 1; - presentParameters.BackBufferFormat = gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat); + presentParameters.BackBufferFormat = gl_d3d9::GetRenderFormat(mBackBufferFormat); presentParameters.EnableAutoDepthStencil = FALSE; presentParameters.Flags = 0; presentParameters.hDeviceWindow = mWindow; @@ -247,7 +207,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI if (mDepthBufferFormat != GL_NONE) { result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight, - gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat), + gl_d3d9::GetRenderFormat(mDepthBufferFormat), D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL); if (FAILED(result)) @@ -276,7 +236,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI } // parameters should be validated/clamped by caller -EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint) { if (!mSwapChain) { @@ -356,6 +316,14 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) return EGL_BAD_ALLOC; } + // On Windows 8 systems, IDirect3DSwapChain9::Present sometimes returns 0x88760873 when the windows is + // in the process of entering/exiting fullscreen. This code doesn't seem to have any documentation. The + // device appears to be ok after emitting this error so simply return a failure to swap. + if (result == 0x88760873) + { + return EGL_BAD_MATCH; + } + // http://crbug.com/313210 // If our swap failed, trigger a device lost event. Resetting will work around an AMD-specific // device removed bug with lost contexts when reinstalling drivers. @@ -370,6 +338,7 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) // Increments refcount on surface. // caller must Release() the returned surface +// TODO: remove the AddRef to match SwapChain11 IDirect3DSurface9 *SwapChain9::getRenderTarget() { if (mRenderTarget) @@ -382,6 +351,7 @@ IDirect3DSurface9 *SwapChain9::getRenderTarget() // Increments refcount on surface. // caller must Release() the returned surface +// TODO: remove the AddRef to match SwapChain11 IDirect3DSurface9 *SwapChain9::getDepthStencil() { if (mDepthStencil) @@ -394,6 +364,7 @@ IDirect3DSurface9 *SwapChain9::getDepthStencil() // Increments refcount on texture. // caller must Release() the returned texture +// TODO: remove the AddRef to match SwapChain11 IDirect3DTexture9 *SwapChain9::getOffscreenTexture() { if (mOffscreenTexture) @@ -434,10 +405,10 @@ void SwapChain9::recreate() return; } - mSwapChain->Release(); + SafeRelease(mSwapChain); mSwapChain = newSwapChain; - mBackBuffer->Release(); + SafeRelease(mBackBuffer); result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); ASSERT(SUCCEEDED(result)); } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/SwapChain9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h index 16a62bd86f..4d756f80d1 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/SwapChain9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h @@ -25,7 +25,7 @@ class SwapChain9 : public SwapChain EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint); virtual void recreate(); virtual IDirect3DSurface9 *getRenderTarget(); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/TextureStorage9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp index 2486a9a5bf..b065ee80fe 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/TextureStorage9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" // -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,17 +10,19 @@ // D3D9 texture. #include "libGLESv2/main.h" -#include "libGLESv2/renderer/d3d9/Renderer9.h" -#include "libGLESv2/renderer/d3d9/TextureStorage9.h" -#include "libGLESv2/renderer/d3d9/SwapChain9.h" -#include "libGLESv2/renderer/d3d9/RenderTarget9.h" -#include "libGLESv2/renderer/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" +#include "libGLESv2/renderer/d3d/d3d9/SwapChain9.h" +#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" #include "libGLESv2/Texture.h" namespace rx { TextureStorage9::TextureStorage9(Renderer *renderer, DWORD usage) - : mLodOffset(0), + : mTopLevel(0), mRenderer(Renderer9::makeRenderer9(renderer)), mD3DUsage(usage), mD3DPool(mRenderer->getTexturePool(usage)) @@ -37,46 +39,23 @@ TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage) return static_cast<TextureStorage9*>(storage); } -DWORD TextureStorage9::GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable) +DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget) { DWORD d3dusage = 0; - if (d3dfmt == D3DFMT_INTZ) + if (gl::GetDepthBits(internalformat) > 0 || + gl::GetStencilBits(internalformat) > 0) { d3dusage |= D3DUSAGE_DEPTHSTENCIL; } - else if(forceRenderable || (TextureStorage9::IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE))) + else if (renderTarget && (gl_d3d9::GetRenderFormat(internalformat) != D3DFMT_UNKNOWN)) { d3dusage |= D3DUSAGE_RENDERTARGET; } + return d3dusage; } -bool TextureStorage9::IsTextureFormatRenderable(D3DFORMAT format) -{ - if (format == D3DFMT_INTZ) - { - return true; - } - switch(format) - { - case D3DFMT_L8: - case D3DFMT_A8L8: - case D3DFMT_DXT1: - case D3DFMT_DXT3: - case D3DFMT_DXT5: - return false; - case D3DFMT_A8R8G8B8: - case D3DFMT_X8R8G8B8: - case D3DFMT_A16B16G16R16F: - case D3DFMT_A32B32G32R32F: - return true; - default: - UNREACHABLE(); - } - - return false; -} bool TextureStorage9::isRenderTarget() const { @@ -98,17 +77,18 @@ DWORD TextureStorage9::getUsage() const return mD3DUsage; } -int TextureStorage9::getLodOffset() const +int TextureStorage9::getTopLevel() const { - return mLodOffset; + return mTopLevel; } -int TextureStorage9::levelCount() +int TextureStorage9::getLevelCount() const { - return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0; + return getBaseTexture() ? (getBaseTexture()->GetLevelCount() - getTopLevel()) : 0; } -TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain) : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET) +TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain) + : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET) { IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture(); mTexture = surfaceTexture; @@ -117,8 +97,8 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain initializeRenderTarget(); } -TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height) - : TextureStorage9(renderer, GetTextureUsage(Renderer9::makeRenderer9(renderer)->ConvertTextureInternalFormat(internalformat), usage, forceRenderable)) +TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) + : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) { mTexture = NULL; mRenderTarget = NULL; @@ -127,9 +107,11 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, int levels, GLenum in if (width > 0 && height > 0) { IDirect3DDevice9 *device = mRenderer->getDevice(); - gl::MakeValidSize(false, gl::IsCompressed(internalformat), &width, &height, &mLodOffset); - HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(), - mRenderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL); + D3DFORMAT format = gl_d3d9::GetTextureFormat(internalformat); + d3d9::MakeValidSize(false, format, &width, &height, &mTopLevel); + UINT creationLevels = (levels == 0) ? 0 : mTopLevel + levels; + + HRESULT result = device->CreateTexture(width, height, creationLevels, getUsage(), format, getPool(), &mTexture, NULL); if (FAILED(result)) { @@ -143,12 +125,8 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, int levels, GLenum in TextureStorage9_2D::~TextureStorage9_2D() { - if (mTexture) - { - mTexture->Release(); - } - - delete mRenderTarget; + SafeRelease(mTexture); + SafeDelete(mRenderTarget); } TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *storage) @@ -165,11 +143,12 @@ IDirect3DSurface9 *TextureStorage9_2D::getSurfaceLevel(int level, bool dirty) if (mTexture) { - HRESULT result = mTexture->GetSurfaceLevel(level + mLodOffset, &surface); + HRESULT result = mTexture->GetSurfaceLevel(level + mTopLevel, &surface); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); // With managed textures the driver needs to be informed of updates to the lower mipmap levels - if (level + mLodOffset != 0 && isManaged() && dirty) + if (level + mTopLevel != 0 && isManaged() && dirty) { mTexture->AddDirtyRect(NULL); } @@ -178,7 +157,7 @@ IDirect3DSurface9 *TextureStorage9_2D::getSurfaceLevel(int level, bool dirty) return surface; } -RenderTarget *TextureStorage9_2D::getRenderTarget() +RenderTarget *TextureStorage9_2D::getRenderTarget(int level) { return mRenderTarget; } @@ -193,8 +172,8 @@ void TextureStorage9_2D::generateMipmap(int level) mRenderer->boxFilter(upper, lower); } - if (upper != NULL) upper->Release(); - if (lower != NULL) lower->Release(); + SafeRelease(upper); + SafeRelease(lower); } IDirect3DBaseTexture9 *TextureStorage9_2D::getBaseTexture() const @@ -214,8 +193,8 @@ void TextureStorage9_2D::initializeRenderTarget() } } -TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size) - : TextureStorage9(renderer, GetTextureUsage(Renderer9::makeRenderer9(renderer)->ConvertTextureInternalFormat(internalformat), usage, forceRenderable)) +TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels) + : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) { mTexture = NULL; for (int i = 0; i < 6; ++i) @@ -229,9 +208,11 @@ TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, int levels, GLenu { IDirect3DDevice9 *device = mRenderer->getDevice(); int height = size; - gl::MakeValidSize(false, gl::IsCompressed(internalformat), &size, &height, &mLodOffset); - HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(), - mRenderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL); + D3DFORMAT format = gl_d3d9::GetTextureFormat(internalformat); + d3d9::MakeValidSize(false, format, &size, &height, &mTopLevel); + UINT creationLevels = (levels == 0) ? 0 : mTopLevel + levels; + + HRESULT result = device->CreateCubeTexture(size, creationLevels, getUsage(), format, getPool(), &mTexture, NULL); if (FAILED(result)) { @@ -245,14 +226,11 @@ TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, int levels, GLenu TextureStorage9_Cube::~TextureStorage9_Cube() { - if (mTexture) - { - mTexture->Release(); - } + SafeRelease(mTexture); for (int i = 0; i < 6; ++i) { - delete mRenderTarget[i]; + SafeDelete(mRenderTarget[i]); } } @@ -271,7 +249,8 @@ IDirect3DSurface9 *TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, in if (mTexture) { D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget); - HRESULT result = mTexture->GetCubeMapSurface(face, level + mLodOffset, &surface); + HRESULT result = mTexture->GetCubeMapSurface(face, level + mTopLevel, &surface); + UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); // With managed textures the driver needs to be informed of updates to the lower mipmap levels @@ -284,23 +263,23 @@ IDirect3DSurface9 *TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, in return surface; } -RenderTarget *TextureStorage9_Cube::getRenderTarget(GLenum faceTarget) +RenderTarget *TextureStorage9_Cube::getRenderTargetFace(GLenum faceTarget, int level) { - return mRenderTarget[gl::TextureCubeMap::faceIndex(faceTarget)]; + return mRenderTarget[TextureD3D_Cube::targetToIndex(faceTarget)]; } -void TextureStorage9_Cube::generateMipmap(int face, int level) +void TextureStorage9_Cube::generateMipmap(int faceIndex, int level) { - IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level - 1, false); - IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true); + IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level - 1, false); + IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, true); if (upper != NULL && lower != NULL) { mRenderer->boxFilter(upper, lower); } - if (upper != NULL) upper->Release(); - if (lower != NULL) lower->Release(); + SafeRelease(upper); + SafeRelease(lower); } IDirect3DBaseTexture9 *TextureStorage9_Cube::getBaseTexture() const diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/TextureStorage9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h index 86f551a131..cc7c155d34 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/TextureStorage9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -11,7 +11,7 @@ #ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE9_H_ #define LIBGLESV2_RENDERER_TEXTURESTORAGE9_H_ -#include "libGLESv2/renderer/TextureStorage.h" +#include "libGLESv2/renderer/d3d/TextureStorage.h" #include "common/debug.h" namespace rx @@ -20,37 +20,37 @@ class Renderer9; class SwapChain9; class RenderTarget; class RenderTarget9; -class Blit; class TextureStorage9 : public TextureStorage { public: - TextureStorage9(Renderer *renderer, DWORD usage); virtual ~TextureStorage9(); static TextureStorage9 *makeTextureStorage9(TextureStorage *storage); - static DWORD GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable); - static bool IsTextureFormatRenderable(D3DFORMAT format); + static DWORD GetTextureUsage(GLenum internalformat, bool renderTarget); D3DPOOL getPool() const; DWORD getUsage() const; virtual IDirect3DBaseTexture9 *getBaseTexture() const = 0; - virtual RenderTarget *getRenderTarget() { return NULL; } - virtual RenderTarget *getRenderTarget(GLenum faceTarget) { return NULL; } + virtual RenderTarget *getRenderTarget(int level) { return NULL; } + virtual RenderTarget *getRenderTargetFace(GLenum faceTarget, int level) { return NULL; } + virtual RenderTarget *getRenderTargetLayer(int mipLevel, int layer) { return NULL; } virtual void generateMipmap(int level) {}; virtual void generateMipmap(int face, int level) {}; - virtual int getLodOffset() const; + virtual int getTopLevel() const; virtual bool isRenderTarget() const; virtual bool isManaged() const; - virtual int levelCount(); + virtual int getLevelCount() const; protected: - int mLodOffset; + int mTopLevel; Renderer9 *mRenderer; + TextureStorage9(Renderer *renderer, DWORD usage); + private: DISALLOW_COPY_AND_ASSIGN(TextureStorage9); @@ -62,13 +62,13 @@ class TextureStorage9_2D : public TextureStorage9 { public: TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain); - TextureStorage9_2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height); + TextureStorage9_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); virtual ~TextureStorage9_2D(); static TextureStorage9_2D *makeTextureStorage9_2D(TextureStorage *storage); IDirect3DSurface9 *getSurfaceLevel(int level, bool dirty); - virtual RenderTarget *getRenderTarget(); + virtual RenderTarget *getRenderTarget(int level); virtual IDirect3DBaseTexture9 *getBaseTexture() const; virtual void generateMipmap(int level); @@ -84,15 +84,15 @@ class TextureStorage9_2D : public TextureStorage9 class TextureStorage9_Cube : public TextureStorage9 { public: - TextureStorage9_Cube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size); + TextureStorage9_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels); virtual ~TextureStorage9_Cube(); static TextureStorage9_Cube *makeTextureStorage9_Cube(TextureStorage *storage); IDirect3DSurface9 *getCubeMapSurface(GLenum faceTarget, int level, bool dirty); - virtual RenderTarget *getRenderTarget(GLenum faceTarget); + virtual RenderTarget *getRenderTargetFace(GLenum faceTarget, int level); virtual IDirect3DBaseTexture9 *getBaseTexture() const; - virtual void generateMipmap(int face, int level); + virtual void generateMipmap(int faceIndex, int level); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage9_Cube); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h new file mode 100644 index 0000000000..66a6c64d81 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h @@ -0,0 +1,43 @@ +// +// Copyright 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexArray9.h: Defines the rx::VertexArray9 class which implements rx::VertexArrayImpl. + +#ifndef LIBGLESV2_RENDERER_VERTEXARRAY9_H_ +#define LIBGLESV2_RENDERER_VERTEXARRAY9_H_ + +#include "libGLESv2/renderer/VertexArrayImpl.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ +class Renderer9; + +class VertexArray9 : public VertexArrayImpl +{ + public: + VertexArray9(rx::Renderer9 *renderer) + : VertexArrayImpl(), + mRenderer(renderer) + { + } + + virtual ~VertexArray9() { } + + virtual void setElementArrayBuffer(const gl::Buffer *buffer) { } + virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { } + virtual void setAttributeDivisor(size_t idx, GLuint divisor) { } + virtual void enableAttribute(size_t idx, bool enabledState) { } + + private: + DISALLOW_COPY_AND_ASSIGN(VertexArray9); + + rx::Renderer9 *mRenderer; +}; + +} + +#endif // LIBGLESV2_RENDERER_VERTEXARRAY9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp new file mode 100644 index 0000000000..d260640dbe --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp @@ -0,0 +1,252 @@ +#include "precompiled.h" +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer9.cpp: Defines the D3D9 VertexBuffer implementation. + +#include "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libGLESv2/renderer/vertexconversion.h" +#include "libGLESv2/renderer/BufferImpl.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" + +#include "libGLESv2/Buffer.h" + +namespace rx +{ + +VertexBuffer9::VertexBuffer9(rx::Renderer9 *const renderer) : mRenderer(renderer) +{ + mVertexBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; +} + +VertexBuffer9::~VertexBuffer9() +{ + SafeRelease(mVertexBuffer); +} + +bool VertexBuffer9::initialize(unsigned int size, bool dynamicUsage) +{ + SafeRelease(mVertexBuffer); + + updateSerial(); + + if (size > 0) + { + DWORD flags = D3DUSAGE_WRITEONLY; + if (dynamicUsage) + { + flags |= D3DUSAGE_DYNAMIC; + } + + HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", size); + return false; + } + } + + mBufferSize = size; + mDynamicUsage = dynamicUsage; + return true; +} + +VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer)); + return static_cast<VertexBuffer9*>(vertexBuffer); +} + +bool VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) +{ + if (mVertexBuffer) + { + gl::Buffer *buffer = attrib.buffer.get(); + + int inputStride = gl::ComputeVertexAttributeStride(attrib); + int elementSize = gl::ComputeVertexAttributeTypeSize(attrib); + + DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; + + void *mapPtr = NULL; + + unsigned int mapSize; + if (!spaceRequired(attrib, count, instances, &mapSize)) + { + return false; + } + + HRESULT result = mVertexBuffer->Lock(offset, mapSize, &mapPtr, lockFlags); + + if (FAILED(result)) + { + ERR("Lock failed with error 0x%08x", result); + return false; + } + + const char *input = NULL; + if (attrib.enabled) + { + if (buffer) + { + BufferImpl *storage = buffer->getImplementation(); + input = static_cast<const char*>(storage->getData()) + static_cast<int>(attrib.offset); + } + else + { + input = static_cast<const char*>(attrib.pointer); + } + } + else + { + input = reinterpret_cast<const char*>(currentValue.FloatValues); + } + + if (instances == 0 || attrib.divisor == 0) + { + input += inputStride * start; + } + + gl::VertexFormat vertexFormat(attrib, currentValue.Type); + bool needsConversion = (d3d9::GetVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) > 0; + + if (!needsConversion && inputStride == elementSize) + { + size_t copySize = static_cast<size_t>(count) * static_cast<size_t>(inputStride); + memcpy(mapPtr, input, copySize); + } + else + { + VertexCopyFunction copyFunction = d3d9::GetVertexCopyFunction(vertexFormat); + copyFunction(input, inputStride, count, mapPtr); + } + + mVertexBuffer->Unlock(); + + return true; + } + else + { + ERR("Vertex buffer not initialized."); + return false; + } +} + +bool VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, + unsigned int *outSpaceRequired) const +{ + return spaceRequired(attrib, count, instances, outSpaceRequired); +} + +unsigned int VertexBuffer9::getBufferSize() const +{ + return mBufferSize; +} + +bool VertexBuffer9::setBufferSize(unsigned int size) +{ + if (size > mBufferSize) + { + return initialize(size, mDynamicUsage); + } + else + { + return true; + } +} + +bool VertexBuffer9::discard() +{ + if (mVertexBuffer) + { + void *dummy; + HRESULT result; + + result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + if (FAILED(result)) + { + ERR("Discard lock failed with error 0x%08x", result); + return false; + } + + result = mVertexBuffer->Unlock(); + if (FAILED(result)) + { + ERR("Discard unlock failed with error 0x%08x", result); + return false; + } + + return true; + } + else + { + ERR("Vertex buffer not initialized."); + return false; + } +} + +IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const +{ + return mVertexBuffer; +} + +bool VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, + unsigned int *outSpaceRequired) +{ + gl::VertexFormat vertexFormat(attrib, GL_FLOAT); + unsigned int elementSize = d3d9::GetVertexElementSize(vertexFormat); + + if (attrib.enabled) + { + unsigned int elementCount = 0; + if (instances == 0 || attrib.divisor == 0) + { + elementCount = count; + } + else + { + if (static_cast<unsigned int>(instances) < std::numeric_limits<unsigned int>::max() - (attrib.divisor - 1)) + { + // Round up + elementCount = (static_cast<unsigned int>(instances) + (attrib.divisor - 1)) / attrib.divisor; + } + else + { + elementCount = static_cast<unsigned int>(instances) / attrib.divisor; + } + } + + if (elementSize <= std::numeric_limits<unsigned int>::max() / elementCount) + { + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * elementCount; + } + return true; + } + else + { + return false; + } + } + else + { + const unsigned int elementSize = 4; + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * 4; + } + return true; + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h new file mode 100644 index 0000000000..fc4b6b6d26 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h @@ -0,0 +1,54 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexBuffer9.h: Defines the D3D9 VertexBuffer implementation. + +#ifndef LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ +#define LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ + +#include "libGLESv2/renderer/d3d/VertexBuffer.h" + +namespace rx +{ +class Renderer9; + +class VertexBuffer9 : public VertexBuffer +{ + public: + explicit VertexBuffer9(rx::Renderer9 *const renderer); + virtual ~VertexBuffer9(); + + virtual bool initialize(unsigned int size, bool dynamicUsage); + + static VertexBuffer9 *makeVertexBuffer9(VertexBuffer *vertexBuffer); + + virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset); + + virtual bool getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const; + + virtual unsigned int getBufferSize() const; + virtual bool setBufferSize(unsigned int size); + virtual bool discard(); + + IDirect3DVertexBuffer9 *getBuffer() const; + + private: + DISALLOW_COPY_AND_ASSIGN(VertexBuffer9); + + rx::Renderer9 *const mRenderer; + + IDirect3DVertexBuffer9 *mVertexBuffer; + unsigned int mBufferSize; + bool mDynamicUsage; + + static bool spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, + unsigned int *outSpaceRequired); +}; + +} + +#endif // LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/VertexDeclarationCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp index e5c8a14232..303d8ad299 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/VertexDeclarationCache.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp @@ -8,9 +8,10 @@ // VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations. #include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/renderer/d3d9/VertexBuffer9.h" -#include "libGLESv2/renderer/d3d9/VertexDeclarationCache.h" +#include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" namespace rx { @@ -36,10 +37,7 @@ VertexDeclarationCache::~VertexDeclarationCache() { for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) { - if (mVertexDeclCache[i].vertexDeclaration) - { - mVertexDeclCache[i].vertexDeclaration->Release(); - } + SafeRelease(mVertexDeclCache[i].vertexDeclaration); } } @@ -134,9 +132,11 @@ GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, Transl mAppliedVBs[stream].offset = attributes[i].offset; } + gl::VertexFormat vertexFormat(*attributes[i].attribute, GL_FLOAT); + element->Stream = stream; element->Offset = 0; - element->Type = attributes[i].attribute->mArrayEnabled ? vertexBuffer->getDeclType(*attributes[i].attribute) : D3DDECLTYPE_FLOAT4; + element->Type = d3d9::GetNativeVertexFormat(vertexFormat); element->Method = D3DDECLMETHOD_DEFAULT; element->Usage = D3DDECLUSAGE_TEXCOORD; element->UsageIndex = programBinary->getSemanticIndex(i); @@ -188,8 +188,7 @@ GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, Transl if (lastCache->vertexDeclaration != NULL) { - lastCache->vertexDeclaration->Release(); - lastCache->vertexDeclaration = NULL; + SafeRelease(lastCache->vertexDeclaration); // mLastSetVDecl is set to the replacement, so we don't have to worry // about it. } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/VertexDeclarationCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h index 3fc024a9ba..004e28df4f 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/VertexDeclarationCache.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h @@ -9,7 +9,7 @@ #ifndef LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_ #define LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_ -#include "libGLESv2/renderer/VertexDataManager.h" +#include "libGLESv2/renderer/d3d/VertexDataManager.h" namespace gl { diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp new file mode 100644 index 0000000000..f5d1da62b3 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp @@ -0,0 +1,820 @@ +#include "precompiled.h" +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils9.cpp: Queries for GL image formats and their translations to D3D9 +// formats. + +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "libGLESv2/renderer/generatemip.h" +#include "libGLESv2/renderer/loadimage.h" +#include "libGLESv2/renderer/copyimage.h" +#include "libGLESv2/renderer/vertexconversion.h" + +namespace rx +{ + +// Each GL internal format corresponds to one D3D format and data loading function. +// Due to not all formats being available all the time, some of the function/format types are wrapped +// in templates that perform format support queries on a Renderer9 object which is supplied +// when requesting the function or format. + +typedef bool(*FallbackPredicateFunction)(); + +template <FallbackPredicateFunction pred, LoadImageFunction prefered, LoadImageFunction fallback> +static void FallbackLoad(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + if (pred()) + { + prefered(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); + } + else + { + fallback(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); + } +} + +static void UnreachableLoad(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + UNREACHABLE(); +} + +const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z'))); +const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L'))); + +struct D3D9FormatInfo +{ + D3DFORMAT mTexFormat; + D3DFORMAT mRenderFormat; + LoadImageFunction mLoadFunction; + + D3D9FormatInfo() + : mTexFormat(D3DFMT_NULL), mRenderFormat(D3DFMT_NULL), mLoadFunction(NULL) + { } + + D3D9FormatInfo(D3DFORMAT textureFormat, D3DFORMAT renderFormat, LoadImageFunction loadFunc) + : mTexFormat(textureFormat), mRenderFormat(renderFormat), mLoadFunction(loadFunc) + { } +}; + +typedef std::pair<GLenum, D3D9FormatInfo> D3D9FormatPair; +typedef std::map<GLenum, D3D9FormatInfo> D3D9FormatMap; + +static D3D9FormatMap BuildD3D9FormatMap() +{ + D3D9FormatMap map; + + // | Internal format | Texture format | Render format | Load function | + map.insert(D3D9FormatPair(GL_NONE, D3D9FormatInfo(D3DFMT_NULL, D3DFMT_NULL, UnreachableLoad ))); + + map.insert(D3D9FormatPair(GL_DEPTH_COMPONENT16, D3D9FormatInfo(D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ))); + map.insert(D3D9FormatPair(GL_DEPTH_COMPONENT32_OES, D3D9FormatInfo(D3DFMT_INTZ, D3DFMT_D32, UnreachableLoad ))); + map.insert(D3D9FormatPair(GL_DEPTH24_STENCIL8_OES, D3D9FormatInfo(D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ))); + map.insert(D3D9FormatPair(GL_STENCIL_INDEX8, D3D9FormatInfo(D3DFMT_UNKNOWN, D3DFMT_D24S8, UnreachableLoad ))); // TODO: What's the texture format? + + map.insert(D3D9FormatPair(GL_RGBA32F_EXT, D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative<GLfloat, 4> ))); + map.insert(D3D9FormatPair(GL_RGB32F_EXT, D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative3To4<GLfloat, gl::Float32One>))); + map.insert(D3D9FormatPair(GL_RG32F_EXT, D3D9FormatInfo(D3DFMT_G32R32F, D3DFMT_G32R32F, LoadToNative<GLfloat, 2> ))); + map.insert(D3D9FormatPair(GL_R32F_EXT, D3D9FormatInfo(D3DFMT_R32F, D3DFMT_R32F, LoadToNative<GLfloat, 1> ))); + map.insert(D3D9FormatPair(GL_ALPHA32F_EXT, D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadA32FToRGBA32F ))); + map.insert(D3D9FormatPair(GL_LUMINANCE32F_EXT, D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadL32FToRGBA32F ))); + map.insert(D3D9FormatPair(GL_LUMINANCE_ALPHA32F_EXT, D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadLA32FToRGBA32F ))); + + map.insert(D3D9FormatPair(GL_RGBA16F_EXT, D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative<GLhalf, 4> ))); + map.insert(D3D9FormatPair(GL_RGB16F_EXT, D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative3To4<GLhalf, gl::Float16One> ))); + map.insert(D3D9FormatPair(GL_RG16F_EXT, D3D9FormatInfo(D3DFMT_G16R16F, D3DFMT_G16R16F, LoadToNative<GLhalf, 2> ))); + map.insert(D3D9FormatPair(GL_R16F_EXT, D3D9FormatInfo(D3DFMT_R16F, D3DFMT_R16F, LoadToNative<GLhalf, 1> ))); + map.insert(D3D9FormatPair(GL_ALPHA16F_EXT, D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadA16FToRGBA16F ))); + map.insert(D3D9FormatPair(GL_LUMINANCE16F_EXT, D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadL16FToRGBA16F ))); + map.insert(D3D9FormatPair(GL_LUMINANCE_ALPHA16F_EXT, D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadLA16FToRGBA16F ))); + + map.insert(D3D9FormatPair(GL_ALPHA8_EXT, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad<gl::supportsSSE2, LoadA8ToBGRA8_SSE2, LoadA8ToBGRA8>))); + + map.insert(D3D9FormatPair(GL_RGB8_OES, D3D9FormatInfo(D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRGB8ToBGRX8 ))); + map.insert(D3D9FormatPair(GL_RGB565, D3D9FormatInfo(D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR5G6B5ToBGRA8 ))); + map.insert(D3D9FormatPair(GL_RGBA8_OES, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad<gl::supportsSSE2, LoadRGBA8ToBGRA8_SSE2, LoadRGBA8ToBGRA8>))); + map.insert(D3D9FormatPair(GL_RGBA4, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA4ToBGRA8 ))); + map.insert(D3D9FormatPair(GL_RGB5_A1, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGB5A1ToBGRA8 ))); + map.insert(D3D9FormatPair(GL_R8_EXT, D3D9FormatInfo(D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR8ToBGRX8 ))); + map.insert(D3D9FormatPair(GL_RG8_EXT, D3D9FormatInfo(D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRG8ToBGRX8 ))); + + map.insert(D3D9FormatPair(GL_BGRA8_EXT, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadToNative<GLubyte, 4> ))); + map.insert(D3D9FormatPair(GL_BGRA4_ANGLEX, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGRA4ToBGRA8 ))); + map.insert(D3D9FormatPair(GL_BGR5_A1_ANGLEX, D3D9FormatInfo(D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGR5A1ToBGRA8 ))); + + map.insert(D3D9FormatPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, D3D9FormatInfo(D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ))); + map.insert(D3D9FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, D3D9FormatInfo(D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ))); + map.insert(D3D9FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, D3D9FormatInfo(D3DFMT_DXT3, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> ))); + map.insert(D3D9FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, D3D9FormatInfo(D3DFMT_DXT5, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> ))); + + // These formats require checking if the renderer supports D3DFMT_L8 or D3DFMT_A8L8 and + // then changing the format and loading function appropriately. + map.insert(D3D9FormatPair(GL_LUMINANCE8_EXT, D3D9FormatInfo(D3DFMT_L8, D3DFMT_UNKNOWN, LoadToNative<GLubyte, 1> ))); + map.insert(D3D9FormatPair(GL_LUMINANCE8_ALPHA8_EXT, D3D9FormatInfo(D3DFMT_A8L8, D3DFMT_UNKNOWN, LoadToNative<GLubyte, 2> ))); + + return map; +} + +static bool GetD3D9FormatInfo(GLenum internalFormat, D3D9FormatInfo *outFormatInfo) +{ + static const D3D9FormatMap formatMap = BuildD3D9FormatMap(); + D3D9FormatMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + if (outFormatInfo) + { + *outFormatInfo = iter->second; + } + return true; + } + else + { + return false; + } +} + +// A map to determine the pixel size and mip generation function of a given D3D format +struct D3DFormatInfo +{ + GLuint mPixelBits; + GLuint mBlockWidth; + GLuint mBlockHeight; + GLenum mInternalFormat; + + MipGenerationFunction mMipGenerationFunction; + ColorReadFunction mColorReadFunction; + + D3DFormatInfo() + : mPixelBits(0), mBlockWidth(0), mBlockHeight(0), mInternalFormat(GL_NONE), mMipGenerationFunction(NULL), + mColorReadFunction(NULL) + { } + + D3DFormatInfo(GLuint pixelBits, GLuint blockWidth, GLuint blockHeight, GLenum internalFormat, + MipGenerationFunction mipFunc, ColorReadFunction readFunc) + : mPixelBits(pixelBits), mBlockWidth(blockWidth), mBlockHeight(blockHeight), mInternalFormat(internalFormat), + mMipGenerationFunction(mipFunc), mColorReadFunction(readFunc) + { } +}; + +typedef std::pair<D3DFORMAT, D3DFormatInfo> D3D9FormatInfoPair; +typedef std::map<D3DFORMAT, D3DFormatInfo> D3D9FormatInfoMap; + +static D3D9FormatInfoMap BuildD3D9FormatInfoMap() +{ + D3D9FormatInfoMap map; + + // | D3DFORMAT | | S |W |H | Internal format | Mip generation function | Color read function | + map.insert(D3D9FormatInfoPair(D3DFMT_NULL, D3DFormatInfo( 0, 0, 0, GL_NONE, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_UNKNOWN, D3DFormatInfo( 0, 0, 0, GL_NONE, NULL, NULL ))); + + map.insert(D3D9FormatInfoPair(D3DFMT_L8, D3DFormatInfo( 8, 1, 1, GL_LUMINANCE8_EXT, GenerateMip<L8>, ReadColor<L8, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A8, D3DFormatInfo( 8, 1, 1, GL_ALPHA8_EXT, GenerateMip<A8>, ReadColor<A8, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A8L8, D3DFormatInfo( 16, 1, 1, GL_LUMINANCE8_ALPHA8_EXT, GenerateMip<A8L8>, ReadColor<A8L8, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A4R4G4B4, D3DFormatInfo( 16, 1, 1, GL_BGRA4_ANGLEX, GenerateMip<B4G4R4A4>, ReadColor<B4G4R4A4, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A1R5G5B5, D3DFormatInfo( 16, 1, 1, GL_BGR5_A1_ANGLEX, GenerateMip<B5G5R5A1>, ReadColor<B5G5R5A1, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_R5G6B5, D3DFormatInfo( 16, 1, 1, GL_RGB565, GenerateMip<R5G6B5>, ReadColor<R5G6B5, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_X8R8G8B8, D3DFormatInfo( 32, 1, 1, GL_BGRA8_EXT, GenerateMip<B8G8R8X8>, ReadColor<B8G8R8X8, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A8R8G8B8, D3DFormatInfo( 32, 1, 1, GL_BGRA8_EXT, GenerateMip<B8G8R8A8>, ReadColor<B8G8R8A8, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_R16F, D3DFormatInfo( 16, 1, 1, GL_R16F_EXT, GenerateMip<R16F>, ReadColor<R16F, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_G16R16F, D3DFormatInfo( 32, 1, 1, GL_RG16F_EXT, GenerateMip<R16G16F>, ReadColor<R16G16F, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A16B16G16R16F, D3DFormatInfo( 64, 1, 1, GL_RGBA16F_EXT, GenerateMip<R16G16B16A16F>, ReadColor<R16G16B16A16F, GLfloat>))); + map.insert(D3D9FormatInfoPair(D3DFMT_R32F, D3DFormatInfo( 32, 1, 1, GL_R32F_EXT, GenerateMip<R32F>, ReadColor<R32F, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_G32R32F, D3DFormatInfo( 64, 1, 1, GL_RG32F_EXT, GenerateMip<R32G32F>, ReadColor<R32G32F, GLfloat> ))); + map.insert(D3D9FormatInfoPair(D3DFMT_A32B32G32R32F, D3DFormatInfo(128, 1, 1, GL_RGBA32F_EXT, GenerateMip<R32G32B32A32F>, ReadColor<R32G32B32A32F, GLfloat>))); + + map.insert(D3D9FormatInfoPair(D3DFMT_D16, D3DFormatInfo( 16, 1, 1, GL_DEPTH_COMPONENT16, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_D24S8, D3DFormatInfo( 32, 1, 1, GL_DEPTH24_STENCIL8_OES, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_D24X8, D3DFormatInfo( 32, 1, 1, GL_DEPTH_COMPONENT16, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_D32, D3DFormatInfo( 32, 1, 1, GL_DEPTH_COMPONENT32_OES, NULL, NULL ))); + + map.insert(D3D9FormatInfoPair(D3DFMT_INTZ, D3DFormatInfo( 32, 1, 1, GL_DEPTH24_STENCIL8_OES, NULL, NULL ))); + + map.insert(D3D9FormatInfoPair(D3DFMT_DXT1, D3DFormatInfo( 64, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_DXT3, D3DFormatInfo(128, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, NULL, NULL ))); + map.insert(D3D9FormatInfoPair(D3DFMT_DXT5, D3DFormatInfo(128, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, NULL, NULL ))); + + return map; +} + +static const D3D9FormatInfoMap &GetD3D9FormatInfoMap() +{ + static const D3D9FormatInfoMap infoMap = BuildD3D9FormatInfoMap(); + return infoMap; +} + +static bool GetD3D9FormatInfo(D3DFORMAT format, D3DFormatInfo *outFormatInfo) +{ + const D3D9FormatInfoMap &infoMap = GetD3D9FormatInfoMap(); + D3D9FormatInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + if (outFormatInfo) + { + *outFormatInfo = iter->second; + } + return true; + } + else + { + return false; + } +} +static d3d9::D3DFormatSet BuildAllD3DFormatSet() +{ + d3d9::D3DFormatSet set; + + const D3D9FormatInfoMap &infoMap = GetD3D9FormatInfoMap(); + for (D3D9FormatInfoMap::const_iterator i = infoMap.begin(); i != infoMap.end(); ++i) + { + set.insert(i->first); + } + + return set; +} + +struct D3D9FastCopyFormat +{ + D3DFORMAT mSourceFormat; + GLenum mDestFormat; + GLenum mDestType; + + D3D9FastCopyFormat(D3DFORMAT sourceFormat, GLenum destFormat, GLenum destType) + : mSourceFormat(sourceFormat), mDestFormat(destFormat), mDestType(destType) + { } + + bool operator<(const D3D9FastCopyFormat& other) const + { + return memcmp(this, &other, sizeof(D3D9FastCopyFormat)) < 0; + } +}; + +typedef std::map<D3D9FastCopyFormat, ColorCopyFunction> D3D9FastCopyMap; +typedef std::pair<D3D9FastCopyFormat, ColorCopyFunction> D3D9FastCopyPair; + +static D3D9FastCopyMap BuildFastCopyMap() +{ + D3D9FastCopyMap map; + + map.insert(D3D9FastCopyPair(D3D9FastCopyFormat(D3DFMT_A8R8G8B8, GL_RGBA, GL_UNSIGNED_BYTE), CopyBGRAUByteToRGBAUByte)); + + return map; +} + +typedef std::pair<GLint, InitializeTextureDataFunction> InternalFormatInitialzerPair; +typedef std::map<GLint, InitializeTextureDataFunction> InternalFormatInitialzerMap; + +static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap() +{ + InternalFormatInitialzerMap map; + + map.insert(InternalFormatInitialzerPair(GL_RGB16F, Initialize4ComponentData<GLhalf, 0x0000, 0x0000, 0x0000, gl::Float16One>)); + map.insert(InternalFormatInitialzerPair(GL_RGB32F, Initialize4ComponentData<GLfloat, 0x00000000, 0x00000000, 0x00000000, gl::Float32One>)); + + return map; +} + +static const InternalFormatInitialzerMap &GetInternalFormatInitialzerMap() +{ + static const InternalFormatInitialzerMap map = BuildInternalFormatInitialzerMap(); + return map; +} + +namespace d3d9 +{ + +MipGenerationFunction GetMipGenerationFunction(D3DFORMAT format) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + return d3dFormatInfo.mMipGenerationFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +LoadImageFunction GetImageLoadFunction(GLenum internalFormat) +{ + D3D9FormatInfo d3d9FormatInfo; + if (GetD3D9FormatInfo(internalFormat, &d3d9FormatInfo)) + { + return d3d9FormatInfo.mLoadFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +GLuint GetFormatPixelBytes(D3DFORMAT format) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + return d3dFormatInfo.mPixelBits / 8; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetBlockWidth(D3DFORMAT format) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + return d3dFormatInfo.mBlockWidth; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetBlockHeight(D3DFORMAT format) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + return d3dFormatInfo.mBlockHeight; + } + else + { + UNREACHABLE(); + return 0; + } +} + +GLuint GetBlockSize(D3DFORMAT format, GLuint width, GLuint height) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + GLuint numBlocksWide = (width + d3dFormatInfo.mBlockWidth - 1) / d3dFormatInfo.mBlockWidth; + GLuint numBlocksHight = (height + d3dFormatInfo.mBlockHeight - 1) / d3dFormatInfo.mBlockHeight; + + return (d3dFormatInfo.mPixelBits * numBlocksWide * numBlocksHight) / 8; + } + else + { + UNREACHABLE(); + return 0; + } +} + +void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + int upsampleCount = 0; + + GLsizei blockWidth = d3dFormatInfo.mBlockWidth; + GLsizei blockHeight = d3dFormatInfo.mBlockHeight; + + // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. + if (isImage || *requestWidth < blockWidth || *requestHeight < blockHeight) + { + while (*requestWidth % blockWidth != 0 || *requestHeight % blockHeight != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + *levelOffset = upsampleCount; + } +} + +const D3DFormatSet &GetAllUsedD3DFormats() +{ + static const D3DFormatSet formatSet = BuildAllD3DFormatSet(); + return formatSet; +} + +ColorReadFunction GetColorReadFunction(D3DFORMAT format) +{ + D3DFormatInfo d3dFormatInfo; + if (GetD3D9FormatInfo(format, &d3dFormatInfo)) + { + return d3dFormatInfo.mColorReadFunction; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +ColorCopyFunction GetFastCopyFunction(D3DFORMAT sourceFormat, GLenum destFormat, GLenum destType) +{ + static const D3D9FastCopyMap fastCopyMap = BuildFastCopyMap(); + D3D9FastCopyMap::const_iterator iter = fastCopyMap.find(D3D9FastCopyFormat(sourceFormat, destFormat, destType)); + return (iter != fastCopyMap.end()) ? iter->second : NULL; +} + +GLenum GetDeclTypeComponentType(D3DDECLTYPE declType) +{ + switch (declType) + { + case D3DDECLTYPE_FLOAT1: return GL_FLOAT; + case D3DDECLTYPE_FLOAT2: return GL_FLOAT; + case D3DDECLTYPE_FLOAT3: return GL_FLOAT; + case D3DDECLTYPE_FLOAT4: return GL_FLOAT; + case D3DDECLTYPE_UBYTE4: return GL_UNSIGNED_INT; + case D3DDECLTYPE_SHORT2: return GL_INT; + case D3DDECLTYPE_SHORT4: return GL_INT; + case D3DDECLTYPE_UBYTE4N: return GL_UNSIGNED_NORMALIZED; + case D3DDECLTYPE_SHORT4N: return GL_SIGNED_NORMALIZED; + case D3DDECLTYPE_USHORT4N: return GL_UNSIGNED_NORMALIZED; + case D3DDECLTYPE_SHORT2N: return GL_SIGNED_NORMALIZED; + case D3DDECLTYPE_USHORT2N: return GL_UNSIGNED_NORMALIZED; + default: UNREACHABLE(); return GL_NONE; + } +} + +// Attribute format conversion +enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 }; + +struct FormatConverter +{ + bool identity; + std::size_t outputElementSize; + void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out); + D3DDECLTYPE d3dDeclType; +}; + +struct TranslationDescription +{ + DWORD capsFlag; + FormatConverter preferredConversion; + FormatConverter fallbackConversion; +}; + +static unsigned int typeIndex(GLenum type); +static const FormatConverter &formatConverter(const gl::VertexAttribute &attribute); + +bool mTranslationsInitialized = false; +FormatConverter mFormatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; + +// Mapping from OpenGL-ES vertex attrib type to D3D decl type: +// +// BYTE SHORT (Cast) +// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm) +// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast) +// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize) +// SHORT SHORT (Identity) +// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize) +// UNSIGNED_SHORT FLOAT (Cast) +// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize) +// FIXED (not in WebGL) FLOAT (FixedToFloat) +// FLOAT FLOAT (Identity) + +// GLToCType maps from GL type (as GLenum) to the C typedef. +template <GLenum GLType> struct GLToCType { }; + +template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; }; +template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; }; +template <> struct GLToCType<GL_SHORT> { typedef GLshort type; }; +template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; }; +template <> struct GLToCType<GL_FIXED> { typedef GLuint type; }; +template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; }; + +// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.) +enum D3DVertexType +{ + D3DVT_FLOAT, + D3DVT_SHORT, + D3DVT_SHORT_NORM, + D3DVT_UBYTE, + D3DVT_UBYTE_NORM, + D3DVT_USHORT_NORM +}; + +// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type. +template <unsigned int D3DType> struct D3DToCType { }; + +template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; }; +template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; }; +template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; }; +template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; }; +template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; }; +template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; }; + +// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size. +template <unsigned int type, int size> struct WidenRule { }; + +template <int size> struct WidenRule<D3DVT_FLOAT, size> : NoWiden<size> { }; +template <int size> struct WidenRule<D3DVT_SHORT, size> : WidenToEven<size> { }; +template <int size> struct WidenRule<D3DVT_SHORT_NORM, size> : WidenToEven<size> { }; +template <int size> struct WidenRule<D3DVT_UBYTE, size> : WidenToFour<size> { }; +template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size> : WidenToFour<size> { }; +template <int size> struct WidenRule<D3DVT_USHORT_NORM, size> : WidenToEven<size> { }; + +// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination. +template <unsigned int d3dtype, int size> struct VertexTypeFlags { }; + +template <unsigned int _capflag, unsigned int _declflag> +struct VertexTypeFlagsHelper +{ + enum { capflag = _capflag }; + enum { declflag = _declflag }; +}; + +template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { }; +template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { }; +template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { }; +template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { }; +template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { }; +template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { }; +template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { }; +template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { }; +template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { }; + + +// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums). +template <GLenum GLtype, bool normalized> struct VertexTypeMapping { }; + +template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred> +struct VertexTypeMappingBase +{ + enum { preferred = Preferred }; + enum { fallback = Fallback }; +}; + +template <> struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Cast +template <> struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Normalize +template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { }; // Identity, Cast +template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { }; // Identity, Normalize +template <> struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Identity +template <> struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize +template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Cast +template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize +template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // FixedToFloat +template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Identity + + +// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat). +// The conversion rules themselves are defined in vertexconversion.h. + +// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping). +template <GLenum fromType, bool normalized, unsigned int toType> +struct ConversionRule : Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type> { }; + +// All conversions from normalized types to float use the Normalize operator. +template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : Normalize<typename GLToCType<fromType>::type> { }; + +// Use a full specialization for this so that it preferentially matches ahead of the generic normalize-to-float rules. +template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { }; +template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { }; + +// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1) +// whether it is normalized or not. +template <class T, bool normalized> struct DefaultVertexValuesStage2 { }; + +template <class T> struct DefaultVertexValuesStage2<T, true> : NormalizedDefaultValues<T> { }; +template <class T> struct DefaultVertexValuesStage2<T, false> : SimpleDefaultValues<T> { }; + +// Work out the default value rule for a D3D type (expressed as the C type) and +template <class T, bool normalized> struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized> { }; +template <bool normalized> struct DefaultVertexValues<float, normalized> : SimpleDefaultValues<float> { }; + +// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion. +// The fallback conversion produces an output that all D3D9 devices must support. +template <class T> struct UsePreferred { enum { type = T::preferred }; }; +template <class T> struct UseFallback { enum { type = T::fallback }; }; + +// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion, +// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag +// and the D3DDECLTYPE member needed for the vertex declaration in declflag. +template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule> +struct Converter + : VertexDataConverter<typename GLToCType<fromType>::type, + WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>, + ConversionRule<fromType, + normalized, + PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>, + DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > > +{ +private: + enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type }; + enum { d3dsize = WidenRule<d3dtype, size>::finalWidth }; + +public: + enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag }; + enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag }; +}; + +// Initialize a TranslationInfo +#define TRANSLATION(type, norm, size, preferred) \ + { \ + Converter<type, norm, size, preferred>::identity, \ + Converter<type, norm, size, preferred>::finalSize, \ + Converter<type, norm, size, preferred>::convertArray, \ + static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag) \ + } + +#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \ + { \ + Converter<type, norm, size, UsePreferred>::capflag, \ + TRANSLATION(type, norm, size, UsePreferred), \ + TRANSLATION(type, norm, size, UseFallback) \ + } + +#define TRANSLATIONS_FOR_TYPE(type) \ + { \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \ + } + +#define TRANSLATIONS_FOR_TYPE_NO_NORM(type) \ + { \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + } + +const TranslationDescription mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1] +{ + TRANSLATIONS_FOR_TYPE(GL_BYTE), + TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE), + TRANSLATIONS_FOR_TYPE(GL_SHORT), + TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT), + TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED), + TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT) +}; + +void InitializeVertexTranslations(const rx::Renderer9 *renderer) +{ + DWORD declTypes = renderer->getCapsDeclTypes(); + + for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++) + { + for (unsigned int j = 0; j < 2; j++) + { + for (unsigned int k = 0; k < 4; k++) + { + if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0) + { + mFormatConverters[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion; + } + else + { + mFormatConverters[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion; + } + } + } + } +} + +unsigned int typeIndex(GLenum type) +{ + switch (type) + { + case GL_BYTE: return 0; + case GL_UNSIGNED_BYTE: return 1; + case GL_SHORT: return 2; + case GL_UNSIGNED_SHORT: return 3; + case GL_FIXED: return 4; + case GL_FLOAT: return 5; + + default: UNREACHABLE(); return 5; + } +} + +const FormatConverter &formatConverter(const gl::VertexFormat &vertexFormat) +{ + // Pure integer attributes only supported in ES3.0 + ASSERT(!vertexFormat.mPureInteger); + return mFormatConverters[typeIndex(vertexFormat.mType)][vertexFormat.mNormalized][vertexFormat.mComponents - 1]; +} + +VertexCopyFunction GetVertexCopyFunction(const gl::VertexFormat &vertexFormat) +{ + return formatConverter(vertexFormat).convertArray; +} + +size_t GetVertexElementSize(const gl::VertexFormat &vertexFormat) +{ + return formatConverter(vertexFormat).outputElementSize; +} + +VertexConversionType GetVertexConversionType(const gl::VertexFormat &vertexFormat) +{ + return (formatConverter(vertexFormat).identity ? VERTEX_CONVERT_NONE : VERTEX_CONVERT_CPU); +} + +D3DDECLTYPE GetNativeVertexFormat(const gl::VertexFormat &vertexFormat) +{ + return formatConverter(vertexFormat).d3dDeclType; +} + +} + +namespace gl_d3d9 +{ + +D3DFORMAT GetTextureFormat(GLenum internalFormat) +{ + D3D9FormatInfo d3d9FormatInfo; + if (GetD3D9FormatInfo(internalFormat, &d3d9FormatInfo)) + { + return d3d9FormatInfo.mTexFormat; + } + else + { + return D3DFMT_UNKNOWN; + } +} + +D3DFORMAT GetRenderFormat(GLenum internalFormat) +{ + D3D9FormatInfo d3d9FormatInfo; + if (GetD3D9FormatInfo(internalFormat, &d3d9FormatInfo)) + { + return d3d9FormatInfo.mRenderFormat; + } + else + { + return D3DFMT_UNKNOWN; + } +} + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLsizei samples) +{ + return (samples > 1) ? static_cast<D3DMULTISAMPLE_TYPE>(samples) : D3DMULTISAMPLE_NONE; +} + +bool RequiresTextureDataInitialization(GLint internalFormat) +{ + const InternalFormatInitialzerMap &map = GetInternalFormatInitialzerMap(); + return map.find(internalFormat) != map.end(); +} + +InitializeTextureDataFunction GetTextureDataInitializationFunction(GLint internalFormat) +{ + const InternalFormatInitialzerMap &map = GetInternalFormatInitialzerMap(); + InternalFormatInitialzerMap::const_iterator iter = map.find(internalFormat); + if (iter != map.end()) + { + return iter->second; + } + else + { + UNREACHABLE(); + return NULL; + } +} + +} + +namespace d3d9_gl +{ + +GLenum GetInternalFormat(D3DFORMAT format) +{ + static const D3D9FormatInfoMap infoMap = BuildD3D9FormatInfoMap(); + D3D9FormatInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + return iter->second.mInternalFormat; + } + else + { + UNREACHABLE(); + return GL_NONE; + } +} + +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type) +{ + return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0; +} + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) +{ + GLenum internalFormat = d3d9_gl::GetInternalFormat(d3dformat); + GLenum convertedFormat = gl::GetFormat(internalFormat); + return convertedFormat == format; +} + +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h new file mode 100644 index 0000000000..26388794e0 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h @@ -0,0 +1,77 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// formatutils9.h: Queries for GL image formats and their translations to D3D9 +// formats. + +#ifndef LIBGLESV2_RENDERER_FORMATUTILS9_H_ +#define LIBGLESV2_RENDERER_FORMATUTILS9_H_ + +#include "libGLESv2/formatutils.h" + +namespace rx +{ + +class Renderer9; + +namespace d3d9 +{ + +typedef std::set<D3DFORMAT> D3DFormatSet; + +MipGenerationFunction GetMipGenerationFunction(D3DFORMAT format); +LoadImageFunction GetImageLoadFunction(GLenum internalFormat); + +GLuint GetFormatPixelBytes(D3DFORMAT format); +GLuint GetBlockWidth(D3DFORMAT format); +GLuint GetBlockHeight(D3DFORMAT format); +GLuint GetBlockSize(D3DFORMAT format, GLuint width, GLuint height); + +void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); + +const D3DFormatSet &GetAllUsedD3DFormats(); + +ColorReadFunction GetColorReadFunction(D3DFORMAT format); +ColorCopyFunction GetFastCopyFunction(D3DFORMAT sourceFormat, GLenum destFormat, GLenum destType); + +VertexCopyFunction GetVertexCopyFunction(const gl::VertexFormat &vertexFormat); +size_t GetVertexElementSize(const gl::VertexFormat &vertexFormat); +VertexConversionType GetVertexConversionType(const gl::VertexFormat &vertexFormat); +D3DDECLTYPE GetNativeVertexFormat(const gl::VertexFormat &vertexFormat); + +GLenum GetDeclTypeComponentType(D3DDECLTYPE declType); +int GetDeclTypeComponentCount(D3DDECLTYPE declType); +bool IsDeclTypeNormalized(D3DDECLTYPE declType); + +void InitializeVertexTranslations(const rx::Renderer9 *renderer); + +} + +namespace gl_d3d9 +{ + +D3DFORMAT GetTextureFormat(GLenum internalForma); +D3DFORMAT GetRenderFormat(GLenum internalFormat); + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLsizei samples); + +bool RequiresTextureDataInitialization(GLint internalFormat); +InitializeTextureDataFunction GetTextureDataInitializationFunction(GLint internalFormat); + +} + +namespace d3d9_gl +{ + +GLenum GetInternalFormat(D3DFORMAT format); +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type); +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format); + +} + +} + +#endif // LIBGLESV2_RENDERER_FORMATUTILS9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp new file mode 100644 index 0000000000..68e5378fbb --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp @@ -0,0 +1,409 @@ +#include "precompiled.h" +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// renderer9_utils.cpp: Conversion functions and other utility routines +// specific to the D3D9 renderer. + +#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/formatutils.h" +#include "common/mathutil.h" +#include "libGLESv2/Context.h" + +#include "common/debug.h" + +#include "third_party/systeminfo/SystemInfo.h" + +namespace rx +{ + +namespace gl_d3d9 +{ + +D3DCMPFUNC ConvertComparison(GLenum comparison) +{ + D3DCMPFUNC d3dComp = D3DCMP_ALWAYS; + switch (comparison) + { + case GL_NEVER: d3dComp = D3DCMP_NEVER; break; + case GL_ALWAYS: d3dComp = D3DCMP_ALWAYS; break; + case GL_LESS: d3dComp = D3DCMP_LESS; break; + case GL_LEQUAL: d3dComp = D3DCMP_LESSEQUAL; break; + case GL_EQUAL: d3dComp = D3DCMP_EQUAL; break; + case GL_GREATER: d3dComp = D3DCMP_GREATER; break; + case GL_GEQUAL: d3dComp = D3DCMP_GREATEREQUAL; break; + case GL_NOTEQUAL: d3dComp = D3DCMP_NOTEQUAL; break; + default: UNREACHABLE(); + } + + return d3dComp; +} + +D3DCOLOR ConvertColor(gl::ColorF color) +{ + return D3DCOLOR_RGBA(gl::unorm<8>(color.red), + gl::unorm<8>(color.green), + gl::unorm<8>(color.blue), + gl::unorm<8>(color.alpha)); +} + +D3DBLEND ConvertBlendFunc(GLenum blend) +{ + D3DBLEND d3dBlend = D3DBLEND_ZERO; + + switch (blend) + { + case GL_ZERO: d3dBlend = D3DBLEND_ZERO; break; + case GL_ONE: d3dBlend = D3DBLEND_ONE; break; + case GL_SRC_COLOR: d3dBlend = D3DBLEND_SRCCOLOR; break; + case GL_ONE_MINUS_SRC_COLOR: d3dBlend = D3DBLEND_INVSRCCOLOR; break; + case GL_DST_COLOR: d3dBlend = D3DBLEND_DESTCOLOR; break; + case GL_ONE_MINUS_DST_COLOR: d3dBlend = D3DBLEND_INVDESTCOLOR; break; + case GL_SRC_ALPHA: d3dBlend = D3DBLEND_SRCALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3DBLEND_INVSRCALPHA; break; + case GL_DST_ALPHA: d3dBlend = D3DBLEND_DESTALPHA; break; + case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3DBLEND_INVDESTALPHA; break; + case GL_CONSTANT_COLOR: d3dBlend = D3DBLEND_BLENDFACTOR; break; + case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; + case GL_CONSTANT_ALPHA: d3dBlend = D3DBLEND_BLENDFACTOR; break; + case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; + case GL_SRC_ALPHA_SATURATE: d3dBlend = D3DBLEND_SRCALPHASAT; break; + default: UNREACHABLE(); + } + + return d3dBlend; +} + +D3DBLENDOP ConvertBlendOp(GLenum blendOp) +{ + D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD; + + switch (blendOp) + { + case GL_FUNC_ADD: d3dBlendOp = D3DBLENDOP_ADD; break; + case GL_FUNC_SUBTRACT: d3dBlendOp = D3DBLENDOP_SUBTRACT; break; + case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3DBLENDOP_REVSUBTRACT; break; + case GL_MIN_EXT: d3dBlendOp = D3DBLENDOP_MIN; break; + case GL_MAX_EXT: d3dBlendOp = D3DBLENDOP_MAX; break; + default: UNREACHABLE(); + } + + return d3dBlendOp; +} + +D3DSTENCILOP ConvertStencilOp(GLenum stencilOp) +{ + D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP; + + switch (stencilOp) + { + case GL_ZERO: d3dStencilOp = D3DSTENCILOP_ZERO; break; + case GL_KEEP: d3dStencilOp = D3DSTENCILOP_KEEP; break; + case GL_REPLACE: d3dStencilOp = D3DSTENCILOP_REPLACE; break; + case GL_INCR: d3dStencilOp = D3DSTENCILOP_INCRSAT; break; + case GL_DECR: d3dStencilOp = D3DSTENCILOP_DECRSAT; break; + case GL_INVERT: d3dStencilOp = D3DSTENCILOP_INVERT; break; + case GL_INCR_WRAP: d3dStencilOp = D3DSTENCILOP_INCR; break; + case GL_DECR_WRAP: d3dStencilOp = D3DSTENCILOP_DECR; break; + default: UNREACHABLE(); + } + + return d3dStencilOp; +} + +D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap) +{ + D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP; + + switch (wrap) + { + case GL_REPEAT: d3dWrap = D3DTADDRESS_WRAP; break; + case GL_CLAMP_TO_EDGE: d3dWrap = D3DTADDRESS_CLAMP; break; + case GL_MIRRORED_REPEAT: d3dWrap = D3DTADDRESS_MIRROR; break; + default: UNREACHABLE(); + } + + return d3dWrap; +} + +D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace) +{ + D3DCULL cull = D3DCULL_CCW; + switch (cullFace) + { + case GL_FRONT: + cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); + break; + case GL_BACK: + cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); + break; + case GL_FRONT_AND_BACK: + cull = D3DCULL_NONE; // culling will be handled during draw + break; + default: UNREACHABLE(); + } + + return cull; +} + +D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace) +{ + D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X; + + switch (cubeFace) + { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + face = D3DCUBEMAP_FACE_POSITIVE_X; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + face = D3DCUBEMAP_FACE_NEGATIVE_X; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + face = D3DCUBEMAP_FACE_POSITIVE_Y; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + face = D3DCUBEMAP_FACE_NEGATIVE_Y; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + face = D3DCUBEMAP_FACE_POSITIVE_Z; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = D3DCUBEMAP_FACE_NEGATIVE_Z; + break; + default: UNREACHABLE(); + } + + return face; +} + +DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha) +{ + return (red ? D3DCOLORWRITEENABLE_RED : 0) | + (green ? D3DCOLORWRITEENABLE_GREEN : 0) | + (blue ? D3DCOLORWRITEENABLE_BLUE : 0) | + (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0); +} + +D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy) +{ + if (maxAnisotropy > 1.0f) + { + return D3DTEXF_ANISOTROPIC; + } + + D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT; + switch (magFilter) + { + case GL_NEAREST: d3dMagFilter = D3DTEXF_POINT; break; + case GL_LINEAR: d3dMagFilter = D3DTEXF_LINEAR; break; + default: UNREACHABLE(); + } + + return d3dMagFilter; +} + +void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy) +{ + switch (minFilter) + { + case GL_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_NEAREST_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_LINEAR_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_NEAREST_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + default: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + UNREACHABLE(); + } + + if (maxAnisotropy > 1.0f) + { + *d3dMinFilter = D3DTEXF_ANISOTROPIC; + } +} + +} + +namespace d3d9_gl +{ + +static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3D9 *d3d9, D3DDEVTYPE deviceType, + UINT adapter, D3DFORMAT adapterFormat) +{ + gl::TextureCaps textureCaps; + + D3DFORMAT renderFormat = gl_d3d9::GetRenderFormat(internalFormat); + if (gl::GetDepthBits(internalFormat) > 0 || gl::GetStencilBits(internalFormat) > 0) + { + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, renderFormat)); + textureCaps.filterable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, renderFormat)); + textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, renderFormat)) || + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, renderFormat)); + } + else + { + D3DFORMAT textureFormat = gl_d3d9::GetTextureFormat(internalFormat); + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, textureFormat)) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_CUBETEXTURE, textureFormat)); + textureCaps.filterable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, textureFormat)); + textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, textureFormat)) || + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, textureFormat)); + } + + textureCaps.sampleCounts.insert(1); + for (size_t i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++) + { + D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i); + + HRESULT result = d3d9->CheckDeviceMultiSampleType(adapter, deviceType, renderFormat, TRUE, multisampleType, NULL); + if (SUCCEEDED(result)) + { + textureCaps.sampleCounts.insert(i); + } + } + + return textureCaps; +} + +void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) +{ + D3DCAPS9 deviceCaps; + if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps))) + { + // Can't continue with out device caps + return; + } + + D3DDISPLAYMODE currentDisplayMode; + d3d9->GetAdapterDisplayMode(adapter, ¤tDisplayMode); + + const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); + for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) + { + gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, d3d9, deviceType, adapter, + currentDisplayMode.Format); + textureCapsMap->insert(*internalFormat, textureCaps); + } + + // GL core feature limits + caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max()); + + // 3D textures are unimplemented in D3D9 + caps->max3DTextureSize = 1; + + // Only one limit in GL, use the minimum dimension + caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight); + + // D3D treats cube maps as a special case of 2D textures + caps->maxCubeMapTextureSize = caps->max2DTextureSize; + + // Array textures are not available in D3D9 + caps->maxArrayTextureLayers = 1; + + // ES3-only feature + caps->maxLODBias = 0.0f; + + // No specific limits on render target size, maximum 2D texture size is equivalent + caps->maxRenderbufferSize = caps->max2DTextureSize; + + // Draw buffers are not supported in D3D9 + caps->maxDrawBuffers = 1; + caps->maxColorAttachments = 1; + + // No specific limits on viewport size, maximum 2D texture size is equivalent + caps->maxViewportWidth = caps->max2DTextureSize; + caps->maxViewportHeight = caps->maxViewportWidth; + + // Point size is clamped to 1.0f when the shader model is less than 3 + caps->minAliasedPointSize = 1.0f; + caps->maxAliasedPointSize = ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize : 1.0f); + + // Wide lines not supported + caps->minAliasedLineWidth = 1.0f; + caps->maxAliasedLineWidth = 1.0f; + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUint = deviceCaps.MaxVertexIndex >= (1 << 16); + extensions->packedDepthStencil = true; + extensions->getProgramBinary = true; + extensions->rgb8rgba8 = true; + extensions->readFormatBGRA = true; + extensions->pixelBufferObject = false; + extensions->mapBuffer = false; + extensions->mapBufferRange = false; + + // ATI cards on XP have problems with non-power-of-two textures. + D3DADAPTER_IDENTIFIER9 adapterId = { 0 }; + if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId))) + { + extensions->textureNPOT = !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && + !(isWindowsVistaOrGreater() && adapterId.VendorId == VENDOR_ID_AMD); + } + else + { + extensions->textureNPOT = false; + } + + extensions->drawBuffers = false; + extensions->textureStorage = true; + + // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec + extensions->textureFilterAnisotropic = (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2; + extensions->maxTextureAnisotropy = static_cast<GLfloat>(deviceCaps.MaxAnisotropy); + + // Check occlusion query support by trying to create one + IDirect3DQuery9 *occlusionQuery = NULL; + extensions->occlusionQueryBoolean = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery; + SafeRelease(occlusionQuery); + + // Check event query support by trying to create one + IDirect3DQuery9 *eventQuery = NULL; + extensions->fence = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery; + SafeRelease(eventQuery); + + extensions->timerQuery = false; // Unimplemented + extensions->robustness = true; + extensions->blendMinMax = true; + extensions->framebufferBlit = true; + extensions->framebufferMultisample = true; + extensions->instancedArrays = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); + extensions->packReverseRowOrder = true; + extensions->standardDerivatives = (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0; + extensions->shaderTextureLOD = true; + extensions->fragDepth = true; + extensions->textureUsage = true; + extensions->translatedShaderSource = true; + extensions->colorBufferFloat = false; +} + +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/renderer9_utils.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h index bf6cdf1ea6..7f3c65d3e0 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/renderer9_utils.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,16 +10,17 @@ #ifndef LIBGLESV2_RENDERER_RENDERER9_UTILS_H #define LIBGLESV2_RENDERER_RENDERER9_UTILS_H -#include "libGLESv2/utilities.h" +#include "libGLESv2/angletypes.h" +#include "libGLESv2/Caps.h" -const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z'))); -const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N','U','L','L'))); +namespace rx +{ namespace gl_d3d9 { D3DCMPFUNC ConvertComparison(GLenum comparison); -D3DCOLOR ConvertColor(gl::Color color); +D3DCOLOR ConvertColor(gl::ColorF color); D3DBLEND ConvertBlendFunc(GLenum blend); D3DBLENDOP ConvertBlendOp(GLenum blendOp); D3DSTENCILOP ConvertStencilOp(GLenum stencilOp); @@ -29,31 +30,19 @@ D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace); DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha); D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy); void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy); -D3DFORMAT ConvertRenderbufferFormat(GLenum format); -D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples); } namespace d3d9_gl { -GLuint GetAlphaSize(D3DFORMAT colorFormat); -GLuint GetStencilSize(D3DFORMAT stencilFormat); - -GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type); - -bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format); -GLenum ConvertBackBufferFormat(D3DFORMAT format); -GLenum ConvertDepthStencilFormat(D3DFORMAT format); -GLenum ConvertRenderTargetFormat(D3DFORMAT format); -GLenum GetEquivalentFormat(D3DFORMAT format); +void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions); } namespace d3d9 { -bool IsCompressedFormat(D3DFORMAT format); -size_t ComputeRowSize(D3DFORMAT format, unsigned int width); inline bool isDeviceLostError(HRESULT errorCode) { @@ -71,4 +60,6 @@ inline bool isDeviceLostError(HRESULT errorCode) } +} + #endif // LIBGLESV2_RENDERER_RENDERER9_UTILS_H diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps new file mode 100644 index 0000000000..eb43eb3e7a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps @@ -0,0 +1,33 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +sampler2D tex : s0; + +uniform float4 mult : c0; +uniform float4 add : c1; + +// Passthrough Pixel Shader +// Outputs texture 0 sampled at texcoord 0. +float4 PS_passthrough(float4 texcoord : TEXCOORD0) : COLOR +{ + return tex2D(tex, texcoord.xy); +}; + +// Luminance Conversion Pixel Shader +// Performs a mad operation using the LA data from the texture with mult.xw and add.xw. +// Returns data in the form of llla +float4 PS_luminance(float4 texcoord : TEXCOORD0) : COLOR +{ + return (tex2D(tex, texcoord.xy).xw * mult.xw + add.xw).xxxy; +}; + +// RGB/A Component Mask Pixel Shader +// Performs a mad operation using the texture's RGBA data with mult.xyzw and add.xyzw. +// Returns data in the form of rgba +float4 PS_componentmask(float4 texcoord : TEXCOORD0) : COLOR +{ + return tex2D(tex, texcoord.xy) * mult + add; +}; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/shaders/Blit.vs b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs index 3a36980b93..3bd611ba5d 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/shaders/Blit.vs +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs @@ -17,7 +17,7 @@ uniform float4 halfPixelSize : c0; // Outputs the homogenous position as-is. // Outputs a tex coord with (0,0) in the upper-left corner of the screen and (1,1) in the bottom right. // C0.X must be negative half-pixel width, C0.Y must be half-pixel height. C0.ZW must be 0. -VS_OUTPUT standardvs(in float4 position : POSITION) +VS_OUTPUT VS_standard(in float4 position : POSITION) { VS_OUTPUT Out; @@ -32,7 +32,7 @@ VS_OUTPUT standardvs(in float4 position : POSITION) // Outputs the homogenous position as-is. // Outputs a tex coord with (0,1) in the upper-left corner of the screen and (1,0) in the bottom right. // C0.XY must be the half-pixel width and height. C0.ZW must be 0. -VS_OUTPUT flipyvs(in float4 position : POSITION) +VS_OUTPUT VS_flipy(in float4 position : POSITION) { VS_OUTPUT Out; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp deleted file mode 100644 index 31d5b8b886..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp +++ /dev/null @@ -1,366 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// BufferStorage11.cpp Defines the BufferStorage11 class. - -#include "libGLESv2/renderer/d3d11/BufferStorage11.h" -#include "libGLESv2/main.h" -#include "libGLESv2/renderer/d3d11/Renderer11.h" - -namespace rx -{ - -BufferStorage11::BufferStorage11(Renderer11 *renderer) -{ - mRenderer = renderer; - - mStagingBuffer = NULL; - mStagingBufferSize = 0; - - mSize = 0; - - mResolvedData = NULL; - mResolvedDataSize = 0; - mResolvedDataValid = false; - - mReadUsageCount = 0; - mWriteUsageCount = 0; -} - -BufferStorage11::~BufferStorage11() -{ - SafeRelease(mStagingBuffer); - - if (mResolvedData) - { - free(mResolvedData); - mResolvedData = NULL; - } - - for (auto it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++) - { - SafeDelete(it->second); - } -} - -BufferStorage11 *BufferStorage11::makeBufferStorage11(BufferStorage *bufferStorage) -{ - ASSERT(HAS_DYNAMIC_TYPE(BufferStorage11*, bufferStorage)); - return static_cast<BufferStorage11*>(bufferStorage); -} - -void *BufferStorage11::getData() -{ - ASSERT(mStagingBuffer); - - if (!mResolvedDataValid) - { - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - HRESULT result; - - if (!mResolvedData || mResolvedDataSize < mStagingBufferSize) - { - free(mResolvedData); - mResolvedData = malloc(mSize); - mResolvedDataSize = mSize; - } - - D3D11_MAPPED_SUBRESOURCE mappedResource; - result = context->Map(mStagingBuffer, 0, D3D11_MAP_READ, 0, &mappedResource); - if (FAILED(result)) - { - return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); - } - - memcpy(mResolvedData, mappedResource.pData, mSize); - - context->Unmap(mStagingBuffer, 0); - - mResolvedDataValid = true; - } - - mReadUsageCount = 0; - - return mResolvedData; -} - -void BufferStorage11::setData(const void* data, unsigned int size, unsigned int offset) -{ - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - HRESULT result; - - const unsigned int requiredStagingBufferSize = size + offset; - const bool createStagingBuffer = !mStagingBuffer || mStagingBufferSize < requiredStagingBufferSize; - - if (createStagingBuffer) - { - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = requiredStagingBufferSize; - bufferDesc.Usage = D3D11_USAGE_STAGING; - bufferDesc.BindFlags = 0; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - bufferDesc.MiscFlags = 0; - bufferDesc.StructureByteStride = 0; - - HRESULT result; - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - ID3D11Buffer *newStagingBuffer; - - if (data && offset == 0) - { - D3D11_SUBRESOURCE_DATA initialData; - initialData.pSysMem = data; - initialData.SysMemPitch = requiredStagingBufferSize; - initialData.SysMemSlicePitch = 0; - - result = device->CreateBuffer(&bufferDesc, &initialData, &newStagingBuffer); - } - else - { - result = device->CreateBuffer(&bufferDesc, NULL, &newStagingBuffer); - } - - if (FAILED(result)) - { - mStagingBufferSize = 0; - return gl::error(GL_OUT_OF_MEMORY); - } - - mStagingBufferSize = requiredStagingBufferSize; - - if (mStagingBuffer && offset > 0) - { - // If offset is greater than zero and the buffer is non-null, need to preserve the data from - // the old buffer up to offset - D3D11_BOX srcBox; - srcBox.left = 0; - srcBox.right = std::min(offset, requiredStagingBufferSize); - srcBox.top = 0; - srcBox.bottom = 1; - srcBox.front = 0; - srcBox.back = 1; - - context->CopySubresourceRegion(newStagingBuffer, 0, 0, 0, 0, mStagingBuffer, 0, &srcBox); - } - - SafeRelease(mStagingBuffer); - mStagingBuffer = newStagingBuffer; - } - - if (data && (offset != 0 || !createStagingBuffer)) - { - D3D11_MAPPED_SUBRESOURCE mappedResource; - result = context->Map(mStagingBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource); - if (FAILED(result)) - { - return gl::error(GL_OUT_OF_MEMORY); - } - - unsigned char *offsetBufferPointer = reinterpret_cast<unsigned char *>(mappedResource.pData) + offset; - memcpy(offsetBufferPointer, data, size); - - context->Unmap(mStagingBuffer, 0); - } - - for (auto it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++) - { - it->second->markDirty(); - } - - mSize = std::max(mSize, requiredStagingBufferSize); - mWriteUsageCount = 0; - - mResolvedDataValid = false; -} - -void BufferStorage11::copyData(BufferStorage* sourceStorage, unsigned int size, - unsigned int sourceOffset, unsigned int destOffset) -{ - BufferStorage11* source = makeBufferStorage11(sourceStorage); - if (source) - { - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - - D3D11_BOX srcBox; - srcBox.left = sourceOffset; - srcBox.right = sourceOffset + size; - srcBox.top = 0; - srcBox.bottom = 1; - srcBox.front = 0; - srcBox.back = 1; - - ASSERT(mStagingBuffer && source->mStagingBuffer); - context->CopySubresourceRegion(mStagingBuffer, 0, destOffset, 0, 0, source->mStagingBuffer, 0, &srcBox); - } -} - -void BufferStorage11::clear() -{ - mResolvedDataValid = false; - mSize = 0; -} - -unsigned int BufferStorage11::getSize() const -{ - return mSize; -} - -bool BufferStorage11::supportsDirectBinding() const -{ - return true; -} - -void BufferStorage11::markBufferUsage() -{ - mReadUsageCount++; - mWriteUsageCount++; - - const unsigned int usageLimit = 5; - - if (mReadUsageCount > usageLimit && mResolvedData) - { - free(mResolvedData); - mResolvedData = NULL; - mResolvedDataSize = 0; - mResolvedDataValid = false; - } -} - -ID3D11Buffer *BufferStorage11::getBuffer(BufferUsage usage) -{ - markBufferUsage(); - - DirectBufferStorage11 *directBuffer = NULL; - - auto directBufferIt = mDirectBuffers.find(usage); - if (directBufferIt != mDirectBuffers.end()) - { - directBuffer = directBufferIt->second; - } - - if (directBuffer) - { - if (directBuffer->isDirty()) - { - // if updateFromStagingBuffer returns true, the D3D buffer has been recreated - // and we should update our serial - if (directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0)) - { - updateSerial(); - } - } - } - else - { - // buffer is not allocated, create it - directBuffer = new DirectBufferStorage11(mRenderer, usage); - directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0); - - mDirectBuffers.insert(std::make_pair(usage, directBuffer)); - updateSerial(); - } - - return directBuffer->getD3DBuffer(); -} - -DirectBufferStorage11::DirectBufferStorage11(Renderer11 *renderer, BufferUsage usage) - : mRenderer(renderer), - mUsage(usage), - mDirectBuffer(NULL), - mBufferSize(0), - mDirty(false) -{ -} - -DirectBufferStorage11::~DirectBufferStorage11() -{ - SafeRelease(mDirectBuffer); -} - -BufferUsage DirectBufferStorage11::getUsage() const -{ - return mUsage; -} - -// Returns true if it recreates the direct buffer -bool DirectBufferStorage11::updateFromStagingBuffer(ID3D11Buffer *stagingBuffer, size_t size, size_t offset) -{ - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - - // unused for now - ASSERT(offset == 0); - - unsigned int requiredBufferSize = size + offset; - bool createBuffer = !mDirectBuffer || mBufferSize < requiredBufferSize; - - // (Re)initialize D3D buffer if needed - if (createBuffer) - { - D3D11_BUFFER_DESC bufferDesc; - fillBufferDesc(&bufferDesc, mRenderer, mUsage, requiredBufferSize); - - ID3D11Buffer *newBuffer; - HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer); - - if (FAILED(result)) - { - return gl::error(GL_OUT_OF_MEMORY, false); - } - - // No longer need the old buffer - SafeRelease(mDirectBuffer); - mDirectBuffer = newBuffer; - - mBufferSize = bufferDesc.ByteWidth; - } - - // Copy data via staging buffer - D3D11_BOX srcBox; - srcBox.left = 0; - srcBox.right = size; - srcBox.top = 0; - srcBox.bottom = 1; - srcBox.front = 0; - srcBox.back = 1; - - context->CopySubresourceRegion(mDirectBuffer, 0, offset, 0, 0, stagingBuffer, 0, &srcBox); - - mDirty = false; - - return createBuffer; -} - -void DirectBufferStorage11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, BufferUsage usage, unsigned int bufferSize) -{ - bufferDesc->ByteWidth = bufferSize; - bufferDesc->MiscFlags = 0; - bufferDesc->StructureByteStride = 0; - - switch (usage) - { - case BUFFER_USAGE_VERTEX: - bufferDesc->Usage = D3D11_USAGE_DEFAULT; - bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER; - bufferDesc->CPUAccessFlags = 0; - break; - - case BUFFER_USAGE_INDEX: - bufferDesc->Usage = D3D11_USAGE_DEFAULT; - bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER; - bufferDesc->CPUAccessFlags = 0; - break; - - default: - UNREACHABLE(); - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/BufferStorage11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/BufferStorage11.h deleted file mode 100644 index a6afafe1b4..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/BufferStorage11.h +++ /dev/null @@ -1,92 +0,0 @@ -// -// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// BufferStorage11.h Defines the BufferStorage11 class. - -#ifndef LIBGLESV2_RENDERER_BUFFERSTORAGE11_H_ -#define LIBGLESV2_RENDERER_BUFFERSTORAGE11_H_ - -#include "libGLESv2/renderer/BufferStorage.h" - -namespace rx -{ -class Renderer; -class Renderer11; -class DirectBufferStorage11; - -enum BufferUsage -{ - BUFFER_USAGE_VERTEX, - BUFFER_USAGE_INDEX, -}; - -class BufferStorage11 : public BufferStorage -{ - public: - explicit BufferStorage11(Renderer11 *renderer); - virtual ~BufferStorage11(); - - static BufferStorage11 *makeBufferStorage11(BufferStorage *bufferStorage); - - virtual void *getData(); - virtual void setData(const void* data, unsigned int size, unsigned int offset); - virtual void copyData(BufferStorage* sourceStorage, unsigned int size, - unsigned int sourceOffset, unsigned int destOffset); - virtual void clear(); - virtual unsigned int getSize() const; - virtual bool supportsDirectBinding() const; - - ID3D11Buffer *getBuffer(BufferUsage usage); - - private: - Renderer11 *mRenderer; - - ID3D11Buffer *mStagingBuffer; - unsigned int mStagingBufferSize; - - std::map<BufferUsage, DirectBufferStorage11*> mDirectBuffers; - - unsigned int mSize; - - void *mResolvedData; - unsigned int mResolvedDataSize; - bool mResolvedDataValid; - - unsigned int mReadUsageCount; - unsigned int mWriteUsageCount; - - void markBufferUsage(); -}; - -// Each instance of BufferStorageD3DBuffer11 is specialized for a class of D3D binding points -// - vertex buffers -// - index buffers -class DirectBufferStorage11 -{ - public: - DirectBufferStorage11(Renderer11 *renderer, BufferUsage usage); - ~DirectBufferStorage11(); - - BufferUsage getUsage() const; - bool updateFromStagingBuffer(ID3D11Buffer *stagingBuffer, size_t size, size_t offset); - - ID3D11Buffer *getD3DBuffer() { return mDirectBuffer; } - bool isDirty() const { return mDirty; } - void markDirty() { mDirty = true; } - - private: - Renderer11 *mRenderer; - const BufferUsage mUsage; - ID3D11Buffer *mDirectBuffer; - size_t mBufferSize; - bool mDirty; - - static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, BufferUsage usage, unsigned int bufferSize); -}; - -} - -#endif // LIBGLESV2_RENDERER_BUFFERSTORAGE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Fence11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Fence11.cpp deleted file mode 100644 index 2a7d4d43ef..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Fence11.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// Fence11.cpp: Defines the rx::Fence11 class which implements rx::FenceImpl. - -#include "libGLESv2/renderer/d3d11/Fence11.h" -#include "libGLESv2/main.h" -#include "libGLESv2/renderer/d3d11/Renderer11.h" - -namespace rx -{ - -Fence11::Fence11(rx::Renderer11 *renderer) -{ - mRenderer = renderer; - mQuery = NULL; -} - -Fence11::~Fence11() -{ - if (mQuery) - { - mQuery->Release(); - mQuery = NULL; - } -} - -GLboolean Fence11::isFence() -{ - // GL_NV_fence spec: - // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence. - return mQuery != NULL; -} - -void Fence11::setFence(GLenum condition) -{ - if (!mQuery) - { - D3D11_QUERY_DESC queryDesc; - queryDesc.Query = D3D11_QUERY_EVENT; - queryDesc.MiscFlags = 0; - - if (FAILED(mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery))) - { - return gl::error(GL_OUT_OF_MEMORY); - } - } - - mRenderer->getDeviceContext()->End(mQuery); - - setCondition(condition); - setStatus(GL_FALSE); -} - -GLboolean Fence11::testFence() -{ - if (mQuery == NULL) - { - return gl::error(GL_INVALID_OPERATION, GL_TRUE); - } - - HRESULT result = mRenderer->getDeviceContext()->GetData(mQuery, NULL, 0, 0); - - if (mRenderer->isDeviceLost()) - { - return gl::error(GL_OUT_OF_MEMORY, GL_TRUE); - } - - ASSERT(result == S_OK || result == S_FALSE); - setStatus(result == S_OK); - return getStatus(); -} - -void Fence11::finishFence() -{ - if (mQuery == NULL) - { - return gl::error(GL_INVALID_OPERATION); - } - - while (!testFence()) - { - Sleep(0); - } -} - -void Fence11::getFenceiv(GLenum pname, GLint *params) -{ - if (mQuery == NULL) - { - return gl::error(GL_INVALID_OPERATION); - } - - switch (pname) - { - case GL_FENCE_STATUS_NV: - { - // GL_NV_fence spec: - // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV - // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence. - if (getStatus()) - { - params[0] = GL_TRUE; - return; - } - - HRESULT result = mRenderer->getDeviceContext()->GetData(mQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH); - - if (mRenderer->isDeviceLost()) - { - params[0] = GL_TRUE; - return gl::error(GL_OUT_OF_MEMORY); - } - - ASSERT(result == S_OK || result == S_FALSE); - setStatus(result == S_OK); - params[0] = getStatus(); - - break; - } - case GL_FENCE_CONDITION_NV: - params[0] = getCondition(); - break; - default: - return gl::error(GL_INVALID_ENUM); - break; - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Image11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Image11.cpp deleted file mode 100644 index 5d039a35e8..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Image11.cpp +++ /dev/null @@ -1,498 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// Image11.h: Implements the rx::Image11 class, which acts as the interface to -// the actual underlying resources of a Texture - -#include "libGLESv2/renderer/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d11/Image11.h" -#include "libGLESv2/renderer/d3d11/TextureStorage11.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/Renderbuffer.h" - -#include "libGLESv2/main.h" -#include "libGLESv2/utilities.h" -#include "libGLESv2/renderer/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/generatemip.h" - -namespace rx -{ - -Image11::Image11() -{ - mStagingTexture = NULL; - mRenderer = NULL; - mDXGIFormat = DXGI_FORMAT_UNKNOWN; -} - -Image11::~Image11() -{ - if (mStagingTexture) - { - mStagingTexture->Release(); - } -} - -Image11 *Image11::makeImage11(Image *img) -{ - ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img)); - return static_cast<rx::Image11*>(img); -} - -void Image11::generateMipmap(Image11 *dest, Image11 *src) -{ - ASSERT(src->getDXGIFormat() == dest->getDXGIFormat()); - ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth()); - ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight()); - - D3D11_MAPPED_SUBRESOURCE destMapped, srcMapped; - dest->map(D3D11_MAP_WRITE, &destMapped); - src->map(D3D11_MAP_READ, &srcMapped); - - const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData); - unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData); - - if (sourceData && destData) - { - switch (src->getDXGIFormat()) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_B8G8R8A8_UNORM: - GenerateMip<R8G8B8A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); - break; - case DXGI_FORMAT_A8_UNORM: - GenerateMip<A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); - break; - case DXGI_FORMAT_R8_UNORM: - GenerateMip<R8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); - break; - case DXGI_FORMAT_R32G32B32A32_FLOAT: - GenerateMip<A32B32G32R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); - break; - case DXGI_FORMAT_R32G32B32_FLOAT: - GenerateMip<R32G32B32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); - break; - case DXGI_FORMAT_R16G16B16A16_FLOAT: - GenerateMip<A16B16G16R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); - break; - case DXGI_FORMAT_R8G8_UNORM: - GenerateMip<R8G8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); - break; - case DXGI_FORMAT_R16_FLOAT: - GenerateMip<R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); - break; - case DXGI_FORMAT_R16G16_FLOAT: - GenerateMip<R16G16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); - break; - case DXGI_FORMAT_R32_FLOAT: - GenerateMip<R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); - break; - case DXGI_FORMAT_R32G32_FLOAT: - GenerateMip<R32G32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); - break; - default: - UNREACHABLE(); - break; - } - - dest->unmap(); - src->unmap(); - } - - dest->markDirty(); -} - -static bool FormatRequiresInitialization(DXGI_FORMAT dxgiFormat, GLenum internalFormat) -{ - return (dxgiFormat == DXGI_FORMAT_R8G8B8A8_UNORM && gl::GetAlphaSize(internalFormat) == 0) || - (dxgiFormat == DXGI_FORMAT_R32G32B32A32_FLOAT && gl::GetAlphaSize(internalFormat) == 0); -} - -bool Image11::isDirty() const -{ - return ((mStagingTexture || FormatRequiresInitialization(mDXGIFormat, mInternalFormat)) && mDirty); -} - -bool Image11::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) -{ - TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance()); - return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, width, height); -} - -bool Image11::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) -{ - TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance()); - return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, width, height); -} - -bool Image11::redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease) -{ - if (mWidth != width || - mHeight != height || - mInternalFormat != internalformat || - forceRelease) - { - mRenderer = Renderer11::makeRenderer11(renderer); - - mWidth = width; - mHeight = height; - mInternalFormat = internalformat; - // compute the d3d format that will be used - mDXGIFormat = gl_d3d11::ConvertTextureFormat(internalformat, mRenderer->getFeatureLevel()); - mActualFormat = d3d11_gl::ConvertTextureInternalFormat(mDXGIFormat); - - if (mStagingTexture) - { - mStagingTexture->Release(); - mStagingTexture = NULL; - } - - return true; - } - - return false; -} - -bool Image11::isRenderableFormat() const -{ - return TextureStorage11::IsTextureFormatRenderable(mDXGIFormat); -} - -DXGI_FORMAT Image11::getDXGIFormat() const -{ - // this should only happen if the image hasn't been redefined first - // which would be a bug by the caller - ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN); - - return mDXGIFormat; -} - -// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input -// into the target pixel rectangle. -void Image11::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLint unpackAlignment, const void *input) -{ - D3D11_MAPPED_SUBRESOURCE mappedImage; - HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); - if (FAILED(result)) - { - ERR("Could not map image for loading."); - return; - } - - GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment); - size_t pixelSize = d3d11::ComputePixelSizeBits(mDXGIFormat) / 8; - void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * pixelSize)); - - switch (mInternalFormat) - { - case GL_ALPHA8_EXT: - if (mRenderer->getFeatureLevel() >= D3D_FEATURE_LEVEL_10_0) - loadAlphaDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - else - loadAlphaDataToBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_LUMINANCE8_EXT: - loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false); - break; - case GL_ALPHA32F_EXT: - loadAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_LUMINANCE32F_EXT: - loadLuminanceFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_ALPHA16F_EXT: - loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_LUMINANCE16F_EXT: - loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_LUMINANCE8_ALPHA8_EXT: - loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false); - break; - case GL_LUMINANCE_ALPHA32F_EXT: - loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_LUMINANCE_ALPHA16F_EXT: - loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_RGB8_OES: - loadRGBUByteDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_RGB565: - loadRGB565DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_RGBA8_OES: - loadRGBAUByteDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_RGBA4: - loadRGBA4444DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_RGB5_A1: - loadRGBA5551DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_BGRA8_EXT: - loadBGRADataToBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_RGB32F_EXT: - loadRGBFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_RGB16F_EXT: - loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_RGBA32F_EXT: - loadRGBAFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - case GL_RGBA16F_EXT: - loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); - break; - default: UNREACHABLE(); - } - - unmap(); -} - -void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - const void *input) -{ - ASSERT(xoffset % 4 == 0); - ASSERT(yoffset % 4 == 0); - - D3D11_MAPPED_SUBRESOURCE mappedImage; - HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); - if (FAILED(result)) - { - ERR("Could not map image for loading."); - return; - } - - // Size computation assumes a 4x4 block compressed texture format - size_t blockSize = d3d11::ComputeBlockSizeBits(mDXGIFormat) / 8; - void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + ((yoffset / 4) * mappedImage.RowPitch + (xoffset / 4) * blockSize)); - - GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat); - GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat); - int rows = inputSize / inputPitch; - for (int i = 0; i < rows; ++i) - { - memcpy((void*)((BYTE*)offsetMappedData + i * mappedImage.RowPitch), (void*)((BYTE*)input + i * inputPitch), inputPitch); - } - - unmap(); -} - -void Image11::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) -{ - gl::Renderbuffer *colorbuffer = source->getReadColorbuffer(); - - if (colorbuffer && colorbuffer->getActualFormat() == (GLuint)mActualFormat) - { - // No conversion needed-- use copyback fastpath - ID3D11Texture2D *colorBufferTexture = NULL; - unsigned int subresourceIndex = 0; - - if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture)) - { - D3D11_TEXTURE2D_DESC textureDesc; - colorBufferTexture->GetDesc(&textureDesc); - - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - - ID3D11Texture2D* srcTex = NULL; - if (textureDesc.SampleDesc.Count > 1) - { - D3D11_TEXTURE2D_DESC resolveDesc; - resolveDesc.Width = textureDesc.Width; - resolveDesc.Height = textureDesc.Height; - resolveDesc.MipLevels = 1; - resolveDesc.ArraySize = 1; - resolveDesc.Format = textureDesc.Format; - resolveDesc.SampleDesc.Count = 1; - resolveDesc.SampleDesc.Quality = 0; - resolveDesc.Usage = D3D11_USAGE_DEFAULT; - resolveDesc.BindFlags = 0; - resolveDesc.CPUAccessFlags = 0; - resolveDesc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex); - if (FAILED(result)) - { - ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); - return; - } - - deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format); - subresourceIndex = 0; - } - else - { - srcTex = colorBufferTexture; - srcTex->AddRef(); - } - - D3D11_BOX srcBox; - srcBox.left = x; - srcBox.right = x + width; - srcBox.top = y; - srcBox.bottom = y + height; - srcBox.front = 0; - srcBox.back = 1; - - deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, 0, srcTex, subresourceIndex, &srcBox); - - srcTex->Release(); - colorBufferTexture->Release(); - } - } - else - { - // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels - D3D11_MAPPED_SUBRESOURCE mappedImage; - HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); - - // determine the offset coordinate into the destination buffer - GLsizei rowOffset = gl::ComputePixelSize(mActualFormat) * xoffset; - void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset; - - mRenderer->readPixels(source, x, y, width, height, gl::ExtractFormat(mInternalFormat), - gl::ExtractType(mInternalFormat), mappedImage.RowPitch, false, 4, dataOffset); - - unmap(); - } -} - -ID3D11Texture2D *Image11::getStagingTexture() -{ - createStagingTexture(); - - return mStagingTexture; -} - -unsigned int Image11::getStagingSubresource() -{ - createStagingTexture(); - - return mStagingSubresource; -} - -template <typename T, size_t N> -static void setDefaultData(ID3D11DeviceContext *deviceContext, ID3D11Texture2D *texture, UINT subresource, - GLsizei width, GLsizei height, const T (&defaultData)[N]) -{ - D3D11_MAPPED_SUBRESOURCE map; - deviceContext->Map(texture, subresource, D3D11_MAP_WRITE, 0, &map); - - unsigned char* ptr = reinterpret_cast<unsigned char*>(map.pData); - size_t pixelSize = sizeof(T) * N; - - for (GLsizei y = 0; y < height; y++) - { - for (GLsizei x = 0; x < width; x++) - { - memcpy(ptr + (y * map.RowPitch) + (x * pixelSize), defaultData, pixelSize); - } - } - - deviceContext->Unmap(texture, subresource); -} - -void Image11::createStagingTexture() -{ - if (mStagingTexture) - { - return; - } - - ID3D11Texture2D *newTexture = NULL; - int lodOffset = 1; - const DXGI_FORMAT dxgiFormat = getDXGIFormat(); - ASSERT(!d3d11::IsDepthStencilFormat(dxgiFormat)); // We should never get here for depth textures - - if (mWidth != 0 && mHeight != 0) - { - GLsizei width = mWidth; - GLsizei height = mHeight; - - // adjust size if needed for compressed textures - gl::MakeValidSize(false, d3d11::IsCompressed(dxgiFormat), &width, &height, &lodOffset); - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.MipLevels = lodOffset + 1; - desc.ArraySize = 1; - desc.Format = dxgiFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_STAGING; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &newTexture); - - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - ERR("Creating image failed."); - return gl::error(GL_OUT_OF_MEMORY); - } - } - - mStagingTexture = newTexture; - mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); - mDirty = false; - - if (mDXGIFormat == DXGI_FORMAT_R8G8B8A8_UNORM && gl::GetAlphaSize(mInternalFormat) == 0) - { - unsigned char defaultPixel[4] = { 0, 0, 0, 255 }; - setDefaultData(mRenderer->getDeviceContext(), mStagingTexture, mStagingSubresource, mWidth, mHeight, defaultPixel); - } - else if (mDXGIFormat == DXGI_FORMAT_R32G32B32A32_FLOAT && gl::GetAlphaSize(mInternalFormat) == 0) - { - float defaultPixel[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - setDefaultData(mRenderer->getDeviceContext(), mStagingTexture, mStagingSubresource, mWidth, mHeight, defaultPixel); - } -} - -HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) -{ - createStagingTexture(); - - HRESULT result = E_FAIL; - - if (mStagingTexture) - { - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map); - - // this can fail if the device is removed (from TDR) - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - } - else if (SUCCEEDED(result)) - { - mDirty = true; - } - } - - return result; -} - -void Image11::unmap() -{ - if (mStagingTexture) - { - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - deviceContext->Unmap(mStagingTexture, mStagingSubresource); - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Query11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Query11.cpp deleted file mode 100644 index 24c0330a1e..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Query11.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl. - -#include "libGLESv2/renderer/d3d11/Query11.h" -#include "libGLESv2/renderer/d3d11/Renderer11.h" -#include "libGLESv2/main.h" - -namespace rx -{ - -Query11::Query11(rx::Renderer11 *renderer, GLenum type) : QueryImpl(type) -{ - mRenderer = renderer; - mQuery = NULL; -} - -Query11::~Query11() -{ - if (mQuery) - { - mQuery->Release(); - mQuery = NULL; - } -} - -void Query11::begin() -{ - if (mQuery == NULL) - { - D3D11_QUERY_DESC queryDesc; - queryDesc.Query = D3D11_QUERY_OCCLUSION; - queryDesc.MiscFlags = 0; - - if (FAILED(mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery))) - { - return gl::error(GL_OUT_OF_MEMORY); - } - } - - mRenderer->getDeviceContext()->Begin(mQuery); -} - -void Query11::end() -{ - if (mQuery == NULL) - { - return gl::error(GL_INVALID_OPERATION); - } - - mRenderer->getDeviceContext()->End(mQuery); - - mStatus = GL_FALSE; - mResult = GL_FALSE; -} - -GLuint Query11::getResult() -{ - if (mQuery != NULL) - { - while (!testQuery()) - { - Sleep(0); - // explicitly check for device loss, some drivers seem to return S_FALSE - // if the device is lost - if (mRenderer->testDeviceLost(true)) - { - return gl::error(GL_OUT_OF_MEMORY, 0); - } - } - } - - return mResult; -} - -GLboolean Query11::isResultAvailable() -{ - if (mQuery != NULL) - { - testQuery(); - } - - return mStatus; -} - -GLboolean Query11::testQuery() -{ - if (mQuery != NULL && mStatus != GL_TRUE) - { - UINT64 numPixels = 0; - HRESULT result = mRenderer->getDeviceContext()->GetData(mQuery, &numPixels, sizeof(UINT64), 0); - if (result == S_OK) - { - mStatus = GL_TRUE; - - switch (getType()) - { - case GL_ANY_SAMPLES_PASSED_EXT: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; - break; - default: - UNREACHABLE(); - } - } - else if (mRenderer->testDeviceLost(true)) - { - return gl::error(GL_OUT_OF_MEMORY, GL_TRUE); - } - - return mStatus; - } - - return GL_TRUE; // prevent blocking when query is null -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/TextureStorage11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/TextureStorage11.cpp deleted file mode 100644 index 0c981ac503..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/TextureStorage11.cpp +++ /dev/null @@ -1,667 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// TextureStorage11.cpp: Implements the abstract rx::TextureStorage11 class and its concrete derived -// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. - -#include "libGLESv2/renderer/d3d11/TextureStorage11.h" - -#include "libGLESv2/renderer/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d11/RenderTarget11.h" -#include "libGLESv2/renderer/d3d11/SwapChain11.h" -#include "libGLESv2/renderer/d3d11/renderer11_utils.h" - -#include "libGLESv2/utilities.h" -#include "libGLESv2/main.h" - -namespace rx -{ - -TextureStorage11::TextureStorage11(Renderer *renderer, UINT bindFlags) - : mBindFlags(bindFlags), - mLodOffset(0), - mMipLevels(0), - mTexture(NULL), - mTextureFormat(DXGI_FORMAT_UNKNOWN), - mShaderResourceFormat(DXGI_FORMAT_UNKNOWN), - mRenderTargetFormat(DXGI_FORMAT_UNKNOWN), - mDepthStencilFormat(DXGI_FORMAT_UNKNOWN), - mSRV(NULL), - mTextureWidth(0), - mTextureHeight(0) -{ - mRenderer = Renderer11::makeRenderer11(renderer); -} - -TextureStorage11::~TextureStorage11() -{ -} - -TextureStorage11 *TextureStorage11::makeTextureStorage11(TextureStorage *storage) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11*, storage)); - return static_cast<TextureStorage11*>(storage); -} - -DWORD TextureStorage11::GetTextureBindFlags(DXGI_FORMAT format, GLenum glusage, bool forceRenderable) -{ - UINT bindFlags = D3D11_BIND_SHADER_RESOURCE; - - if (d3d11::IsDepthStencilFormat(format)) - { - bindFlags |= D3D11_BIND_DEPTH_STENCIL; - } - else if(forceRenderable || (TextureStorage11::IsTextureFormatRenderable(format) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE))) - { - bindFlags |= D3D11_BIND_RENDER_TARGET; - } - return bindFlags; -} - -bool TextureStorage11::IsTextureFormatRenderable(DXGI_FORMAT format) -{ - switch(format) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_A8_UNORM: - case DXGI_FORMAT_R32G32B32A32_FLOAT: - case DXGI_FORMAT_R16G16B16A16_FLOAT: - case DXGI_FORMAT_B8G8R8A8_UNORM: - case DXGI_FORMAT_R8_UNORM: - case DXGI_FORMAT_R8G8_UNORM: - case DXGI_FORMAT_R16_FLOAT: - case DXGI_FORMAT_R16G16_FLOAT: - return true; - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_R32G32B32_FLOAT: // not renderable on all devices - return false; - default: - UNREACHABLE(); - return false; - } -} - -UINT TextureStorage11::getBindFlags() const -{ - return mBindFlags; -} - -ID3D11Texture2D *TextureStorage11::getBaseTexture() const -{ - return mTexture; -} - -int TextureStorage11::getLodOffset() const -{ - return mLodOffset; -} - -bool TextureStorage11::isRenderTarget() const -{ - return (mBindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL)) != 0; -} - -bool TextureStorage11::isManaged() const -{ - return false; -} - -int TextureStorage11::levelCount() -{ - int levels = 0; - if (getBaseTexture()) - { - levels = mMipLevels - getLodOffset(); - } - return levels; -} - -UINT TextureStorage11::getSubresourceIndex(int level, int faceIndex) -{ - UINT index = 0; - if (getBaseTexture()) - { - index = D3D11CalcSubresource(level, faceIndex, mMipLevels); - } - return index; -} - -bool TextureStorage11::updateSubresourceLevel(ID3D11Texture2D *srcTexture, unsigned int sourceSubresource, - int level, int face, GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height) -{ - if (srcTexture) - { - // Round up the width and height to the nearest multiple of dimension alignment - unsigned int dimensionAlignment = d3d11::GetTextureFormatDimensionAlignment(mTextureFormat); - width = width + dimensionAlignment - 1 - (width - 1) % dimensionAlignment; - height = height + dimensionAlignment - 1 - (height - 1) % dimensionAlignment; - - D3D11_BOX srcBox; - srcBox.left = xoffset; - srcBox.top = yoffset; - srcBox.right = xoffset + width; - srcBox.bottom = yoffset + height; - srcBox.front = 0; - srcBox.back = 1; - - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - - ASSERT(getBaseTexture()); - context->CopySubresourceRegion(getBaseTexture(), getSubresourceIndex(level + mLodOffset, face), - xoffset, yoffset, 0, srcTexture, sourceSubresource, &srcBox); - return true; - } - - return false; -} - -void TextureStorage11::generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest) -{ - if (source && dest) - { - ID3D11ShaderResourceView *sourceSRV = source->getShaderResourceView(); - ID3D11RenderTargetView *destRTV = dest->getRenderTargetView(); - - if (sourceSRV && destRTV) - { - gl::Rectangle sourceArea; - sourceArea.x = 0; - sourceArea.y = 0; - sourceArea.width = source->getWidth(); - sourceArea.height = source->getHeight(); - - gl::Rectangle destArea; - destArea.x = 0; - destArea.y = 0; - destArea.width = dest->getWidth(); - destArea.height = dest->getHeight(); - - mRenderer->copyTexture(sourceSRV, sourceArea, source->getWidth(), source->getHeight(), - destRTV, destArea, dest->getWidth(), dest->getHeight(), - GL_RGBA); - } - } -} - -TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain) - : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE) -{ - mTexture = swapchain->getOffscreenTexture(); - mSRV = swapchain->getRenderTargetShaderResource(); - - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mRenderTarget[i] = NULL; - } - - D3D11_TEXTURE2D_DESC texDesc; - mTexture->GetDesc(&texDesc); - mMipLevels = texDesc.MipLevels; - mTextureFormat = texDesc.Format; - mTextureWidth = texDesc.Width; - mTextureHeight = texDesc.Height; - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - mSRV->GetDesc(&srvDesc); - mShaderResourceFormat = srvDesc.Format; - - ID3D11RenderTargetView* offscreenRTV = swapchain->getRenderTarget(); - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - offscreenRTV->GetDesc(&rtvDesc); - mRenderTargetFormat = rtvDesc.Format; - offscreenRTV->Release(); - - mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; -} - -TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height) - : TextureStorage11(renderer, GetTextureBindFlags(gl_d3d11::ConvertTextureFormat(internalformat, Renderer11::makeRenderer11(renderer)->getFeatureLevel()), usage, forceRenderable)) -{ - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mRenderTarget[i] = NULL; - } - - DXGI_FORMAT convertedFormat = gl_d3d11::ConvertTextureFormat(internalformat, mRenderer->getFeatureLevel()); - if (d3d11::IsDepthStencilFormat(convertedFormat)) - { - mTextureFormat = d3d11::GetDepthTextureFormat(convertedFormat); - mShaderResourceFormat = d3d11::GetDepthShaderResourceFormat(convertedFormat); - mDepthStencilFormat = convertedFormat; - mRenderTargetFormat = DXGI_FORMAT_UNKNOWN; - } - else - { - mTextureFormat = convertedFormat; - mShaderResourceFormat = convertedFormat; - mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; - mRenderTargetFormat = convertedFormat; - } - - // if the width or height is not positive this should be treated as an incomplete texture - // we handle that here by skipping the d3d texture creation - if (width > 0 && height > 0) - { - // adjust size if needed for compressed textures - gl::MakeValidSize(false, gl::IsCompressed(internalformat), &width, &height, &mLodOffset); - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; // Compressed texture size constraints? - desc.Height = height; - desc.MipLevels = mRenderer->getFeatureLevel() >= D3D_FEATURE_LEVEL_10_0 ? ((levels > 0) ? levels + mLodOffset : 0) : 1; - desc.ArraySize = 1; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); - - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - gl::error(GL_OUT_OF_MEMORY); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - ERR("Creating image failed."); - gl::error(GL_OUT_OF_MEMORY); - } - else - { - mTexture->GetDesc(&desc); - mMipLevels = desc.MipLevels; - mTextureWidth = desc.Width; - mTextureHeight = desc.Height; - } - } -} - -TextureStorage11_2D::~TextureStorage11_2D() -{ - if (mTexture) - { - mTexture->Release(); - mTexture = NULL; - } - - if (mSRV) - { - mSRV->Release(); - mSRV = NULL; - } - - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - delete mRenderTarget[i]; - mRenderTarget[i] = NULL; - } -} - -TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage *storage) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2D*, storage)); - return static_cast<TextureStorage11_2D*>(storage); -} - -RenderTarget *TextureStorage11_2D::getRenderTarget(int level) -{ - if (level >= 0 && level < static_cast<int>(mMipLevels)) - { - if (!mRenderTarget[level]) - { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = mShaderResourceFormat; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MostDetailedMip = level; - srvDesc.Texture2D.MipLevels = level ? 1 : -1; - - ID3D11ShaderResourceView *srv; - result = device->CreateShaderResourceView(mTexture, &srvDesc, &srv); - - if (result == E_OUTOFMEMORY) - { - return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); - } - ASSERT(SUCCEEDED(result)); - - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) - { - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = level; - - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); - - if (result == E_OUTOFMEMORY) - { - srv->Release(); - return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); - } - ASSERT(SUCCEEDED(result)); - - // RenderTarget11 expects to be the owner of the resources it is given but TextureStorage11 - // also needs to keep a reference to the texture. - mTexture->AddRef(); - - mRenderTarget[level] = new RenderTarget11(mRenderer, rtv, mTexture, srv, - std::max(mTextureWidth >> level, 1U), - std::max(mTextureHeight >> level, 1U)); - } - else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) - { - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = mDepthStencilFormat; - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = level; - dsvDesc.Flags = 0; - - ID3D11DepthStencilView *dsv; - result = device->CreateDepthStencilView(mTexture, &dsvDesc, &dsv); - - if (result == E_OUTOFMEMORY) - { - srv->Release(); - return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); - } - ASSERT(SUCCEEDED(result)); - - // RenderTarget11 expects to be the owner of the resources it is given but TextureStorage11 - // also needs to keep a reference to the texture. - mTexture->AddRef(); - - mRenderTarget[level] = new RenderTarget11(mRenderer, dsv, mTexture, srv, - std::max(mTextureWidth >> level, 1U), - std::max(mTextureHeight >> level, 1U)); - } - else - { - UNREACHABLE(); - } - } - - return mRenderTarget[level]; - } - else - { - return NULL; - } -} - -ID3D11ShaderResourceView *TextureStorage11_2D::getSRV() -{ - if (!mSRV) - { - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = mShaderResourceFormat; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = (mMipLevels == 0 ? -1 : mMipLevels); - srvDesc.Texture2D.MostDetailedMip = 0; - - HRESULT result = device->CreateShaderResourceView(mTexture, &srvDesc, &mSRV); - - if (result == E_OUTOFMEMORY) - { - return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11ShaderResourceView*>(NULL)); - } - ASSERT(SUCCEEDED(result)); - } - - return mSRV; -} - -void TextureStorage11_2D::generateMipmap(int level) -{ - RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(level - 1)); - RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(level)); - - generateMipmapLayer(source, dest); -} - -TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size) - : TextureStorage11(renderer, GetTextureBindFlags(gl_d3d11::ConvertTextureFormat(internalformat, Renderer11::makeRenderer11(renderer)->getFeatureLevel()), usage, forceRenderable)) -{ - for (unsigned int i = 0; i < 6; i++) - { - for (unsigned int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; j++) - { - mRenderTarget[i][j] = NULL; - } - } - - DXGI_FORMAT convertedFormat = gl_d3d11::ConvertTextureFormat(internalformat, mRenderer->getFeatureLevel()); - if (d3d11::IsDepthStencilFormat(convertedFormat)) - { - mTextureFormat = d3d11::GetDepthTextureFormat(convertedFormat); - mShaderResourceFormat = d3d11::GetDepthShaderResourceFormat(convertedFormat); - mDepthStencilFormat = convertedFormat; - mRenderTargetFormat = DXGI_FORMAT_UNKNOWN; - } - else - { - mTextureFormat = convertedFormat; - mShaderResourceFormat = convertedFormat; - mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; - mRenderTargetFormat = convertedFormat; - } - - // if the size is not positive this should be treated as an incomplete texture - // we handle that here by skipping the d3d texture creation - if (size > 0) - { - // adjust size if needed for compressed textures - int height = size; - gl::MakeValidSize(false, gl::IsCompressed(internalformat), &size, &height, &mLodOffset); - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE2D_DESC desc; - desc.Width = size; - desc.Height = size; - desc.MipLevels = (levels > 0) ? levels + mLodOffset : 0; - desc.ArraySize = 6; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); - - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - ERR("Creating image failed."); - gl::error(GL_OUT_OF_MEMORY); - } - else - { - mTexture->GetDesc(&desc); - mMipLevels = desc.MipLevels; - mTextureWidth = desc.Width; - mTextureHeight = desc.Height; - } - } -} - -TextureStorage11_Cube::~TextureStorage11_Cube() -{ - if (mTexture) - { - mTexture->Release(); - mTexture = NULL; - } - - if (mSRV) - { - mSRV->Release(); - mSRV = NULL; - } - - for (unsigned int i = 0; i < 6; i++) - { - for (unsigned int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; j++) - { - delete mRenderTarget[i][j]; - mRenderTarget[i][j] = NULL; - } - } -} - -TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureStorage *storage) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_Cube*, storage)); - return static_cast<TextureStorage11_Cube*>(storage); -} - -RenderTarget *TextureStorage11_Cube::getRenderTarget(GLenum faceTarget, int level) -{ - unsigned int faceIdx = gl::TextureCubeMap::faceIndex(faceTarget); - if (level >= 0 && level < static_cast<int>(mMipLevels)) - { - if (!mRenderTarget[faceIdx][level]) - { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = mShaderResourceFormat; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube - srvDesc.Texture2DArray.MostDetailedMip = level; - srvDesc.Texture2DArray.MipLevels = 1; - srvDesc.Texture2DArray.FirstArraySlice = faceIdx; - srvDesc.Texture2DArray.ArraySize = 1; - - ID3D11ShaderResourceView *srv; - result = device->CreateShaderResourceView(mTexture, &srvDesc, &srv); - - if (result == E_OUTOFMEMORY) - { - return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); - } - ASSERT(SUCCEEDED(result)); - - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) - { - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = level; - rtvDesc.Texture2DArray.FirstArraySlice = faceIdx; - rtvDesc.Texture2DArray.ArraySize = 1; - - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); - - if (result == E_OUTOFMEMORY) - { - srv->Release(); - return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); - } - ASSERT(SUCCEEDED(result)); - - // RenderTarget11 expects to be the owner of the resources it is given but TextureStorage11 - // also needs to keep a reference to the texture. - mTexture->AddRef(); - - mRenderTarget[faceIdx][level] = new RenderTarget11(mRenderer, rtv, mTexture, srv, - std::max(mTextureWidth >> level, 1U), - std::max(mTextureHeight >> level, 1U)); - } - else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) - { - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = mRenderTargetFormat; - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; - dsvDesc.Texture2DArray.MipSlice = level; - dsvDesc.Texture2DArray.FirstArraySlice = faceIdx; - dsvDesc.Texture2DArray.ArraySize = 1; - - ID3D11DepthStencilView *dsv; - result = device->CreateDepthStencilView(mTexture, &dsvDesc, &dsv); - - if (result == E_OUTOFMEMORY) - { - srv->Release(); - return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL)); - } - ASSERT(SUCCEEDED(result)); - - // RenderTarget11 expects to be the owner of the resources it is given but TextureStorage11 - // also needs to keep a reference to the texture. - mTexture->AddRef(); - - mRenderTarget[faceIdx][level] = new RenderTarget11(mRenderer, dsv, mTexture, srv, - std::max(mTextureWidth >> level, 1U), - std::max(mTextureHeight >> level, 1U)); - } - else - { - UNREACHABLE(); - } - } - - return mRenderTarget[faceIdx][level]; - } - else - { - return NULL; - } -} - -ID3D11ShaderResourceView *TextureStorage11_Cube::getSRV() -{ - if (!mSRV) - { - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = mShaderResourceFormat; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - srvDesc.TextureCube.MipLevels = (mMipLevels == 0 ? -1 : mMipLevels); - srvDesc.TextureCube.MostDetailedMip = 0; - - HRESULT result = device->CreateShaderResourceView(mTexture, &srvDesc, &mSRV); - - if (result == E_OUTOFMEMORY) - { - return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11ShaderResourceView*>(NULL)); - } - ASSERT(SUCCEEDED(result)); - } - - return mSRV; -} - -void TextureStorage11_Cube::generateMipmap(int face, int level) -{ - RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level - 1)); - RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level)); - - generateMipmapLayer(source, dest); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/TextureStorage11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/TextureStorage11.h deleted file mode 100644 index 3c5ded05b8..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/TextureStorage11.h +++ /dev/null @@ -1,120 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// TextureStorage11.h: Defines the abstract rx::TextureStorage11 class and its concrete derived -// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. - -#ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ -#define LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ - -#include "libGLESv2/Texture.h" -#include "libGLESv2/renderer/TextureStorage.h" - -namespace rx -{ -class RenderTarget; -class RenderTarget11; -class Renderer; -class Renderer11; -class SwapChain11; - -class TextureStorage11 : public TextureStorage -{ - public: - TextureStorage11(Renderer *renderer, UINT bindFlags); - virtual ~TextureStorage11(); - - static TextureStorage11 *makeTextureStorage11(TextureStorage *storage); - - static DWORD GetTextureBindFlags(DXGI_FORMAT d3dfmt, GLenum glusage, bool forceRenderable); - static bool IsTextureFormatRenderable(DXGI_FORMAT format); - - UINT getBindFlags() const; - - virtual ID3D11Texture2D *getBaseTexture() const; - virtual ID3D11ShaderResourceView *getSRV() = 0; - virtual RenderTarget *getRenderTarget() { return getRenderTarget(0); } - virtual RenderTarget *getRenderTarget(int level) { return NULL; } - virtual RenderTarget *getRenderTarget(GLenum faceTarget) { return getRenderTarget(faceTarget, 0); } - virtual RenderTarget *getRenderTarget(GLenum faceTarget, int level) { return NULL; } - - virtual void generateMipmap(int level) {}; - virtual void generateMipmap(int face, int level) {}; - - virtual int getLodOffset() const; - virtual bool isRenderTarget() const; - virtual bool isManaged() const; - virtual int levelCount(); - UINT getSubresourceIndex(int level, int faceTarget); - - bool updateSubresourceLevel(ID3D11Texture2D *texture, unsigned int sourceSubresource, int level, - int faceTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - - protected: - void generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest); - - Renderer11 *mRenderer; - int mLodOffset; - unsigned int mMipLevels; - - ID3D11Texture2D *mTexture; - DXGI_FORMAT mTextureFormat; - DXGI_FORMAT mShaderResourceFormat; - DXGI_FORMAT mRenderTargetFormat; - DXGI_FORMAT mDepthStencilFormat; - unsigned int mTextureWidth; - unsigned int mTextureHeight; - - ID3D11ShaderResourceView *mSRV; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage11); - - const UINT mBindFlags; -}; - -class TextureStorage11_2D : public TextureStorage11 -{ - public: - TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain); - TextureStorage11_2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height); - virtual ~TextureStorage11_2D(); - - static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage); - - virtual ID3D11ShaderResourceView *getSRV(); - virtual RenderTarget *getRenderTarget(int level); - - virtual void generateMipmap(int level); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2D); - - RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; -}; - -class TextureStorage11_Cube : public TextureStorage11 -{ - public: - TextureStorage11_Cube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size); - virtual ~TextureStorage11_Cube(); - - static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage); - - virtual ID3D11ShaderResourceView *getSRV(); - virtual RenderTarget *getRenderTarget(GLenum faceTarget, int level); - - virtual void generateMipmap(int face, int level); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage11_Cube); - - RenderTarget11 *mRenderTarget[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; -}; - -} - -#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/VertexBuffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/VertexBuffer11.cpp deleted file mode 100644 index 6f9b4181f1..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/VertexBuffer11.cpp +++ /dev/null @@ -1,440 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation. - -#include "libGLESv2/renderer/d3d11/VertexBuffer11.h" -#include "libGLESv2/renderer/BufferStorage.h" - -#include "libGLESv2/Buffer.h" -#include "libGLESv2/renderer/d3d11/Renderer11.h" -#include "libGLESv2/Context.h" - -namespace rx -{ - -VertexBuffer11::VertexBuffer11(rx::Renderer11 *const renderer) : mRenderer(renderer) -{ - mBuffer = NULL; - mBufferSize = 0; - mDynamicUsage = false; -} - -VertexBuffer11::~VertexBuffer11() -{ - if (mBuffer) - { - mBuffer->Release(); - mBuffer = NULL; - } -} - -bool VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) -{ - if (mBuffer) - { - mBuffer->Release(); - mBuffer = NULL; - } - - updateSerial(); - - if (size > 0) - { - ID3D11Device* dxDevice = mRenderer->getDevice(); - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = size; - bufferDesc.Usage = D3D11_USAGE_DYNAMIC; - bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - bufferDesc.MiscFlags = 0; - bufferDesc.StructureByteStride = 0; - - HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); - if (FAILED(result)) - { - return false; - } - } - - mBufferSize = size; - mDynamicUsage = dynamicUsage; - return true; -} - -VertexBuffer11 *VertexBuffer11::makeVertexBuffer11(VertexBuffer *vetexBuffer) -{ - ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer11*, vetexBuffer)); - return static_cast<VertexBuffer11*>(vetexBuffer); -} - -bool VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, - GLsizei instances, unsigned int offset) -{ - if (mBuffer) - { - gl::Buffer *buffer = attrib.mBoundBuffer.get(); - - int inputStride = attrib.stride(); - const VertexConverter &converter = getVertexConversion(attrib); - - ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); - if (FAILED(result)) - { - ERR("Vertex buffer map failed with error 0x%08x", result); - return false; - } - - char* output = reinterpret_cast<char*>(mappedResource.pData) + offset; - - const char *input = NULL; - if (buffer) - { - BufferStorage *storage = buffer->getStorage(); - input = static_cast<const char*>(storage->getData()) + static_cast<int>(attrib.mOffset); - } - else - { - input = static_cast<const char*>(attrib.mPointer); - } - - if (instances == 0 || attrib.mDivisor == 0) - { - input += inputStride * start; - } - - converter.conversionFunc(input, inputStride, count, output); - - dxContext->Unmap(mBuffer, 0); - - return true; - } - else - { - ERR("Vertex buffer not initialized."); - return false; - } -} - -bool VertexBuffer11::storeRawData(const void* data, unsigned int size, unsigned int offset) -{ - if (mBuffer) - { - ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); - if (FAILED(result)) - { - ERR("Vertex buffer map failed with error 0x%08x", result); - return false; - } - - char* bufferData = static_cast<char*>(mappedResource.pData); - memcpy(bufferData + offset, data, size); - - dxContext->Unmap(mBuffer, 0); - - return true; - } - else - { - ERR("Vertex buffer not initialized."); - return false; - } -} - -bool VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, - GLsizei instances, unsigned int *outSpaceRequired) const -{ - unsigned int elementSize = getVertexConversion(attrib).outputElementSize; - - unsigned int elementCount = 0; - if (instances == 0 || attrib.mDivisor == 0) - { - elementCount = count; - } - else - { - if (static_cast<unsigned int>(instances) < std::numeric_limits<unsigned int>::max() - (attrib.mDivisor - 1)) - { - // Round up - elementCount = (static_cast<unsigned int>(instances) + (attrib.mDivisor - 1)) / attrib.mDivisor; - } - else - { - elementCount = instances / attrib.mDivisor; - } - } - - if (elementSize <= std::numeric_limits<unsigned int>::max() / elementCount) - { - if (outSpaceRequired) - { - *outSpaceRequired = elementSize * elementCount; - } - return true; - } - else - { - return false; - } -} - -bool VertexBuffer11::requiresConversion(const gl::VertexAttribute &attrib) const -{ - return !getVertexConversion(attrib).identity; -} - -unsigned int VertexBuffer11::getBufferSize() const -{ - return mBufferSize; -} - -bool VertexBuffer11::setBufferSize(unsigned int size) -{ - if (size > mBufferSize) - { - return initialize(size, mDynamicUsage); - } - else - { - return true; - } -} - -bool VertexBuffer11::discard() -{ - if (mBuffer) - { - ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - ERR("Vertex buffer map failed with error 0x%08x", result); - return false; - } - - dxContext->Unmap(mBuffer, 0); - - return true; - } - else - { - ERR("Vertex buffer not initialized."); - return false; - } -} - -unsigned int VertexBuffer11::getVertexSize(const gl::VertexAttribute &attrib) const -{ - return getVertexConversion(attrib).outputElementSize; -} - -DXGI_FORMAT VertexBuffer11::getDXGIFormat(const gl::VertexAttribute &attrib) const -{ - return getVertexConversion(attrib).dxgiFormat; -} - -ID3D11Buffer *VertexBuffer11::getBuffer() const -{ - return mBuffer; -} - -template <typename T, unsigned int componentCount, bool widen, bool normalized> -static void copyVertexData(const void *input, unsigned int stride, unsigned int count, void *output) -{ - unsigned int attribSize = sizeof(T) * componentCount; - - if (attribSize == stride && !widen) - { - memcpy(output, input, count * attribSize); - } - else - { - unsigned int outputStride = widen ? 4 : componentCount; - T defaultVal = normalized ? std::numeric_limits<T>::max() : T(1); - - for (unsigned int i = 0; i < count; i++) - { - const T *offsetInput = reinterpret_cast<const T*>(reinterpret_cast<const char*>(input) + i * stride); - T *offsetOutput = reinterpret_cast<T*>(output) + i * outputStride; - - for (unsigned int j = 0; j < componentCount; j++) - { - offsetOutput[j] = offsetInput[j]; - } - - if (widen) - { - offsetOutput[3] = defaultVal; - } - } - } -} - -template <unsigned int componentCount> -static void copyFixedVertexData(const void* input, unsigned int stride, unsigned int count, void* output) -{ - static const float divisor = 1.0f / (1 << 16); - - for (unsigned int i = 0; i < count; i++) - { - const GLfixed* offsetInput = reinterpret_cast<const GLfixed*>(reinterpret_cast<const char*>(input) + stride * i); - float* offsetOutput = reinterpret_cast<float*>(output) + i * componentCount; - - for (unsigned int j = 0; j < componentCount; j++) - { - offsetOutput[j] = static_cast<float>(offsetInput[j]) * divisor; - } - } -} - -template <typename T, unsigned int componentCount, bool normalized> -static void copyToFloatVertexData(const void* input, unsigned int stride, unsigned int count, void* output) -{ - typedef std::numeric_limits<T> NL; - - for (unsigned int i = 0; i < count; i++) - { - const T *offsetInput = reinterpret_cast<const T*>(reinterpret_cast<const char*>(input) + stride * i); - float *offsetOutput = reinterpret_cast<float*>(output) + i * componentCount; - - for (unsigned int j = 0; j < componentCount; j++) - { - if (normalized) - { - if (NL::is_signed) - { - const float divisor = 1.0f / (2 * static_cast<float>(NL::max()) + 1); - offsetOutput[j] = (2 * static_cast<float>(offsetInput[j]) + 1) * divisor; - } - else - { - offsetOutput[j] = static_cast<float>(offsetInput[j]) / NL::max(); - } - } - else - { - offsetOutput[j] = static_cast<float>(offsetInput[j]); - } - } - } -} - -const VertexBuffer11::VertexConverter VertexBuffer11::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = -{ - { // GL_BYTE - { // unnormalized - { ©ToFloatVertexData<GLbyte, 1, false>, false, DXGI_FORMAT_R32_FLOAT, 4 }, - { ©ToFloatVertexData<GLbyte, 2, false>, false, DXGI_FORMAT_R32G32_FLOAT, 8 }, - { ©ToFloatVertexData<GLbyte, 3, false>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 }, - { ©ToFloatVertexData<GLbyte, 4, false>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 }, - }, - { // normalized - { ©VertexData<GLbyte, 1, false, true>, true, DXGI_FORMAT_R8_SNORM, 1 }, - { ©VertexData<GLbyte, 2, false, true>, true, DXGI_FORMAT_R8G8_SNORM, 2 }, - { ©VertexData<GLbyte, 3, true, true>, false, DXGI_FORMAT_R8G8B8A8_SNORM, 4 }, - { ©VertexData<GLbyte, 4, false, true>, true, DXGI_FORMAT_R8G8B8A8_SNORM, 4 }, - }, - }, - { // GL_UNSIGNED_BYTE - { // unnormalized - { ©ToFloatVertexData<GLubyte, 1, false>, false, DXGI_FORMAT_R32_FLOAT, 4 }, - { ©ToFloatVertexData<GLubyte, 2, false>, false, DXGI_FORMAT_R32G32_FLOAT, 8 }, - { ©ToFloatVertexData<GLubyte, 3, false>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 }, - { ©ToFloatVertexData<GLubyte, 4, false>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 }, - }, - { // normalized - { ©VertexData<GLubyte, 1, false, true>, true, DXGI_FORMAT_R8_UNORM, 1 }, - { ©VertexData<GLubyte, 2, false, true>, true, DXGI_FORMAT_R8G8_UNORM, 2 }, - { ©VertexData<GLubyte, 3, true, true>, false, DXGI_FORMAT_R8G8B8A8_UNORM, 4 }, - { ©VertexData<GLubyte, 4, false, true>, true, DXGI_FORMAT_R8G8B8A8_UNORM, 4 }, - }, - }, - { // GL_SHORT - { // unnormalized - { ©ToFloatVertexData<GLshort, 1, false>, false, DXGI_FORMAT_R32_FLOAT, 4 }, - { ©ToFloatVertexData<GLshort, 2, false>, false, DXGI_FORMAT_R32G32_FLOAT, 8 }, - { ©ToFloatVertexData<GLshort, 3, false>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 }, - { ©ToFloatVertexData<GLshort, 4, false>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 }, - }, - { // normalized - { ©VertexData<GLshort, 1, false, true>, true, DXGI_FORMAT_R16_SNORM, 2 }, - { ©VertexData<GLshort, 2, false, true>, true, DXGI_FORMAT_R16G16_SNORM, 4 }, - { ©VertexData<GLshort, 3, true, true>, false, DXGI_FORMAT_R16G16B16A16_SNORM, 8 }, - { ©VertexData<GLshort, 4, false, true>, true, DXGI_FORMAT_R16G16B16A16_SNORM, 8 }, - }, - }, - { // GL_UNSIGNED_SHORT - { // unnormalized - { ©ToFloatVertexData<GLushort, 1, false>, false, DXGI_FORMAT_R32_FLOAT, 4 }, - { ©ToFloatVertexData<GLushort, 2, false>, false, DXGI_FORMAT_R32G32_FLOAT, 8 }, - { ©ToFloatVertexData<GLushort, 3, false>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 }, - { ©ToFloatVertexData<GLushort, 4, false>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 }, - }, - { // normalized - { ©VertexData<GLushort, 1, false, true>, true, DXGI_FORMAT_R16_UNORM, 2 }, - { ©VertexData<GLushort, 2, false, true>, true, DXGI_FORMAT_R16G16_UNORM, 4 }, - { ©VertexData<GLushort, 3, true, true>, false, DXGI_FORMAT_R16G16B16A16_UNORM, 8 }, - { ©VertexData<GLushort, 4, false, true>, true, DXGI_FORMAT_R16G16B16A16_UNORM, 8 }, - }, - }, - { // GL_FIXED - { // unnormalized - { ©FixedVertexData<1>, false, DXGI_FORMAT_R32_FLOAT, 4 }, - { ©FixedVertexData<2>, false, DXGI_FORMAT_R32G32_FLOAT, 8 }, - { ©FixedVertexData<3>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 }, - { ©FixedVertexData<4>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 }, - }, - { // normalized - { ©FixedVertexData<1>, false, DXGI_FORMAT_R32_FLOAT, 4 }, - { ©FixedVertexData<2>, false, DXGI_FORMAT_R32G32_FLOAT, 8 }, - { ©FixedVertexData<3>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 }, - { ©FixedVertexData<4>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 }, - }, - }, - { // GL_FLOAT - { // unnormalized - { ©VertexData<GLfloat, 1, false, false>, true, DXGI_FORMAT_R32_FLOAT, 4 }, - { ©VertexData<GLfloat, 2, false, false>, true, DXGI_FORMAT_R32G32_FLOAT, 8 }, - { ©VertexData<GLfloat, 3, false, false>, true, DXGI_FORMAT_R32G32B32_FLOAT, 12 }, - { ©VertexData<GLfloat, 4, false, false>, true, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 }, - }, - { // normalized - { ©VertexData<GLfloat, 1, false, false>, true, DXGI_FORMAT_R32_FLOAT, 4 }, - { ©VertexData<GLfloat, 2, false, false>, true, DXGI_FORMAT_R32G32_FLOAT, 8 }, - { ©VertexData<GLfloat, 3, false, false>, true, DXGI_FORMAT_R32G32B32_FLOAT, 12 }, - { ©VertexData<GLfloat, 4, false, false>, true, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 }, - }, - }, -}; - -const VertexBuffer11::VertexConverter &VertexBuffer11::getVertexConversion(const gl::VertexAttribute &attribute) -{ - unsigned int typeIndex = 0; - switch (attribute.mType) - { - case GL_BYTE: typeIndex = 0; break; - case GL_UNSIGNED_BYTE: typeIndex = 1; break; - case GL_SHORT: typeIndex = 2; break; - case GL_UNSIGNED_SHORT: typeIndex = 3; break; - case GL_FIXED: typeIndex = 4; break; - case GL_FLOAT: typeIndex = 5; break; - default: UNREACHABLE(); break; - } - - return mPossibleTranslations[typeIndex][attribute.mNormalized ? 1 : 0][attribute.mSize - 1]; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/renderer11_utils.cpp deleted file mode 100644 index 34b8259a80..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/renderer11_utils.cpp +++ /dev/null @@ -1,688 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// renderer11_utils.cpp: Conversion functions and other utility routines -// specific to the D3D11 renderer. - -#include "libGLESv2/renderer/d3d11/renderer11_utils.h" - -#include "common/debug.h" - -namespace gl_d3d11 -{ - -D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha) -{ - D3D11_BLEND d3dBlend = D3D11_BLEND_ZERO; - - switch (glBlend) - { - case GL_ZERO: d3dBlend = D3D11_BLEND_ZERO; break; - case GL_ONE: d3dBlend = D3D11_BLEND_ONE; break; - case GL_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_SRC_ALPHA : D3D11_BLEND_SRC_COLOR); break; - case GL_ONE_MINUS_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_SRC_ALPHA : D3D11_BLEND_INV_SRC_COLOR); break; - case GL_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_DEST_COLOR); break; - case GL_ONE_MINUS_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_INV_DEST_COLOR); break; - case GL_SRC_ALPHA: d3dBlend = D3D11_BLEND_SRC_ALPHA; break; - case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3D11_BLEND_INV_SRC_ALPHA; break; - case GL_DST_ALPHA: d3dBlend = D3D11_BLEND_DEST_ALPHA; break; - case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3D11_BLEND_INV_DEST_ALPHA; break; - case GL_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; - case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; - case GL_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; - case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; - case GL_SRC_ALPHA_SATURATE: d3dBlend = D3D11_BLEND_SRC_ALPHA_SAT; break; - default: UNREACHABLE(); - } - - return d3dBlend; -} - -D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp) -{ - D3D11_BLEND_OP d3dBlendOp = D3D11_BLEND_OP_ADD; - - switch (glBlendOp) - { - case GL_FUNC_ADD: d3dBlendOp = D3D11_BLEND_OP_ADD; break; - case GL_FUNC_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_SUBTRACT; break; - case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_REV_SUBTRACT; break; - default: UNREACHABLE(); - } - - return d3dBlendOp; -} - -UINT8 ConvertColorMask(bool red, bool green, bool blue, bool alpha) -{ - UINT8 mask = 0; - if (red) - { - mask |= D3D11_COLOR_WRITE_ENABLE_RED; - } - if (green) - { - mask |= D3D11_COLOR_WRITE_ENABLE_GREEN; - } - if (blue) - { - mask |= D3D11_COLOR_WRITE_ENABLE_BLUE; - } - if (alpha) - { - mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; - } - return mask; -} - -D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode) -{ - D3D11_CULL_MODE cull = D3D11_CULL_NONE; - - if (cullEnabled) - { - switch (cullMode) - { - case GL_FRONT: cull = D3D11_CULL_FRONT; break; - case GL_BACK: cull = D3D11_CULL_BACK; break; - case GL_FRONT_AND_BACK: cull = D3D11_CULL_NONE; break; - default: UNREACHABLE(); - } - } - else - { - cull = D3D11_CULL_NONE; - } - - return cull; -} - -D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison) -{ - D3D11_COMPARISON_FUNC d3dComp = D3D11_COMPARISON_NEVER; - switch (comparison) - { - case GL_NEVER: d3dComp = D3D11_COMPARISON_NEVER; break; - case GL_ALWAYS: d3dComp = D3D11_COMPARISON_ALWAYS; break; - case GL_LESS: d3dComp = D3D11_COMPARISON_LESS; break; - case GL_LEQUAL: d3dComp = D3D11_COMPARISON_LESS_EQUAL; break; - case GL_EQUAL: d3dComp = D3D11_COMPARISON_EQUAL; break; - case GL_GREATER: d3dComp = D3D11_COMPARISON_GREATER; break; - case GL_GEQUAL: d3dComp = D3D11_COMPARISON_GREATER_EQUAL; break; - case GL_NOTEQUAL: d3dComp = D3D11_COMPARISON_NOT_EQUAL; break; - default: UNREACHABLE(); - } - - return d3dComp; -} - -D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled) -{ - return depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; -} - -UINT8 ConvertStencilMask(GLuint stencilmask) -{ - return static_cast<UINT8>(stencilmask); -} - -D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp) -{ - D3D11_STENCIL_OP d3dStencilOp = D3D11_STENCIL_OP_KEEP; - - switch (stencilOp) - { - case GL_ZERO: d3dStencilOp = D3D11_STENCIL_OP_ZERO; break; - case GL_KEEP: d3dStencilOp = D3D11_STENCIL_OP_KEEP; break; - case GL_REPLACE: d3dStencilOp = D3D11_STENCIL_OP_REPLACE; break; - case GL_INCR: d3dStencilOp = D3D11_STENCIL_OP_INCR_SAT; break; - case GL_DECR: d3dStencilOp = D3D11_STENCIL_OP_DECR_SAT; break; - case GL_INVERT: d3dStencilOp = D3D11_STENCIL_OP_INVERT; break; - case GL_INCR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_INCR; break; - case GL_DECR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_DECR; break; - default: UNREACHABLE(); - } - - return d3dStencilOp; -} - -D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy) -{ - if (maxAnisotropy > 1.0f) - { - return D3D11_ENCODE_ANISOTROPIC_FILTER(false); - } - else - { - D3D11_FILTER_TYPE dxMin = D3D11_FILTER_TYPE_POINT; - D3D11_FILTER_TYPE dxMip = D3D11_FILTER_TYPE_POINT; - switch (minFilter) - { - case GL_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_NEAREST_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_LINEAR_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_NEAREST_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_LINEAR; break; - case GL_LINEAR_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_LINEAR; break; - default: UNREACHABLE(); - } - - D3D11_FILTER_TYPE dxMag = D3D11_FILTER_TYPE_POINT; - switch (magFilter) - { - case GL_NEAREST: dxMag = D3D11_FILTER_TYPE_POINT; break; - case GL_LINEAR: dxMag = D3D11_FILTER_TYPE_LINEAR; break; - default: UNREACHABLE(); - } - - return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, false); - } -} - -D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap) -{ - switch (wrap) - { - case GL_REPEAT: return D3D11_TEXTURE_ADDRESS_WRAP; - case GL_CLAMP_TO_EDGE: return D3D11_TEXTURE_ADDRESS_CLAMP; - case GL_MIRRORED_REPEAT: return D3D11_TEXTURE_ADDRESS_MIRROR; - default: UNREACHABLE(); - } - - return D3D11_TEXTURE_ADDRESS_WRAP; -} - -FLOAT ConvertMinLOD(GLenum minFilter, unsigned int lodOffset) -{ - return (minFilter == GL_NEAREST || minFilter == GL_LINEAR) ? static_cast<float>(lodOffset) : -FLT_MAX; -} - -FLOAT ConvertMaxLOD(GLenum minFilter, unsigned int lodOffset) -{ - return (minFilter == GL_NEAREST || minFilter == GL_LINEAR) ? static_cast<float>(lodOffset) : FLT_MAX; -} - -} - -namespace d3d11_gl -{ - -GLenum ConvertBackBufferFormat(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: return GL_RGBA8_OES; - case DXGI_FORMAT_B8G8R8A8_UNORM: return GL_BGRA8_EXT; - default: - UNREACHABLE(); - } - - return GL_RGBA8_OES; -} - -GLenum ConvertDepthStencilFormat(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_UNKNOWN: return GL_NONE; - case DXGI_FORMAT_D16_UNORM: return GL_DEPTH_COMPONENT16; - case DXGI_FORMAT_D24_UNORM_S8_UINT: return GL_DEPTH24_STENCIL8_OES; - default: - UNREACHABLE(); - } - - return GL_DEPTH24_STENCIL8_OES; -} - -GLenum ConvertRenderbufferFormat(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_B8G8R8A8_UNORM: - return GL_BGRA8_EXT; - case DXGI_FORMAT_R8G8B8A8_UNORM: - return GL_RGBA8_OES; - case DXGI_FORMAT_D16_UNORM: - return GL_DEPTH_COMPONENT16; - case DXGI_FORMAT_D24_UNORM_S8_UINT: - return GL_DEPTH24_STENCIL8_OES; - default: - UNREACHABLE(); - } - - return GL_RGBA8_OES; -} - -GLenum ConvertTextureInternalFormat(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - return GL_RGBA8_OES; - case DXGI_FORMAT_A8_UNORM: - return GL_ALPHA8_EXT; - case DXGI_FORMAT_BC1_UNORM: - return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - case DXGI_FORMAT_BC2_UNORM: - return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; - case DXGI_FORMAT_BC3_UNORM: - return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; - case DXGI_FORMAT_R32G32B32A32_FLOAT: - return GL_RGBA32F_EXT; - case DXGI_FORMAT_R32G32B32_FLOAT: - return GL_RGB32F_EXT; - case DXGI_FORMAT_R16G16B16A16_FLOAT: - return GL_RGBA16F_EXT; - case DXGI_FORMAT_B8G8R8A8_UNORM: - return GL_BGRA8_EXT; - case DXGI_FORMAT_R8_UNORM: - return GL_R8_EXT; - case DXGI_FORMAT_R8G8_UNORM: - return GL_RG8_EXT; - case DXGI_FORMAT_R16_FLOAT: - return GL_R16F_EXT; - case DXGI_FORMAT_R16G16_FLOAT: - return GL_RG16F_EXT; - case DXGI_FORMAT_D16_UNORM: - return GL_DEPTH_COMPONENT16; - case DXGI_FORMAT_D24_UNORM_S8_UINT: - return GL_DEPTH24_STENCIL8_OES; - case DXGI_FORMAT_UNKNOWN: - return GL_NONE; - default: - UNREACHABLE(); - } - - return GL_RGBA8_OES; -} - -} - -namespace gl_d3d11 -{ - -DXGI_FORMAT ConvertRenderbufferFormat(GLenum format) -{ - switch (format) - { - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGBA8_OES: - case GL_RGB565: - case GL_RGB8_OES: - return DXGI_FORMAT_R8G8B8A8_UNORM; - case GL_BGRA8_EXT: - return DXGI_FORMAT_B8G8R8A8_UNORM; - case GL_DEPTH_COMPONENT16: - return DXGI_FORMAT_D16_UNORM; - case GL_STENCIL_INDEX8: - case GL_DEPTH24_STENCIL8_OES: - return DXGI_FORMAT_D24_UNORM_S8_UINT; - default: - UNREACHABLE(); - } - - return DXGI_FORMAT_R8G8B8A8_UNORM; -} - -DXGI_FORMAT ConvertTextureFormat(GLenum internalformat, D3D_FEATURE_LEVEL featureLevel) -{ - switch (internalformat) - { - case GL_RGB565: - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGB8_OES: - case GL_RGBA8_OES: - case GL_LUMINANCE8_EXT: - case GL_LUMINANCE8_ALPHA8_EXT: - return DXGI_FORMAT_R8G8B8A8_UNORM; - case GL_ALPHA8_EXT: - return featureLevel >= D3D_FEATURE_LEVEL_10_0 ? DXGI_FORMAT_A8_UNORM : DXGI_FORMAT_B8G8R8A8_UNORM; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - return DXGI_FORMAT_BC1_UNORM; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - return DXGI_FORMAT_BC2_UNORM; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - return DXGI_FORMAT_BC3_UNORM; - case GL_RGBA32F_EXT: - case GL_ALPHA32F_EXT: - case GL_LUMINANCE_ALPHA32F_EXT: - return DXGI_FORMAT_R32G32B32A32_FLOAT; - case GL_RGB32F_EXT: - case GL_LUMINANCE32F_EXT: - return DXGI_FORMAT_R32G32B32A32_FLOAT; - case GL_RGBA16F_EXT: - case GL_ALPHA16F_EXT: - case GL_LUMINANCE_ALPHA16F_EXT: - case GL_RGB16F_EXT: - case GL_LUMINANCE16F_EXT: - return DXGI_FORMAT_R16G16B16A16_FLOAT; - case GL_BGRA8_EXT: - return DXGI_FORMAT_B8G8R8A8_UNORM; - case GL_R8_EXT: - return DXGI_FORMAT_R8_UNORM; - case GL_RG8_EXT: - return DXGI_FORMAT_R8G8_UNORM; - case GL_R16F_EXT: - return DXGI_FORMAT_R16_FLOAT; - case GL_RG16F_EXT: - return DXGI_FORMAT_R16G16_FLOAT; - case GL_DEPTH_COMPONENT16: - return DXGI_FORMAT_D16_UNORM; - case GL_DEPTH_COMPONENT32_OES: - case GL_DEPTH24_STENCIL8_OES: - return DXGI_FORMAT_D24_UNORM_S8_UINT; - case GL_NONE: - return DXGI_FORMAT_UNKNOWN; - default: - UNREACHABLE(); - } - - return DXGI_FORMAT_R8G8B8A8_UNORM; -} - -} - -namespace d3d11 -{ - -void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v) -{ - vertex->x = x; - vertex->y = y; - vertex->u = u; - vertex->v = v; -} - -void SetPositionDepthColorVertex(PositionDepthColorVertex* vertex, float x, float y, float z, - const gl::Color &color) -{ - vertex->x = x; - vertex->y = y; - vertex->z = z; - vertex->r = color.red; - vertex->g = color.green; - vertex->b = color.blue; - vertex->a = color.alpha; -} - -size_t ComputePixelSizeBits(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_R1_UNORM: - return 1; - - case DXGI_FORMAT_A8_UNORM: - case DXGI_FORMAT_R8_SINT: - case DXGI_FORMAT_R8_SNORM: - case DXGI_FORMAT_R8_TYPELESS: - case DXGI_FORMAT_R8_UINT: - case DXGI_FORMAT_R8_UNORM: - return 8; - - case DXGI_FORMAT_B5G5R5A1_UNORM: - case DXGI_FORMAT_B5G6R5_UNORM: - case DXGI_FORMAT_D16_UNORM: - case DXGI_FORMAT_R16_FLOAT: - case DXGI_FORMAT_R16_SINT: - case DXGI_FORMAT_R16_SNORM: - case DXGI_FORMAT_R16_TYPELESS: - case DXGI_FORMAT_R16_UINT: - case DXGI_FORMAT_R16_UNORM: - case DXGI_FORMAT_R8G8_SINT: - case DXGI_FORMAT_R8G8_SNORM: - case DXGI_FORMAT_R8G8_TYPELESS: - case DXGI_FORMAT_R8G8_UINT: - case DXGI_FORMAT_R8G8_UNORM: - return 16; - - case DXGI_FORMAT_B8G8R8X8_TYPELESS: - case DXGI_FORMAT_B8G8R8X8_UNORM: - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - case DXGI_FORMAT_D24_UNORM_S8_UINT: - case DXGI_FORMAT_D32_FLOAT: - case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: - case DXGI_FORMAT_G8R8_G8B8_UNORM: - case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: - case DXGI_FORMAT_R10G10B10A2_TYPELESS: - case DXGI_FORMAT_R10G10B10A2_UINT: - case DXGI_FORMAT_R10G10B10A2_UNORM: - case DXGI_FORMAT_R11G11B10_FLOAT: - case DXGI_FORMAT_R16G16_FLOAT: - case DXGI_FORMAT_R16G16_SINT: - case DXGI_FORMAT_R16G16_SNORM: - case DXGI_FORMAT_R16G16_TYPELESS: - case DXGI_FORMAT_R16G16_UINT: - case DXGI_FORMAT_R16G16_UNORM: - case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: - case DXGI_FORMAT_R24G8_TYPELESS: - case DXGI_FORMAT_R32_FLOAT: - case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: - case DXGI_FORMAT_R32_SINT: - case DXGI_FORMAT_R32_TYPELESS: - case DXGI_FORMAT_R32_UINT: - case DXGI_FORMAT_R8G8_B8G8_UNORM: - case DXGI_FORMAT_R8G8B8A8_SINT: - case DXGI_FORMAT_R8G8B8A8_SNORM: - case DXGI_FORMAT_R8G8B8A8_TYPELESS: - case DXGI_FORMAT_R8G8B8A8_UINT: - case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - case DXGI_FORMAT_B8G8R8A8_TYPELESS: - case DXGI_FORMAT_B8G8R8A8_UNORM: - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: - case DXGI_FORMAT_X24_TYPELESS_G8_UINT: - case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: - return 32; - - case DXGI_FORMAT_R16G16B16A16_FLOAT: - case DXGI_FORMAT_R16G16B16A16_SINT: - case DXGI_FORMAT_R16G16B16A16_SNORM: - case DXGI_FORMAT_R16G16B16A16_TYPELESS: - case DXGI_FORMAT_R16G16B16A16_UINT: - case DXGI_FORMAT_R16G16B16A16_UNORM: - case DXGI_FORMAT_R32G32_FLOAT: - case DXGI_FORMAT_R32G32_SINT: - case DXGI_FORMAT_R32G32_TYPELESS: - case DXGI_FORMAT_R32G32_UINT: - case DXGI_FORMAT_R32G8X24_TYPELESS: - return 64; - - case DXGI_FORMAT_R32G32B32_FLOAT: - case DXGI_FORMAT_R32G32B32_SINT: - case DXGI_FORMAT_R32G32B32_TYPELESS: - case DXGI_FORMAT_R32G32B32_UINT: - return 96; - - case DXGI_FORMAT_R32G32B32A32_FLOAT: - case DXGI_FORMAT_R32G32B32A32_SINT: - case DXGI_FORMAT_R32G32B32A32_TYPELESS: - case DXGI_FORMAT_R32G32B32A32_UINT: - return 128; - - case DXGI_FORMAT_BC1_TYPELESS: - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: - case DXGI_FORMAT_BC4_SNORM: - case DXGI_FORMAT_BC4_TYPELESS: - case DXGI_FORMAT_BC4_UNORM: - return 4; - - case DXGI_FORMAT_BC2_TYPELESS: - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: - case DXGI_FORMAT_BC3_TYPELESS: - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: - case DXGI_FORMAT_BC5_SNORM: - case DXGI_FORMAT_BC5_TYPELESS: - case DXGI_FORMAT_BC5_UNORM: - case DXGI_FORMAT_BC6H_SF16: - case DXGI_FORMAT_BC6H_TYPELESS: - case DXGI_FORMAT_BC6H_UF16: - case DXGI_FORMAT_BC7_TYPELESS: - case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: - return 8; - - default: - return 0; - } -} - -size_t ComputeBlockSizeBits(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_BC1_TYPELESS: - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: - case DXGI_FORMAT_BC4_SNORM: - case DXGI_FORMAT_BC4_TYPELESS: - case DXGI_FORMAT_BC4_UNORM: - case DXGI_FORMAT_BC2_TYPELESS: - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: - case DXGI_FORMAT_BC3_TYPELESS: - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: - case DXGI_FORMAT_BC5_SNORM: - case DXGI_FORMAT_BC5_TYPELESS: - case DXGI_FORMAT_BC5_UNORM: - case DXGI_FORMAT_BC6H_SF16: - case DXGI_FORMAT_BC6H_TYPELESS: - case DXGI_FORMAT_BC6H_UF16: - case DXGI_FORMAT_BC7_TYPELESS: - case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: - return ComputePixelSizeBits(format) * 16; - default: - UNREACHABLE(); - return 0; - } -} - -bool IsCompressed(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_BC1_TYPELESS: - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: - case DXGI_FORMAT_BC4_SNORM: - case DXGI_FORMAT_BC4_TYPELESS: - case DXGI_FORMAT_BC4_UNORM: - case DXGI_FORMAT_BC2_TYPELESS: - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: - case DXGI_FORMAT_BC3_TYPELESS: - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: - case DXGI_FORMAT_BC5_SNORM: - case DXGI_FORMAT_BC5_TYPELESS: - case DXGI_FORMAT_BC5_UNORM: - case DXGI_FORMAT_BC6H_SF16: - case DXGI_FORMAT_BC6H_TYPELESS: - case DXGI_FORMAT_BC6H_UF16: - case DXGI_FORMAT_BC7_TYPELESS: - case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: - return true; - case DXGI_FORMAT_UNKNOWN: - UNREACHABLE(); - return false; - default: - return false; - } -} - -unsigned int GetTextureFormatDimensionAlignment(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_BC1_TYPELESS: - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: - case DXGI_FORMAT_BC4_SNORM: - case DXGI_FORMAT_BC4_TYPELESS: - case DXGI_FORMAT_BC4_UNORM: - case DXGI_FORMAT_BC2_TYPELESS: - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: - case DXGI_FORMAT_BC3_TYPELESS: - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: - case DXGI_FORMAT_BC5_SNORM: - case DXGI_FORMAT_BC5_TYPELESS: - case DXGI_FORMAT_BC5_UNORM: - case DXGI_FORMAT_BC6H_SF16: - case DXGI_FORMAT_BC6H_TYPELESS: - case DXGI_FORMAT_BC6H_UF16: - case DXGI_FORMAT_BC7_TYPELESS: - case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: - return 4; - case DXGI_FORMAT_UNKNOWN: - UNREACHABLE(); - return 1; - default: - return 1; - } -} - -bool IsDepthStencilFormat(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: - case DXGI_FORMAT_D32_FLOAT: - case DXGI_FORMAT_D24_UNORM_S8_UINT: - case DXGI_FORMAT_D16_UNORM: - return true; - default: - return false; - } -} - -DXGI_FORMAT GetDepthTextureFormat(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return DXGI_FORMAT_R32G8X24_TYPELESS; - case DXGI_FORMAT_D32_FLOAT: return DXGI_FORMAT_R32_TYPELESS; - case DXGI_FORMAT_D24_UNORM_S8_UINT: return DXGI_FORMAT_R24G8_TYPELESS; - case DXGI_FORMAT_D16_UNORM: return DXGI_FORMAT_R16_TYPELESS; - default: UNREACHABLE(); return DXGI_FORMAT_UNKNOWN; - } -} - -DXGI_FORMAT GetDepthShaderResourceFormat(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; - case DXGI_FORMAT_D32_FLOAT: return DXGI_FORMAT_R32_UINT; - case DXGI_FORMAT_D24_UNORM_S8_UINT: return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; - case DXGI_FORMAT_D16_UNORM: return DXGI_FORMAT_R16_UNORM; - default: UNREACHABLE(); return DXGI_FORMAT_UNKNOWN; - } -} - -HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) -{ -#if defined(_DEBUG) - return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name); -#else - return S_OK; -#endif -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/renderer11_utils.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/renderer11_utils.h deleted file mode 100644 index 70ad4fea2b..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/renderer11_utils.h +++ /dev/null @@ -1,95 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// renderer11_utils.h: Conversion functions and other utility routines -// specific to the D3D11 renderer. - -#ifndef LIBGLESV2_RENDERER_RENDERER11_UTILS_H -#define LIBGLESV2_RENDERER_RENDERER11_UTILS_H - -#include "libGLESv2/angletypes.h" - -namespace gl_d3d11 -{ - -D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha); -D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp); -UINT8 ConvertColorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha); - -D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode); - -D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison); -D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled); -UINT8 ConvertStencilMask(GLuint stencilmask); -D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp); - -D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy); -D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap); -FLOAT ConvertMinLOD(GLenum minFilter, unsigned int lodOffset); -FLOAT ConvertMaxLOD(GLenum minFilter, unsigned int lodOffset); - -DXGI_FORMAT ConvertRenderbufferFormat(GLenum format); -DXGI_FORMAT ConvertTextureFormat(GLenum format, D3D_FEATURE_LEVEL featureLevel); -} - -namespace d3d11_gl -{ - -GLenum ConvertBackBufferFormat(DXGI_FORMAT format); -GLenum ConvertDepthStencilFormat(DXGI_FORMAT format); -GLenum ConvertRenderbufferFormat(DXGI_FORMAT format); -GLenum ConvertTextureInternalFormat(DXGI_FORMAT format); - -} - -namespace d3d11 -{ - -struct PositionTexCoordVertex -{ - float x, y; - float u, v; -}; -void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v); - -struct PositionDepthColorVertex -{ - float x, y, z; - float r, g, b, a; -}; -void SetPositionDepthColorVertex(PositionDepthColorVertex* vertex, float x, float y, float z, - const gl::Color &color); - -size_t ComputePixelSizeBits(DXGI_FORMAT format); -size_t ComputeBlockSizeBits(DXGI_FORMAT format); - -bool IsCompressed(DXGI_FORMAT format); -unsigned int GetTextureFormatDimensionAlignment(DXGI_FORMAT format); - -bool IsDepthStencilFormat(DXGI_FORMAT format); -DXGI_FORMAT GetDepthTextureFormat(DXGI_FORMAT format); -DXGI_FORMAT GetDepthShaderResourceFormat(DXGI_FORMAT format); - -HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name); - -inline bool isDeviceLostError(HRESULT errorCode) -{ - switch (errorCode) - { - case DXGI_ERROR_DEVICE_HUNG: - case DXGI_ERROR_DEVICE_REMOVED: - case DXGI_ERROR_DEVICE_RESET: - case DXGI_ERROR_DRIVER_INTERNAL_ERROR: - case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: - return true; - default: - return false; - } -} - -} - -#endif // LIBGLESV2_RENDERER_RENDERER11_UTILS_H diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/shaders/Clear11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/shaders/Clear11.hlsl deleted file mode 100644 index cb132dc99c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/shaders/Clear11.hlsl +++ /dev/null @@ -1,42 +0,0 @@ -void VS_Clear( in float3 inPosition : POSITION, in float4 inColor : COLOR, - out float4 outPosition : SV_POSITION, out float4 outColor : COLOR) -{ - outPosition = float4(inPosition, 1.0f); - outColor = inColor; -} - -// Assume we are in SM4+, which has 8 color outputs -struct PS_OutputMultiple -{ - float4 color0 : SV_TARGET0; - float4 color1 : SV_TARGET1; - float4 color2 : SV_TARGET2; - float4 color3 : SV_TARGET3; -#ifdef SM4 - float4 color4 : SV_TARGET4; - float4 color5 : SV_TARGET5; - float4 color6 : SV_TARGET6; - float4 color7 : SV_TARGET7; -#endif -}; - -PS_OutputMultiple PS_ClearMultiple(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) -{ - PS_OutputMultiple outColor; - outColor.color0 = inColor; - outColor.color1 = inColor; - outColor.color2 = inColor; - outColor.color3 = inColor; -#ifdef SM4 - outColor.color4 = inColor; - outColor.color5 = inColor; - outColor.color6 = inColor; - outColor.color7 = inColor; -#endif - return outColor; -} - -float4 PS_ClearSingle(in float4 inPosition : SV_Position, in float4 inColor : COLOR) : SV_Target0 -{ - return inColor; -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/shaders/Passthrough11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/shaders/Passthrough11.hlsl deleted file mode 100644 index 43b7801efc..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/shaders/Passthrough11.hlsl +++ /dev/null @@ -1,29 +0,0 @@ -Texture2D Texture : register(t0); -SamplerState Sampler : register(s0); - -void VS_Passthrough( in float2 inPosition : POSITION, in float2 inTexCoord : TEXCOORD0, - out float4 outPosition : SV_POSITION, out float2 outTexCoord : TEXCOORD0) -{ - outPosition = float4(inPosition, 0.0f, 1.0f); - outTexCoord = inTexCoord; -} - -float4 PS_PassthroughRGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return Texture.Sample(Sampler, inTexCoord).rgba; -} - -float4 PS_PassthroughRGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return float4(Texture.Sample(Sampler, inTexCoord).rgb, 1.0f); -} - -float4 PS_PassthroughLum(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return float4(Texture.Sample(Sampler, inTexCoord).rrr, 1.0f); -} - -float4 PS_PassthroughLumAlpha(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return Texture.Sample(Sampler, inTexCoord).rrra; -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/BufferStorage9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/BufferStorage9.cpp deleted file mode 100644 index 9fdc1246f1..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/BufferStorage9.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// BufferStorage9.cpp Defines the BufferStorage9 class. - -#include "libGLESv2/renderer/d3d9/BufferStorage9.h" -#include "common/debug.h" - -namespace rx -{ - -BufferStorage9::BufferStorage9() -{ - mMemory = NULL; - mAllocatedSize = 0; - mSize = 0; -} - -BufferStorage9::~BufferStorage9() -{ - delete[] mMemory; -} - -BufferStorage9 *BufferStorage9::makeBufferStorage9(BufferStorage *bufferStorage) -{ - ASSERT(HAS_DYNAMIC_TYPE(BufferStorage9*, bufferStorage)); - return static_cast<BufferStorage9*>(bufferStorage); -} - -void *BufferStorage9::getData() -{ - return mMemory; -} - -void BufferStorage9::setData(const void* data, unsigned int size, unsigned int offset) -{ - if (!mMemory || offset + size > mAllocatedSize) - { - unsigned int newAllocatedSize = offset + size; - void *newMemory = new char[newAllocatedSize]; - - if (offset > 0 && mMemory && mAllocatedSize > 0) - { - memcpy(newMemory, mMemory, std::min(offset, mAllocatedSize)); - } - - delete[] mMemory; - mMemory = newMemory; - mAllocatedSize = newAllocatedSize; - } - - mSize = std::max(mSize, offset + size); - if (data) - { - memcpy(reinterpret_cast<char*>(mMemory) + offset, data, size); - } -} - -void BufferStorage9::clear() -{ - mSize = 0; -} - -unsigned int BufferStorage9::getSize() const -{ - return mSize; -} - -bool BufferStorage9::supportsDirectBinding() const -{ - return false; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/BufferStorage9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/BufferStorage9.h deleted file mode 100644 index 3e803969bc..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/BufferStorage9.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// BufferStorage9.h Defines the BufferStorage9 class. - -#ifndef LIBGLESV2_RENDERER_BUFFERSTORAGE9_H_ -#define LIBGLESV2_RENDERER_BUFFERSTORAGE9_H_ - -#include "libGLESv2/renderer/BufferStorage.h" - -namespace rx -{ - -class BufferStorage9 : public BufferStorage -{ - public: - BufferStorage9(); - virtual ~BufferStorage9(); - - static BufferStorage9 *makeBufferStorage9(BufferStorage *bufferStorage); - - virtual void *getData(); - virtual void setData(const void* data, unsigned int size, unsigned int offset); - virtual void clear(); - virtual unsigned int getSize() const; - virtual bool supportsDirectBinding() const; - - private: - DISALLOW_COPY_AND_ASSIGN(BufferStorage9); - - void *mMemory; - unsigned int mAllocatedSize; - - unsigned int mSize; -}; - -} - -#endif // LIBGLESV2_RENDERER_BUFFERSTORAGE9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Fence9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Fence9.cpp deleted file mode 100644 index 639c37b4e4..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/Fence9.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// Fence9.cpp: Defines the rx::Fence9 class. - -#include "libGLESv2/renderer/d3d9/Fence9.h" -#include "libGLESv2/main.h" -#include "libGLESv2/renderer/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d9/Renderer9.h" - -namespace rx -{ - -Fence9::Fence9(rx::Renderer9 *renderer) -{ - mRenderer = renderer; - mQuery = NULL; -} - -Fence9::~Fence9() -{ - if (mQuery) - { - mRenderer->freeEventQuery(mQuery); - mQuery = NULL; - } -} - -GLboolean Fence9::isFence() -{ - // GL_NV_fence spec: - // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence. - return mQuery != NULL; -} - -void Fence9::setFence(GLenum condition) -{ - if (!mQuery) - { - mQuery = mRenderer->allocateEventQuery(); - if (!mQuery) - { - return gl::error(GL_OUT_OF_MEMORY); - } - } - - HRESULT result = mQuery->Issue(D3DISSUE_END); - ASSERT(SUCCEEDED(result)); - - setCondition(condition); - setStatus(GL_FALSE); -} - -GLboolean Fence9::testFence() -{ - if (mQuery == NULL) - { - return gl::error(GL_INVALID_OPERATION, GL_TRUE); - } - - HRESULT result = mQuery->GetData(NULL, 0, D3DGETDATA_FLUSH); - - if (d3d9::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - return gl::error(GL_OUT_OF_MEMORY, GL_TRUE); - } - - ASSERT(result == S_OK || result == S_FALSE); - setStatus(result == S_OK); - return getStatus(); -} - -void Fence9::finishFence() -{ - if (mQuery == NULL) - { - return gl::error(GL_INVALID_OPERATION); - } - - while (!testFence()) - { - Sleep(0); - } -} - -void Fence9::getFenceiv(GLenum pname, GLint *params) -{ - if (mQuery == NULL) - { - return gl::error(GL_INVALID_OPERATION); - } - - switch (pname) - { - case GL_FENCE_STATUS_NV: - { - // GL_NV_fence spec: - // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV - // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence. - if (getStatus()) - { - params[0] = GL_TRUE; - return; - } - - HRESULT result = mQuery->GetData(NULL, 0, 0); - - if (d3d9::isDeviceLostError(result)) - { - params[0] = GL_TRUE; - mRenderer->notifyDeviceLost(); - return gl::error(GL_OUT_OF_MEMORY); - } - - ASSERT(result == S_OK || result == S_FALSE); - setStatus(result == S_OK); - params[0] = getStatus(); - - break; - } - case GL_FENCE_CONDITION_NV: - params[0] = getCondition(); - break; - default: - return gl::error(GL_INVALID_ENUM); - break; - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/RenderTarget9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/RenderTarget9.cpp deleted file mode 100644 index 090431db99..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/RenderTarget9.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// RenderTarget9.cpp: Implements a D3D9-specific wrapper for IDirect3DSurface9 -// pointers retained by renderbuffers. - -#include "libGLESv2/renderer/d3d9/RenderTarget9.h" -#include "libGLESv2/renderer/d3d9/Renderer9.h" - -#include "libGLESv2/renderer/d3d9/renderer9_utils.h" -#include "libGLESv2/main.h" - -namespace rx -{ - -RenderTarget9::RenderTarget9(Renderer *renderer, IDirect3DSurface9 *surface) -{ - mRenderer = Renderer9::makeRenderer9(renderer); - mRenderTarget = surface; - - if (mRenderTarget) - { - D3DSURFACE_DESC description; - mRenderTarget->GetDesc(&description); - - mWidth = description.Width; - mHeight = description.Height; - - mInternalFormat = d3d9_gl::GetEquivalentFormat(description.Format); - mActualFormat = d3d9_gl::GetEquivalentFormat(description.Format); - mSamples = d3d9_gl::GetSamplesFromMultisampleType(description.MultiSampleType); - } -} - -RenderTarget9::RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum format, GLsizei samples) -{ - mRenderer = Renderer9::makeRenderer9(renderer); - mRenderTarget = NULL; - - D3DFORMAT requestedFormat = gl_d3d9::ConvertRenderbufferFormat(format); - int supportedSamples = mRenderer->getNearestSupportedSamples(requestedFormat, samples); - - if (supportedSamples == -1) - { - gl::error(GL_OUT_OF_MEMORY); - - return; - } - - HRESULT result = D3DERR_INVALIDCALL; - - if (width > 0 && height > 0) - { - if (requestedFormat == D3DFMT_D24S8) - { - result = mRenderer->getDevice()->CreateDepthStencilSurface(width, height, requestedFormat, - gl_d3d9::GetMultisampleTypeFromSamples(supportedSamples), - 0, FALSE, &mRenderTarget, NULL); - } - else - { - result = mRenderer->getDevice()->CreateRenderTarget(width, height, requestedFormat, - gl_d3d9::GetMultisampleTypeFromSamples(supportedSamples), - 0, FALSE, &mRenderTarget, NULL); - } - - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) - { - gl::error(GL_OUT_OF_MEMORY); - - return; - } - - ASSERT(SUCCEEDED(result)); - } - - mWidth = width; - mHeight = height; - mInternalFormat = format; - mSamples = supportedSamples; - mActualFormat = d3d9_gl::GetEquivalentFormat(requestedFormat); -} - -RenderTarget9::~RenderTarget9() -{ - if (mRenderTarget) - { - mRenderTarget->Release(); - } -} - -RenderTarget9 *RenderTarget9::makeRenderTarget9(RenderTarget *target) -{ - ASSERT(HAS_DYNAMIC_TYPE(rx::RenderTarget9*, target)); - return static_cast<rx::RenderTarget9*>(target); -} - -IDirect3DSurface9 *RenderTarget9::getSurface() -{ - // Caller is responsible for releasing the returned surface reference. - if (mRenderTarget) - { - mRenderTarget->AddRef(); - } - - return mRenderTarget; -} - -}
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/VertexBuffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/VertexBuffer9.cpp deleted file mode 100644 index 57f5bcd256..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/VertexBuffer9.cpp +++ /dev/null @@ -1,530 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// VertexBuffer9.cpp: Defines the D3D9 VertexBuffer implementation. - -#include "libGLESv2/renderer/d3d9/VertexBuffer9.h" -#include "libGLESv2/renderer/d3d9/vertexconversion.h" -#include "libGLESv2/renderer/BufferStorage.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/renderer/d3d9/Renderer9.h" - -#include "libGLESv2/Buffer.h" - -namespace rx -{ - -bool VertexBuffer9::mTranslationsInitialized = false; -VertexBuffer9::FormatConverter VertexBuffer9::mFormatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; - -VertexBuffer9::VertexBuffer9(rx::Renderer9 *const renderer) : mRenderer(renderer) -{ - mVertexBuffer = NULL; - mBufferSize = 0; - mDynamicUsage = false; - - if (!mTranslationsInitialized) - { - initializeTranslations(renderer->getCapsDeclTypes()); - mTranslationsInitialized = true; - } -} - -VertexBuffer9::~VertexBuffer9() -{ - if (mVertexBuffer) - { - mVertexBuffer->Release(); - mVertexBuffer = NULL; - } -} - -bool VertexBuffer9::initialize(unsigned int size, bool dynamicUsage) -{ - if (mVertexBuffer) - { - mVertexBuffer->Release(); - mVertexBuffer = NULL; - } - - updateSerial(); - - if (size > 0) - { - DWORD flags = D3DUSAGE_WRITEONLY; - if (dynamicUsage) - { - flags |= D3DUSAGE_DYNAMIC; - } - - HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer); - - if (FAILED(result)) - { - ERR("Out of memory allocating a vertex buffer of size %lu.", size); - return false; - } - } - - mBufferSize = size; - mDynamicUsage = dynamicUsage; - return true; -} - -VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer) -{ - ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer)); - return static_cast<VertexBuffer9*>(vertexBuffer); -} - -bool VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, - GLsizei instances, unsigned int offset) -{ - if (mVertexBuffer) - { - gl::Buffer *buffer = attrib.mBoundBuffer.get(); - - int inputStride = attrib.stride(); - int elementSize = attrib.typeSize(); - const FormatConverter &converter = formatConverter(attrib); - - DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; - - void *mapPtr = NULL; - - unsigned int mapSize; - if (!spaceRequired(attrib, count, instances, &mapSize)) - { - return false; - } - - HRESULT result = mVertexBuffer->Lock(offset, mapSize, &mapPtr, lockFlags); - - if (FAILED(result)) - { - ERR("Lock failed with error 0x%08x", result); - return false; - } - - const char *input = NULL; - if (buffer) - { - BufferStorage *storage = buffer->getStorage(); - input = static_cast<const char*>(storage->getData()) + static_cast<int>(attrib.mOffset); - } - else - { - input = static_cast<const char*>(attrib.mPointer); - } - - if (instances == 0 || attrib.mDivisor == 0) - { - input += inputStride * start; - } - - if (converter.identity && inputStride == elementSize) - { - memcpy(mapPtr, input, count * inputStride); - } - else - { - converter.convertArray(input, inputStride, count, mapPtr); - } - - mVertexBuffer->Unlock(); - - return true; - } - else - { - ERR("Vertex buffer not initialized."); - return false; - } -} - -bool VertexBuffer9::storeRawData(const void* data, unsigned int size, unsigned int offset) -{ - if (mVertexBuffer) - { - DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; - - void *mapPtr = NULL; - HRESULT result = mVertexBuffer->Lock(offset, size, &mapPtr, lockFlags); - - if (FAILED(result)) - { - ERR("Lock failed with error 0x%08x", result); - return false; - } - - memcpy(mapPtr, data, size); - - mVertexBuffer->Unlock(); - - return true; - } - else - { - ERR("Vertex buffer not initialized."); - return false; - } -} - -bool VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, - unsigned int *outSpaceRequired) const -{ - return spaceRequired(attrib, count, instances, outSpaceRequired); -} - -bool VertexBuffer9::requiresConversion(const gl::VertexAttribute &attrib) const -{ - return !formatConverter(attrib).identity; -} - -unsigned int VertexBuffer9::getVertexSize(const gl::VertexAttribute &attrib) const -{ - unsigned int spaceRequired; - return getSpaceRequired(attrib, 1, 0, &spaceRequired) ? spaceRequired : 0; -} - -D3DDECLTYPE VertexBuffer9::getDeclType(const gl::VertexAttribute &attrib) const -{ - return formatConverter(attrib).d3dDeclType; -} - -unsigned int VertexBuffer9::getBufferSize() const -{ - return mBufferSize; -} - -bool VertexBuffer9::setBufferSize(unsigned int size) -{ - if (size > mBufferSize) - { - return initialize(size, mDynamicUsage); - } - else - { - return true; - } -} - -bool VertexBuffer9::discard() -{ - if (mVertexBuffer) - { - void *dummy; - HRESULT result; - - result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); - if (FAILED(result)) - { - ERR("Discard lock failed with error 0x%08x", result); - return false; - } - - result = mVertexBuffer->Unlock(); - if (FAILED(result)) - { - ERR("Discard unlock failed with error 0x%08x", result); - return false; - } - - return true; - } - else - { - ERR("Vertex buffer not initialized."); - return false; - } -} - -IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const -{ - return mVertexBuffer; -} - -// Mapping from OpenGL-ES vertex attrib type to D3D decl type: -// -// BYTE SHORT (Cast) -// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm) -// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast) -// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize) -// SHORT SHORT (Identity) -// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize) -// UNSIGNED_SHORT FLOAT (Cast) -// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize) -// FIXED (not in WebGL) FLOAT (FixedToFloat) -// FLOAT FLOAT (Identity) - -// GLToCType maps from GL type (as GLenum) to the C typedef. -template <GLenum GLType> struct GLToCType { }; - -template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; }; -template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; }; -template <> struct GLToCType<GL_SHORT> { typedef GLshort type; }; -template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; }; -template <> struct GLToCType<GL_FIXED> { typedef GLuint type; }; -template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; }; - -// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.) -enum D3DVertexType -{ - D3DVT_FLOAT, - D3DVT_SHORT, - D3DVT_SHORT_NORM, - D3DVT_UBYTE, - D3DVT_UBYTE_NORM, - D3DVT_USHORT_NORM -}; - -// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type. -template <unsigned int D3DType> struct D3DToCType { }; - -template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; }; -template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; }; -template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; }; -template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; }; -template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; }; -template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; }; - -// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size. -template <unsigned int type, int size> struct WidenRule { }; - -template <int size> struct WidenRule<D3DVT_FLOAT, size> : NoWiden<size> { }; -template <int size> struct WidenRule<D3DVT_SHORT, size> : WidenToEven<size> { }; -template <int size> struct WidenRule<D3DVT_SHORT_NORM, size> : WidenToEven<size> { }; -template <int size> struct WidenRule<D3DVT_UBYTE, size> : WidenToFour<size> { }; -template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size> : WidenToFour<size> { }; -template <int size> struct WidenRule<D3DVT_USHORT_NORM, size> : WidenToEven<size> { }; - -// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination. -template <unsigned int d3dtype, int size> struct VertexTypeFlags { }; - -template <unsigned int _capflag, unsigned int _declflag> -struct VertexTypeFlagsHelper -{ - enum { capflag = _capflag }; - enum { declflag = _declflag }; -}; - -template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { }; -template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { }; -template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { }; -template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { }; -template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { }; -template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { }; -template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { }; -template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { }; -template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { }; -template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { }; -template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { }; -template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { }; - - -// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums). -template <GLenum GLtype, bool normalized> struct VertexTypeMapping { }; - -template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred> -struct VertexTypeMappingBase -{ - enum { preferred = Preferred }; - enum { fallback = Fallback }; -}; - -template <> struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Cast -template <> struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Normalize -template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { }; // Identity, Cast -template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { }; // Identity, Normalize -template <> struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Identity -template <> struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize -template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Cast -template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize -template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // FixedToFloat -template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Identity - - -// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat). -// The conversion rules themselves are defined in vertexconversion.h. - -// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping). -template <GLenum fromType, bool normalized, unsigned int toType> -struct ConversionRule : Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type> { }; - -// All conversions from normalized types to float use the Normalize operator. -template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : Normalize<typename GLToCType<fromType>::type> { }; - -// Use a full specialization for this so that it preferentially matches ahead of the generic normalize-to-float rules. -template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { }; -template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { }; - -// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1) -// whether it is normalized or not. -template <class T, bool normalized> struct DefaultVertexValuesStage2 { }; - -template <class T> struct DefaultVertexValuesStage2<T, true> : NormalizedDefaultValues<T> { }; -template <class T> struct DefaultVertexValuesStage2<T, false> : SimpleDefaultValues<T> { }; - -// Work out the default value rule for a D3D type (expressed as the C type) and -template <class T, bool normalized> struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized> { }; -template <bool normalized> struct DefaultVertexValues<float, normalized> : SimpleDefaultValues<float> { }; - -// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion. -// The fallback conversion produces an output that all D3D9 devices must support. -template <class T> struct UsePreferred { enum { type = T::preferred }; }; -template <class T> struct UseFallback { enum { type = T::fallback }; }; - -// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion, -// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag -// and the D3DDECLTYPE member needed for the vertex declaration in declflag. -template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule> -struct Converter - : VertexDataConverter<typename GLToCType<fromType>::type, - WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>, - ConversionRule<fromType, - normalized, - PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>, - DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > > -{ -private: - enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type }; - enum { d3dsize = WidenRule<d3dtype, size>::finalWidth }; - -public: - enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag }; - enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag }; -}; - -// Initialize a TranslationInfo -#define TRANSLATION(type, norm, size, preferred) \ - { \ - Converter<type, norm, size, preferred>::identity, \ - Converter<type, norm, size, preferred>::finalSize, \ - Converter<type, norm, size, preferred>::convertArray, \ - static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag) \ - } - -#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \ - { \ - Converter<type, norm, size, UsePreferred>::capflag, \ - TRANSLATION(type, norm, size, UsePreferred), \ - TRANSLATION(type, norm, size, UseFallback) \ - } - -#define TRANSLATIONS_FOR_TYPE(type) \ - { \ - { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ - { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \ - } - -#define TRANSLATIONS_FOR_TYPE_NO_NORM(type) \ - { \ - { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ - { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ - } - -const VertexBuffer9::TranslationDescription VertexBuffer9::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1] -{ - TRANSLATIONS_FOR_TYPE(GL_BYTE), - TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE), - TRANSLATIONS_FOR_TYPE(GL_SHORT), - TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT), - TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED), - TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT) -}; - -void VertexBuffer9::initializeTranslations(DWORD declTypes) -{ - for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++) - { - for (unsigned int j = 0; j < 2; j++) - { - for (unsigned int k = 0; k < 4; k++) - { - if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0) - { - mFormatConverters[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion; - } - else - { - mFormatConverters[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion; - } - } - } - } -} - -unsigned int VertexBuffer9::typeIndex(GLenum type) -{ - switch (type) - { - case GL_BYTE: return 0; - case GL_UNSIGNED_BYTE: return 1; - case GL_SHORT: return 2; - case GL_UNSIGNED_SHORT: return 3; - case GL_FIXED: return 4; - case GL_FLOAT: return 5; - - default: UNREACHABLE(); return 5; - } -} - -const VertexBuffer9::FormatConverter &VertexBuffer9::formatConverter(const gl::VertexAttribute &attribute) -{ - return mFormatConverters[typeIndex(attribute.mType)][attribute.mNormalized][attribute.mSize - 1]; -} - -bool VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, - unsigned int *outSpaceRequired) -{ - unsigned int elementSize = formatConverter(attrib).outputElementSize; - - if (attrib.mArrayEnabled) - { - unsigned int elementCount = 0; - if (instances == 0 || attrib.mDivisor == 0) - { - elementCount = count; - } - else - { - if (static_cast<unsigned int>(instances) < std::numeric_limits<unsigned int>::max() - (attrib.mDivisor - 1)) - { - // Round up - elementCount = (static_cast<unsigned int>(instances) + (attrib.mDivisor - 1)) / attrib.mDivisor; - } - else - { - elementCount = static_cast<unsigned int>(instances) / attrib.mDivisor; - } - } - - if (elementSize <= std::numeric_limits<unsigned int>::max() / elementCount) - { - if (outSpaceRequired) - { - *outSpaceRequired = elementSize * elementCount; - } - return true; - } - else - { - return false; - } - } - else - { - const unsigned int elementSize = 4; - if (outSpaceRequired) - { - *outSpaceRequired = elementSize * 4; - } - return true; - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/VertexBuffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/VertexBuffer9.h deleted file mode 100644 index 2f88117bda..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/VertexBuffer9.h +++ /dev/null @@ -1,91 +0,0 @@ -// -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// VertexBuffer9.h: Defines the D3D9 VertexBuffer implementation. - -#ifndef LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ -#define LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ - -#include "libGLESv2/renderer/VertexBuffer.h" - -namespace rx -{ -class Renderer9; - -class VertexBuffer9 : public VertexBuffer -{ - public: - explicit VertexBuffer9(rx::Renderer9 *const renderer); - virtual ~VertexBuffer9(); - - virtual bool initialize(unsigned int size, bool dynamicUsage); - - static VertexBuffer9 *makeVertexBuffer9(VertexBuffer *vertexBuffer); - - virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances, - unsigned int offset); - virtual bool storeRawData(const void* data, unsigned int size, unsigned int offset); - - virtual bool getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const; - - virtual bool requiresConversion(const gl::VertexAttribute &attrib) const; - - unsigned int getVertexSize(const gl::VertexAttribute &attrib) const; - D3DDECLTYPE getDeclType(const gl::VertexAttribute &attrib) const; - - virtual unsigned int getBufferSize() const; - virtual bool setBufferSize(unsigned int size); - virtual bool discard(); - - IDirect3DVertexBuffer9 *getBuffer() const; - - private: - DISALLOW_COPY_AND_ASSIGN(VertexBuffer9); - - rx::Renderer9 *const mRenderer; - - IDirect3DVertexBuffer9 *mVertexBuffer; - unsigned int mBufferSize; - bool mDynamicUsage; - - // Attribute format conversion - enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 }; - - struct FormatConverter - { - bool identity; - std::size_t outputElementSize; - void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out); - D3DDECLTYPE d3dDeclType; - }; - - static bool mTranslationsInitialized; - static void initializeTranslations(DWORD declTypes); - - // [GL types as enumerated by typeIndex()][normalized][size - 1] - static FormatConverter mFormatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; - - struct TranslationDescription - { - DWORD capsFlag; - FormatConverter preferredConversion; - FormatConverter fallbackConversion; - }; - - // This table is used to generate mFormatConverters. - // [GL types as enumerated by typeIndex()][normalized][size - 1] - static const TranslationDescription mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; - - static unsigned int typeIndex(GLenum type); - static const FormatConverter &formatConverter(const gl::VertexAttribute &attribute); - - static bool spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, - unsigned int *outSpaceRequired); -}; - -} - -#endif // LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/renderer9_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/renderer9_utils.cpp deleted file mode 100644 index b7f2ffb1d9..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/renderer9_utils.cpp +++ /dev/null @@ -1,500 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// renderer9_utils.cpp: Conversion functions and other utility routines -// specific to the D3D9 renderer. - -#include "libGLESv2/renderer/d3d9/renderer9_utils.h" -#include "libGLESv2/mathutil.h" -#include "libGLESv2/Context.h" - -#include "common/debug.h" - -namespace gl_d3d9 -{ - -D3DCMPFUNC ConvertComparison(GLenum comparison) -{ - D3DCMPFUNC d3dComp = D3DCMP_ALWAYS; - switch (comparison) - { - case GL_NEVER: d3dComp = D3DCMP_NEVER; break; - case GL_ALWAYS: d3dComp = D3DCMP_ALWAYS; break; - case GL_LESS: d3dComp = D3DCMP_LESS; break; - case GL_LEQUAL: d3dComp = D3DCMP_LESSEQUAL; break; - case GL_EQUAL: d3dComp = D3DCMP_EQUAL; break; - case GL_GREATER: d3dComp = D3DCMP_GREATER; break; - case GL_GEQUAL: d3dComp = D3DCMP_GREATEREQUAL; break; - case GL_NOTEQUAL: d3dComp = D3DCMP_NOTEQUAL; break; - default: UNREACHABLE(); - } - - return d3dComp; -} - -D3DCOLOR ConvertColor(gl::Color color) -{ - return D3DCOLOR_RGBA(gl::unorm<8>(color.red), - gl::unorm<8>(color.green), - gl::unorm<8>(color.blue), - gl::unorm<8>(color.alpha)); -} - -D3DBLEND ConvertBlendFunc(GLenum blend) -{ - D3DBLEND d3dBlend = D3DBLEND_ZERO; - - switch (blend) - { - case GL_ZERO: d3dBlend = D3DBLEND_ZERO; break; - case GL_ONE: d3dBlend = D3DBLEND_ONE; break; - case GL_SRC_COLOR: d3dBlend = D3DBLEND_SRCCOLOR; break; - case GL_ONE_MINUS_SRC_COLOR: d3dBlend = D3DBLEND_INVSRCCOLOR; break; - case GL_DST_COLOR: d3dBlend = D3DBLEND_DESTCOLOR; break; - case GL_ONE_MINUS_DST_COLOR: d3dBlend = D3DBLEND_INVDESTCOLOR; break; - case GL_SRC_ALPHA: d3dBlend = D3DBLEND_SRCALPHA; break; - case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3DBLEND_INVSRCALPHA; break; - case GL_DST_ALPHA: d3dBlend = D3DBLEND_DESTALPHA; break; - case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3DBLEND_INVDESTALPHA; break; - case GL_CONSTANT_COLOR: d3dBlend = D3DBLEND_BLENDFACTOR; break; - case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; - case GL_CONSTANT_ALPHA: d3dBlend = D3DBLEND_BLENDFACTOR; break; - case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; - case GL_SRC_ALPHA_SATURATE: d3dBlend = D3DBLEND_SRCALPHASAT; break; - default: UNREACHABLE(); - } - - return d3dBlend; -} - -D3DBLENDOP ConvertBlendOp(GLenum blendOp) -{ - D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD; - - switch (blendOp) - { - case GL_FUNC_ADD: d3dBlendOp = D3DBLENDOP_ADD; break; - case GL_FUNC_SUBTRACT: d3dBlendOp = D3DBLENDOP_SUBTRACT; break; - case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3DBLENDOP_REVSUBTRACT; break; - default: UNREACHABLE(); - } - - return d3dBlendOp; -} - -D3DSTENCILOP ConvertStencilOp(GLenum stencilOp) -{ - D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP; - - switch (stencilOp) - { - case GL_ZERO: d3dStencilOp = D3DSTENCILOP_ZERO; break; - case GL_KEEP: d3dStencilOp = D3DSTENCILOP_KEEP; break; - case GL_REPLACE: d3dStencilOp = D3DSTENCILOP_REPLACE; break; - case GL_INCR: d3dStencilOp = D3DSTENCILOP_INCRSAT; break; - case GL_DECR: d3dStencilOp = D3DSTENCILOP_DECRSAT; break; - case GL_INVERT: d3dStencilOp = D3DSTENCILOP_INVERT; break; - case GL_INCR_WRAP: d3dStencilOp = D3DSTENCILOP_INCR; break; - case GL_DECR_WRAP: d3dStencilOp = D3DSTENCILOP_DECR; break; - default: UNREACHABLE(); - } - - return d3dStencilOp; -} - -D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap) -{ - D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP; - - switch (wrap) - { - case GL_REPEAT: d3dWrap = D3DTADDRESS_WRAP; break; - case GL_CLAMP_TO_EDGE: d3dWrap = D3DTADDRESS_CLAMP; break; - case GL_MIRRORED_REPEAT: d3dWrap = D3DTADDRESS_MIRROR; break; - default: UNREACHABLE(); - } - - return d3dWrap; -} - -D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace) -{ - D3DCULL cull = D3DCULL_CCW; - switch (cullFace) - { - case GL_FRONT: - cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); - break; - case GL_BACK: - cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); - break; - case GL_FRONT_AND_BACK: - cull = D3DCULL_NONE; // culling will be handled during draw - break; - default: UNREACHABLE(); - } - - return cull; -} - -D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace) -{ - D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X; - - switch (cubeFace) - { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - face = D3DCUBEMAP_FACE_POSITIVE_X; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - face = D3DCUBEMAP_FACE_NEGATIVE_X; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - face = D3DCUBEMAP_FACE_POSITIVE_Y; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - face = D3DCUBEMAP_FACE_NEGATIVE_Y; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - face = D3DCUBEMAP_FACE_POSITIVE_Z; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - face = D3DCUBEMAP_FACE_NEGATIVE_Z; - break; - default: UNREACHABLE(); - } - - return face; -} - -DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha) -{ - return (red ? D3DCOLORWRITEENABLE_RED : 0) | - (green ? D3DCOLORWRITEENABLE_GREEN : 0) | - (blue ? D3DCOLORWRITEENABLE_BLUE : 0) | - (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0); -} - -D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy) -{ - if (maxAnisotropy > 1.0f) - { - return D3DTEXF_ANISOTROPIC; - } - - D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT; - switch (magFilter) - { - case GL_NEAREST: d3dMagFilter = D3DTEXF_POINT; break; - case GL_LINEAR: d3dMagFilter = D3DTEXF_LINEAR; break; - default: UNREACHABLE(); - } - - return d3dMagFilter; -} - -void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy) -{ - switch (minFilter) - { - case GL_NEAREST: - *d3dMinFilter = D3DTEXF_POINT; - *d3dMipFilter = D3DTEXF_NONE; - break; - case GL_LINEAR: - *d3dMinFilter = D3DTEXF_LINEAR; - *d3dMipFilter = D3DTEXF_NONE; - break; - case GL_NEAREST_MIPMAP_NEAREST: - *d3dMinFilter = D3DTEXF_POINT; - *d3dMipFilter = D3DTEXF_POINT; - break; - case GL_LINEAR_MIPMAP_NEAREST: - *d3dMinFilter = D3DTEXF_LINEAR; - *d3dMipFilter = D3DTEXF_POINT; - break; - case GL_NEAREST_MIPMAP_LINEAR: - *d3dMinFilter = D3DTEXF_POINT; - *d3dMipFilter = D3DTEXF_LINEAR; - break; - case GL_LINEAR_MIPMAP_LINEAR: - *d3dMinFilter = D3DTEXF_LINEAR; - *d3dMipFilter = D3DTEXF_LINEAR; - break; - default: - *d3dMinFilter = D3DTEXF_POINT; - *d3dMipFilter = D3DTEXF_NONE; - UNREACHABLE(); - } - - if (maxAnisotropy > 1.0f) - { - *d3dMinFilter = D3DTEXF_ANISOTROPIC; - } -} - -D3DFORMAT ConvertRenderbufferFormat(GLenum format) -{ - switch (format) - { - case GL_NONE: return D3DFMT_NULL; - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGBA8_OES: return D3DFMT_A8R8G8B8; - case GL_RGB565: return D3DFMT_R5G6B5; - case GL_RGB8_OES: return D3DFMT_X8R8G8B8; - case GL_DEPTH_COMPONENT16: - case GL_STENCIL_INDEX8: - case GL_DEPTH24_STENCIL8_OES: return D3DFMT_D24S8; - default: UNREACHABLE(); return D3DFMT_A8R8G8B8; - } -} - -D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples) -{ - if (samples <= 1) - return D3DMULTISAMPLE_NONE; - else - return (D3DMULTISAMPLE_TYPE)samples; -} - -} - -namespace d3d9_gl -{ - -unsigned int GetStencilSize(D3DFORMAT stencilFormat) -{ - if (stencilFormat == D3DFMT_INTZ) - { - return 8; - } - switch(stencilFormat) - { - case D3DFMT_D24FS8: - case D3DFMT_D24S8: - return 8; - case D3DFMT_D24X4S4: - return 4; - case D3DFMT_D15S1: - return 1; - case D3DFMT_D16_LOCKABLE: - case D3DFMT_D32: - case D3DFMT_D24X8: - case D3DFMT_D32F_LOCKABLE: - case D3DFMT_D16: - return 0; - //case D3DFMT_D32_LOCKABLE: return 0; // DirectX 9Ex only - //case D3DFMT_S8_LOCKABLE: return 8; // DirectX 9Ex only - default: - return 0; - } -} - -unsigned int GetAlphaSize(D3DFORMAT colorFormat) -{ - switch (colorFormat) - { - case D3DFMT_A16B16G16R16F: - return 16; - case D3DFMT_A32B32G32R32F: - return 32; - case D3DFMT_A2R10G10B10: - return 2; - case D3DFMT_A8R8G8B8: - return 8; - case D3DFMT_A1R5G5B5: - return 1; - case D3DFMT_X8R8G8B8: - case D3DFMT_R5G6B5: - return 0; - default: - return 0; - } -} - -GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type) -{ - if (type == D3DMULTISAMPLE_NONMASKABLE) - return 0; - else - return type; -} - -bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) -{ - switch (d3dformat) - { - case D3DFMT_L8: - return (format == GL_LUMINANCE); - case D3DFMT_A8L8: - return (format == GL_LUMINANCE_ALPHA); - case D3DFMT_DXT1: - return (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT); - case D3DFMT_DXT3: - return (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); - case D3DFMT_DXT5: - return (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); - case D3DFMT_A8R8G8B8: - case D3DFMT_A16B16G16R16F: - case D3DFMT_A32B32G32R32F: - return (format == GL_RGBA || format == GL_BGRA_EXT); - case D3DFMT_X8R8G8B8: - return (format == GL_RGB); - default: - if (d3dformat == D3DFMT_INTZ && gl::IsDepthTexture(format)) - return true; - return false; - } -} - -GLenum ConvertBackBufferFormat(D3DFORMAT format) -{ - switch (format) - { - case D3DFMT_A4R4G4B4: return GL_RGBA4; - case D3DFMT_A8R8G8B8: return GL_RGBA8_OES; - case D3DFMT_A1R5G5B5: return GL_RGB5_A1; - case D3DFMT_R5G6B5: return GL_RGB565; - case D3DFMT_X8R8G8B8: return GL_RGB8_OES; - default: - UNREACHABLE(); - } - - return GL_RGBA4; -} - -GLenum ConvertDepthStencilFormat(D3DFORMAT format) -{ - if (format == D3DFMT_INTZ) - { - return GL_DEPTH24_STENCIL8_OES; - } - switch (format) - { - case D3DFMT_D16: - case D3DFMT_D24X8: - return GL_DEPTH_COMPONENT16; - case D3DFMT_D24S8: - return GL_DEPTH24_STENCIL8_OES; - case D3DFMT_UNKNOWN: - return GL_NONE; - default: - UNREACHABLE(); - } - - return GL_DEPTH24_STENCIL8_OES; -} - -GLenum ConvertRenderTargetFormat(D3DFORMAT format) -{ - if (format == D3DFMT_INTZ) - { - return GL_DEPTH24_STENCIL8_OES; - } - - switch (format) - { - case D3DFMT_A4R4G4B4: return GL_RGBA4; - case D3DFMT_A8R8G8B8: return GL_RGBA8_OES; - case D3DFMT_A1R5G5B5: return GL_RGB5_A1; - case D3DFMT_R5G6B5: return GL_RGB565; - case D3DFMT_X8R8G8B8: return GL_RGB8_OES; - case D3DFMT_D16: - case D3DFMT_D24X8: - return GL_DEPTH_COMPONENT16; - case D3DFMT_D24S8: - return GL_DEPTH24_STENCIL8_OES; - case D3DFMT_UNKNOWN: - return GL_NONE; - default: - UNREACHABLE(); - } - - return GL_RGBA4; -} - -GLenum GetEquivalentFormat(D3DFORMAT format) -{ - if (format == D3DFMT_INTZ) - return GL_DEPTH24_STENCIL8_OES; - if (format == D3DFMT_NULL) - return GL_NONE; - - switch (format) - { - case D3DFMT_A4R4G4B4: return GL_RGBA4; - case D3DFMT_A8R8G8B8: return GL_RGBA8_OES; - case D3DFMT_A1R5G5B5: return GL_RGB5_A1; - case D3DFMT_R5G6B5: return GL_RGB565; - case D3DFMT_X8R8G8B8: return GL_RGB8_OES; - case D3DFMT_D16: return GL_DEPTH_COMPONENT16; - case D3DFMT_D24S8: return GL_DEPTH24_STENCIL8_OES; - case D3DFMT_UNKNOWN: return GL_NONE; - case D3DFMT_DXT1: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - case D3DFMT_DXT3: return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; - case D3DFMT_DXT5: return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; - case D3DFMT_A32B32G32R32F: return GL_RGBA32F_EXT; - case D3DFMT_A16B16G16R16F: return GL_RGBA16F_EXT; - case D3DFMT_L8: return GL_LUMINANCE8_EXT; - case D3DFMT_A8L8: return GL_LUMINANCE8_ALPHA8_EXT; - default: UNREACHABLE(); - return GL_NONE; - } -} - -} - -namespace d3d9 -{ - -bool IsCompressedFormat(D3DFORMAT surfaceFormat) -{ - switch(surfaceFormat) - { - case D3DFMT_DXT1: - case D3DFMT_DXT2: - case D3DFMT_DXT3: - case D3DFMT_DXT4: - case D3DFMT_DXT5: - return true; - default: - return false; - } -} - -size_t ComputeRowSize(D3DFORMAT format, unsigned int width) -{ - if (format == D3DFMT_INTZ) - { - return 4 * width; - } - switch (format) - { - case D3DFMT_L8: - return 1 * width; - case D3DFMT_A8L8: - return 2 * width; - case D3DFMT_X8R8G8B8: - case D3DFMT_A8R8G8B8: - return 4 * width; - case D3DFMT_A16B16G16R16F: - return 8 * width; - case D3DFMT_A32B32G32R32F: - return 16 * width; - case D3DFMT_DXT1: - return 8 * ((width + 3) / 4); - case D3DFMT_DXT3: - case D3DFMT_DXT5: - return 16 * ((width + 3) / 4); - default: - UNREACHABLE(); - return 0; - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/shaders/Blit.ps b/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/shaders/Blit.ps deleted file mode 100644 index dcb3bd0e76..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/shaders/Blit.ps +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -sampler2D tex : s0; - -uniform float4 mode : c0; - -// Passthrough Pixel Shader -// Outputs texture 0 sampled at texcoord 0. -float4 passthroughps(float4 texcoord : TEXCOORD0) : COLOR -{ - return tex2D(tex, texcoord.xy); -}; - -// Luminance Conversion Pixel Shader -// Outputs sample(tex0, tc0).rrra. -// For LA output (pass A) set C0.X = 1, C0.Y = 0. -// For L output (A = 1) set C0.X = 0, C0.Y = 1. -float4 luminanceps(float4 texcoord : TEXCOORD0) : COLOR -{ - float4 tmp = tex2D(tex, texcoord.xy); - tmp.w = tmp.w * mode.x + mode.y; - return tmp.xxxw; -}; - -// RGB/A Component Mask Pixel Shader -// Outputs sample(tex0, tc0) with options to force RGB = 0 and/or A = 1. -// To force RGB = 0, set C0.X = 0, otherwise C0.X = 1. -// To force A = 1, set C0.Z = 0, C0.W = 1, otherwise C0.Z = 1, C0.W = 0. -float4 componentmaskps(float4 texcoord : TEXCOORD0) : COLOR -{ - float4 tmp = tex2D(tex, texcoord.xy); - tmp.xyz = tmp.xyz * mode.x; - tmp.w = tmp.w * mode.z + mode.w; - return tmp; -}; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.h b/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.h index 8e1973605b..a57b00d444 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -10,194 +10,19 @@ #ifndef LIBGLESV2_RENDERER_GENERATEMIP_H_ #define LIBGLESV2_RENDERER_GENERATEMIP_H_ -#include "libGLESv2/mathutil.h" +#include "libGLESv2/renderer/imageformats.h" +#include "libGLESv2/angletypes.h" namespace rx { -struct L8 -{ - unsigned char L; - - static void average(L8 *dst, const L8 *src1, const L8 *src2) - { - dst->L = ((src1->L ^ src2->L) >> 1) + (src1->L & src2->L); - } -}; - -typedef L8 R8; // R8 type is functionally equivalent for mip purposes -typedef L8 A8; // A8 type is functionally equivalent for mip purposes - -struct A8L8 -{ - unsigned char L; - unsigned char A; - - static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2) - { - *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); - } -}; - -typedef A8L8 R8G8; // R8G8 type is functionally equivalent for mip purposes - -struct A8R8G8B8 -{ - unsigned char B; - unsigned char G; - unsigned char R; - unsigned char A; - - static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2) - { - *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); - } -}; - -typedef A8R8G8B8 R8G8B8A8; // R8G8B8A8 type is functionally equivalent for mip purposes - -struct A16B16G16R16F -{ - unsigned short R; - unsigned short G; - unsigned short B; - unsigned short A; - - static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2) - { - dst->R = gl::float32ToFloat16((gl::float16ToFloat32(src1->R) + gl::float16ToFloat32(src2->R)) * 0.5f); - dst->G = gl::float32ToFloat16((gl::float16ToFloat32(src1->G) + gl::float16ToFloat32(src2->G)) * 0.5f); - dst->B = gl::float32ToFloat16((gl::float16ToFloat32(src1->B) + gl::float16ToFloat32(src2->B)) * 0.5f); - dst->A = gl::float32ToFloat16((gl::float16ToFloat32(src1->A) + gl::float16ToFloat32(src2->A)) * 0.5f); - } -}; - -struct R16F -{ - unsigned short R; - - static void average(R16F *dst, const R16F *src1, const R16F *src2) - { - dst->R = gl::float32ToFloat16((gl::float16ToFloat32(src1->R) + gl::float16ToFloat32(src2->R)) * 0.5f); - } -}; - -struct R16G16F -{ - unsigned short R; - unsigned short G; - - static void average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2) - { - dst->R = gl::float32ToFloat16((gl::float16ToFloat32(src1->R) + gl::float16ToFloat32(src2->R)) * 0.5f); - dst->G = gl::float32ToFloat16((gl::float16ToFloat32(src1->G) + gl::float16ToFloat32(src2->G)) * 0.5f); - } -}; - -struct A32B32G32R32F -{ - float R; - float G; - float B; - float A; - - static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2) - { - dst->R = (src1->R + src2->R) * 0.5f; - dst->G = (src1->G + src2->G) * 0.5f; - dst->B = (src1->B + src2->B) * 0.5f; - dst->A = (src1->A + src2->A) * 0.5f; - } -}; - -struct R32F -{ - float R; - - static void average(R32F *dst, const R32F *src1, const R32F *src2) - { - dst->R = (src1->R + src2->R) * 0.5f; - } -}; - -struct R32G32F -{ - float R; - float G; - - static void average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2) - { - dst->R = (src1->R + src2->R) * 0.5f; - dst->G = (src1->G + src2->G) * 0.5f; - } -}; - -struct R32G32B32F -{ - float R; - float G; - float B; - - static void average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *src2) - { - dst->R = (src1->R + src2->R) * 0.5f; - dst->G = (src1->G + src2->G) * 0.5f; - dst->B = (src1->B + src2->B) * 0.5f; - } -}; template <typename T> -static void GenerateMip(unsigned int sourceWidth, unsigned int sourceHeight, - const unsigned char *sourceData, int sourcePitch, - unsigned char *destData, int destPitch) -{ - unsigned int mipWidth = std::max(1U, sourceWidth >> 1); - unsigned int mipHeight = std::max(1U, sourceHeight >> 1); - - if (sourceHeight == 1) - { - ASSERT(sourceWidth != 1); - - const T *src = (const T*)sourceData; - T *dst = (T*)destData; - - for (unsigned int x = 0; x < mipWidth; x++) - { - T::average(&dst[x], &src[x * 2], &src[x * 2 + 1]); - } - } - else if (sourceWidth == 1) - { - ASSERT(sourceHeight != 1); +inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); - for (unsigned int y = 0; y < mipHeight; y++) - { - const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch); - const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch); - T *dst = (T*)(destData + y * destPitch); - - T::average(dst, src0, src1); - } - } - else - { - for (unsigned int y = 0; y < mipHeight; y++) - { - const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch); - const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch); - T *dst = (T*)(destData + y * destPitch); - - for (unsigned int x = 0; x < mipWidth; x++) - { - T tmp0; - T tmp1; - - T::average(&tmp0, &src0[x * 2], &src0[x * 2 + 1]); - T::average(&tmp1, &src1[x * 2], &src1[x * 2 + 1]); - T::average(&dst[x], &tmp0, &tmp1); - } - } - } -} } +#include "generatemip.inl" + #endif // LIBGLESV2_RENDERER_GENERATEMIP_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.inl b/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.inl new file mode 100644 index 0000000000..6788a42f03 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.inl @@ -0,0 +1,266 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// generatemip.inl: Defines the GenerateMip function, templated on the format +// type of the image for which mip levels are being generated. + +#include "common/mathutil.h" + +namespace rx +{ + +namespace priv +{ + +template <typename T> +static inline T *GetPixel(uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast<T*>(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); +} + +template <typename T> +static inline const T *GetPixel(const uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast<const T*>(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); +} + +template <typename T> +static void GenerateMip_Y(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth == 1); + + for (size_t y = 0; y < destHeight; y++) + { + const T *src0 = GetPixel<T>(sourceData, 0, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, 0, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, 0, y, 0, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template <typename T> +static void GenerateMip_X(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth == 1); + + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel<T>(sourceData, x * 2, 0, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, x * 2 + 1, 0, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, x, 0, 0, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template <typename T> +static void GenerateMip_Z(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + const T *src0 = GetPixel<T>(sourceData, 0, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, 0, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, 0, 0, z, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template <typename T> +static void GenerateMip_XY(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth == 1); + + for (size_t y = 0; y < destHeight; y++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel<T>(sourceData, x * 2, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, x * 2, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel<T>(sourceData, x * 2 + 1, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel<T>(sourceData, x * 2 + 1, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, x, y, 0, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template <typename T> +static void GenerateMip_YZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t y = 0; y < destHeight; y++) + { + const T *src0 = GetPixel<T>(sourceData, 0, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, 0, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel<T>(sourceData, 0, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel<T>(sourceData, 0, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, 0, y, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template <typename T> +static void GenerateMip_XZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel<T>(sourceData, x * 2, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, x * 2, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel<T>(sourceData, x * 2 + 1, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel<T>(sourceData, x * 2 + 1, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, x, 0, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template <typename T> +static void GenerateMip_XYZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t y = 0; y < destHeight; y++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel<T>(sourceData, x * 2, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel<T>(sourceData, x * 2, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel<T>(sourceData, x * 2, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel<T>(sourceData, x * 2, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src4 = GetPixel<T>(sourceData, x * 2 + 1, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src5 = GetPixel<T>(sourceData, x * 2 + 1, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src6 = GetPixel<T>(sourceData, x * 2 + 1, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src7 = GetPixel<T>(sourceData, x * 2 + 1, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel<T>(destData, x, y, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(&tmp2, src4, src5); + T::average(&tmp3, src6, src7); + + T::average(&tmp4, &tmp0, &tmp1); + T::average(&tmp5, &tmp2, &tmp3); + + T::average(dst, &tmp4, &tmp5); + } + } + } +} + + +typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); + +template <typename T> +static MipGenerationFunction GetMipGenerationFunction(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth) +{ + uint8_t index = ((sourceWidth > 1) ? 1 : 0) | + ((sourceHeight > 1) ? 2 : 0) | + ((sourceDepth > 1) ? 4 : 0); + + switch (index) + { + case 0: return NULL; + case 1: return GenerateMip_X<T>; // W x 1 x 1 + case 2: return GenerateMip_Y<T>; // 1 x H x 1 + case 3: return GenerateMip_XY<T>; // W x H x 1 + case 4: return GenerateMip_Z<T>; // 1 x 1 x D + case 5: return GenerateMip_XZ<T>; // W x 1 x D + case 6: return GenerateMip_YZ<T>; // 1 x H x D + case 7: return GenerateMip_XYZ<T>; // W x H x D + } + + UNREACHABLE(); + return NULL; +} + +} + +template <typename T> +inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + size_t mipWidth = std::max<size_t>(1, sourceWidth >> 1); + size_t mipHeight = std::max<size_t>(1, sourceHeight >> 1); + size_t mipDepth = std::max<size_t>(1, sourceDepth >> 1); + + priv::MipGenerationFunction generationFunction = priv::GetMipGenerationFunction<T>(sourceWidth, sourceHeight, sourceDepth); + ASSERT(generationFunction != NULL); + + generationFunction(sourceWidth, sourceHeight, sourceDepth, sourceData, sourceRowPitch, sourceDepthPitch, + mipWidth, mipHeight, mipDepth, destData, destRowPitch, destDepthPitch); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/imageformats.h b/src/3rdparty/angle/src/libGLESv2/renderer/imageformats.h new file mode 100644 index 0000000000..2140a9ee72 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/imageformats.h @@ -0,0 +1,2029 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// imageformats.h: Defines image format types with functions for mip generation +// and copying. + +#ifndef LIBGLESV2_RENDERER_IMAGEFORMATS_H_ +#define LIBGLESV2_RENDERER_IMAGEFORMATS_H_ + +#include "common/mathutil.h" + +namespace rx +{ + +// Several structures share functionality for reading, writing or mipmapping but the layout +// must match the texture format which the structure represents. If collapsing or typedefing +// structs in this header, make sure the functionality and memory layout is exactly the same. + +struct L8 +{ + unsigned char L; + + static void readColor(gl::ColorF *dst, const L8 *src) + { + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = 1.0f; + } + + static void writeColor(L8 *dst, const gl::ColorF *src) + { + dst->L = gl::floatToNormalized<unsigned char>((src->red + src->green + src->blue) / 3.0f); + } + + static void average(L8 *dst, const L8 *src1, const L8 *src2) + { + dst->L = gl::average(src1->L, src2->L); + } +}; + +struct R8 +{ + unsigned char R; + + static void readColor(gl::ColorF *dst, const R8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R8 *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned char>(src->red); + } + + static void writeColor(R8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned char>(src->red); + } + + static void average(R8 *dst, const R8 *src1, const R8 *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct A8 +{ + unsigned char A; + + static void readColor(gl::ColorF *dst, const A8 *src) + { + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void writeColor(A8 *dst, const gl::ColorF *src) + { + dst->A = gl::floatToNormalized<unsigned char>(src->alpha); + } + + static void average(A8 *dst, const A8 *src1, const A8 *src2) + { + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct L8A8 +{ + unsigned char L; + unsigned char A; + + static void readColor(gl::ColorF *dst, const L8A8 *src) + { + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void writeColor(L8A8 *dst, const gl::ColorF *src) + { + dst->L = gl::floatToNormalized<unsigned char>((src->red + src->green + src->blue) / 3.0f); + dst->A = gl::floatToNormalized<unsigned char>(src->alpha); + } + + static void average(L8A8 *dst, const L8A8 *src1, const L8A8 *src2) + { + *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); + } +}; + +struct A8L8 +{ + unsigned char A; + unsigned char L; + + static void readColor(gl::ColorF *dst, const A8L8 *src) + { + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void writeColor(A8L8 *dst, const gl::ColorF *src) + { + dst->L = gl::floatToNormalized<unsigned char>((src->red + src->green + src->blue) / 3.0f); + dst->A = gl::floatToNormalized<unsigned char>(src->alpha); + } + + static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2) + { + *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); + } +}; + +struct R8G8 +{ + unsigned char R; + unsigned char G; + + static void readColor(gl::ColorF *dst, const R8G8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R8G8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8G8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned char>(src->red); + dst->G = gl::floatToNormalized<unsigned char>(src->green); + } + + static void writeColor(R8G8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned char>(src->red); + dst->G = static_cast<unsigned char>(src->green); + } + + static void average(R8G8 *dst, const R8G8 *src1, const R8G8 *src2) + { + *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); + } +}; + +struct R8G8B8 +{ + unsigned char R; + unsigned char G; + unsigned char B; + + static void readColor(gl::ColorF *dst, const R8G8B8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R8G8B8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->G; + dst->alpha = 1; + } + + static void writeColor(R8G8B8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned char>(src->red); + dst->G = gl::floatToNormalized<unsigned char>(src->green); + dst->B = gl::floatToNormalized<unsigned char>(src->blue); + } + + static void writeColor(R8G8B8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned char>(src->red); + dst->G = static_cast<unsigned char>(src->green); + dst->B = static_cast<unsigned char>(src->blue); + } + + static void average(R8G8B8 *dst, const R8G8B8 *src1, const R8G8B8 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct B8G8R8 +{ + unsigned char B; + unsigned char G; + unsigned char R; + + static void readColor(gl::ColorF *dst, const B8G8R8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const B8G8R8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->G; + dst->alpha = 1; + } + + static void writeColor(B8G8R8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned char>(src->red); + dst->G = gl::floatToNormalized<unsigned char>(src->green); + dst->B = gl::floatToNormalized<unsigned char>(src->blue); + } + + static void writeColor(B8G8R8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned char>(src->red); + dst->G = static_cast<unsigned char>(src->green); + dst->B = static_cast<unsigned char>(src->blue); + } + + static void average(B8G8R8 *dst, const B8G8R8 *src1, const B8G8R8 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R5G6B5 +{ + unsigned short RGB; + + static void readColor(gl::ColorF *dst, const R5G6B5 *src) + { + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->RGB)); + dst->green = gl::normalizedToFloat<6>(gl::getShiftedData<6, 5>(src->RGB)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGB)); + dst->alpha = 1.0f; + } + + static void writeColor(R5G6B5 *dst, const gl::ColorF *src) + { + dst->RGB = gl::shiftData<5, 11>(gl::floatToNormalized<5, unsigned short>(src->red)) | + gl::shiftData<6, 5>(gl::floatToNormalized<6, unsigned short>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)); + } + + static void average(R5G6B5 *dst, const R5G6B5 *src1, const R5G6B5 *src2) + { + dst->RGB = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->RGB), gl::getShiftedData<5, 11>(src2->RGB))) | + gl::shiftData<6, 5>(gl::average(gl::getShiftedData<6, 5>(src1->RGB), gl::getShiftedData<6, 5>(src2->RGB))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGB), gl::getShiftedData<5, 0>(src2->RGB))); + } +}; + +struct A8R8G8B8 +{ + unsigned char A; + unsigned char R; + unsigned char G; + unsigned char B; + + static void readColor(gl::ColorF *dst, const A8R8G8B8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const A8R8G8B8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(A8R8G8B8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned char>(src->red); + dst->G = gl::floatToNormalized<unsigned char>(src->green); + dst->B = gl::floatToNormalized<unsigned char>(src->blue); + dst->A = gl::floatToNormalized<unsigned char>(src->alpha); + } + + static void writeColor(A8R8G8B8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned char>(src->red); + dst->G = static_cast<unsigned char>(src->green); + dst->B = static_cast<unsigned char>(src->blue); + dst->A = static_cast<unsigned char>(src->alpha); + } + + static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + } +}; + +struct R8G8B8A8 +{ + unsigned char R; + unsigned char G; + unsigned char B; + unsigned char A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const R8G8B8A8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R8G8B8A8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned char>(src->red); + dst->G = gl::floatToNormalized<unsigned char>(src->green); + dst->B = gl::floatToNormalized<unsigned char>(src->blue); + dst->A = gl::floatToNormalized<unsigned char>(src->alpha); + } + + static void writeColor(R8G8B8A8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned char>(src->red); + dst->G = static_cast<unsigned char>(src->green); + dst->B = static_cast<unsigned char>(src->blue); + dst->A = static_cast<unsigned char>(src->alpha); + } + + static void average(R8G8B8A8 *dst, const R8G8B8A8 *src1, const R8G8B8A8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + } +}; + +struct B8G8R8A8 +{ + unsigned char B; + unsigned char G; + unsigned char R; + unsigned char A; + + static void readColor(gl::ColorF *dst, const B8G8R8A8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const B8G8R8A8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(B8G8R8A8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned char>(src->red); + dst->G = gl::floatToNormalized<unsigned char>(src->green); + dst->B = gl::floatToNormalized<unsigned char>(src->blue); + dst->A = gl::floatToNormalized<unsigned char>(src->alpha); + } + + static void writeColor(B8G8R8A8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned char>(src->red); + dst->G = static_cast<unsigned char>(src->green); + dst->B = static_cast<unsigned char>(src->blue); + dst->A = static_cast<unsigned char>(src->alpha); + } + + static void average(B8G8R8A8 *dst, const B8G8R8A8 *src1, const B8G8R8A8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + } +}; + +struct B8G8R8X8 +{ + unsigned char B; + unsigned char G; + unsigned char R; + unsigned char X; + + static void readColor(gl::ColorF *dst, const B8G8R8X8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const B8G8R8X8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(B8G8R8X8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned char>(src->red); + dst->G = gl::floatToNormalized<unsigned char>(src->green); + dst->B = gl::floatToNormalized<unsigned char>(src->blue); + dst->X = 255; + } + + static void writeColor(B8G8R8X8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned char>(src->red); + dst->G = static_cast<unsigned char>(src->green); + dst->B = static_cast<unsigned char>(src->blue); + dst->X = 255; + } + + static void average(B8G8R8X8 *dst, const B8G8R8X8 *src1, const B8G8R8X8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + dst->X = 255; + } +}; + +struct B5G5R5A1 +{ + unsigned short BGRA; + + static void readColor(gl::ColorF *dst, const B5G5R5A1 *src) + { + dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->BGRA)); + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->BGRA)); + dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->BGRA)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->BGRA)); + } + + static void writeColor(B5G5R5A1 *dst, const gl::ColorF *src) + { + dst->BGRA = gl::shiftData<1, 15>(gl::floatToNormalized<1, unsigned short>(src->alpha)) | + gl::shiftData<5, 10>(gl::floatToNormalized<5, unsigned short>(src->red)) | + gl::shiftData<5, 5>(gl::floatToNormalized<5, unsigned short>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)); + } + + static void average(B5G5R5A1 *dst, const B5G5R5A1 *src1, const B5G5R5A1 *src2) + { + dst->BGRA = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->BGRA), gl::getShiftedData<1, 15>(src2->BGRA))) | + gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->BGRA), gl::getShiftedData<5, 10>(src2->BGRA))) | + gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->BGRA), gl::getShiftedData<5, 5>(src2->BGRA))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->BGRA), gl::getShiftedData<5, 0>(src2->BGRA))); + } +}; + +struct R5G5B5A1 +{ + unsigned short RGBA; + + static void readColor(gl::ColorF *dst, const R5G5B5A1 *src) + { + dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->RGBA)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->RGBA)); + dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->RGBA)); + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGBA)); + } + + static void writeColor(R5G5B5A1 *dst, const gl::ColorF *src) + { + dst->RGBA = gl::shiftData<1, 15>(gl::floatToNormalized<1, unsigned short>(src->alpha)) | + gl::shiftData<5, 10>(gl::floatToNormalized<5, unsigned short>(src->blue)) | + gl::shiftData<5, 5>(gl::floatToNormalized<5, unsigned short>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->red)); + } + + static void average(R5G5B5A1 *dst, const R5G5B5A1 *src1, const R5G5B5A1 *src2) + { + dst->RGBA = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->RGBA), gl::getShiftedData<1, 15>(src2->RGBA))) | + gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->RGBA), gl::getShiftedData<5, 10>(src2->RGBA))) | + gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->RGBA), gl::getShiftedData<5, 5>(src2->RGBA))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGBA), gl::getShiftedData<5, 0>(src2->RGBA))); + } +}; + +struct R4G4B4A4 +{ + unsigned char R : 4; + unsigned char G : 4; + unsigned char B : 4; + unsigned char A : 4; + + static void readColor(gl::ColorF *dst, const R4G4B4A4 *src) + { + dst->red = gl::normalizedToFloat<4>(src->R); + dst->green = gl::normalizedToFloat<4>(src->G); + dst->blue = gl::normalizedToFloat<4>(src->B); + dst->alpha = gl::normalizedToFloat<4>(src->A); + } + + static void writeColor(R4G4B4A4 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<4, unsigned char>(src->red); + dst->G = gl::floatToNormalized<4, unsigned char>(src->green); + dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); + dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); + } + + static void average(R4G4B4A4 *dst, const R4G4B4A4 *src1, const R4G4B4A4 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct A4R4G4B4 +{ + unsigned char A : 4; + unsigned char R : 4; + unsigned char G : 4; + unsigned char B : 4; + + static void readColor(gl::ColorF *dst, const A4R4G4B4 *src) + { + dst->red = gl::normalizedToFloat<4>(src->R); + dst->green = gl::normalizedToFloat<4>(src->G); + dst->blue = gl::normalizedToFloat<4>(src->B); + dst->alpha = gl::normalizedToFloat<4>(src->A); + } + + static void writeColor(A4R4G4B4 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<4, unsigned char>(src->red); + dst->G = gl::floatToNormalized<4, unsigned char>(src->green); + dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); + dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); + } + + static void average(A4R4G4B4 *dst, const A4R4G4B4 *src1, const A4R4G4B4 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct B4G4R4A4 +{ + unsigned char B : 4; + unsigned char G : 4; + unsigned char R : 4; + unsigned char A : 4; + + static void readColor(gl::ColorF *dst, const B4G4R4A4 *src) + { + dst->red = gl::normalizedToFloat<4>(src->R); + dst->green = gl::normalizedToFloat<4>(src->G); + dst->blue = gl::normalizedToFloat<4>(src->B); + dst->alpha = gl::normalizedToFloat<4>(src->A); + } + + static void writeColor(B4G4R4A4 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<4, unsigned char>(src->red); + dst->G = gl::floatToNormalized<4, unsigned char>(src->green); + dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); + dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); + } + + static void average(B4G4R4A4 *dst, const B4G4R4A4 *src1, const B4G4R4A4 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R16 +{ + unsigned short R; + + static void readColor(gl::ColorF *dst, const R16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R16 *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned short>(src->red); + } + + static void writeColor(R16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned short>(src->red); + } + + static void average(R16 *dst, const R16 *src1, const R16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R16G16 +{ + unsigned short R; + unsigned short G; + + static void readColor(gl::ColorF *dst, const R16G16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R16G16 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16G16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned short>(src->red); + dst->G = gl::floatToNormalized<unsigned short>(src->green); + } + + static void writeColor(R16G16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned short>(src->red); + dst->G = static_cast<unsigned short>(src->green); + } + + static void average(R16G16 *dst, const R16G16 *src1, const R16G16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R16G16B16 +{ + unsigned short R; + unsigned short G; + unsigned short B; + + static void readColor(gl::ColorF *dst, const R16G16B16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R16G16B16 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R16G16B16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned short>(src->red); + dst->G = gl::floatToNormalized<unsigned short>(src->green); + dst->B = gl::floatToNormalized<unsigned short>(src->blue); + } + + static void writeColor(R16G16B16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned short>(src->red); + dst->G = static_cast<unsigned short>(src->green); + dst->B = static_cast<unsigned short>(src->blue); + } + + static void average(R16G16B16 *dst, const R16G16B16 *src1, const R16G16B16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R16G16B16A16 +{ + unsigned short R; + unsigned short G; + unsigned short B; + unsigned short A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const R16G16B16A16 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R16G16B16A16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned short>(src->red); + dst->G = gl::floatToNormalized<unsigned short>(src->green); + dst->B = gl::floatToNormalized<unsigned short>(src->blue); + dst->A = gl::floatToNormalized<unsigned short>(src->alpha); + } + + static void writeColor(R16G16B16A16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned short>(src->red); + dst->G = static_cast<unsigned short>(src->green); + dst->B = static_cast<unsigned short>(src->blue); + dst->A = static_cast<unsigned short>(src->alpha); + } + + static void average(R16G16B16A16 *dst, const R16G16B16A16 *src1, const R16G16B16A16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32 +{ + unsigned int R; + + static void readColor(gl::ColorF *dst, const R32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R32 *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned int>(src->red); + } + + static void writeColor(R32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned int>(src->red); + } + + static void average(R32 *dst, const R32 *src1, const R32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R32G32 +{ + unsigned int R; + unsigned int G; + + static void readColor(gl::ColorF *dst, const R32G32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R32G32 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32G32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned int>(src->red); + dst->G = gl::floatToNormalized<unsigned int>(src->green); + } + + static void writeColor(R32G32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned int>(src->red); + dst->G = static_cast<unsigned int>(src->green); + } + + static void average(R32G32 *dst, const R32G32 *src1, const R32G32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R32G32B32 +{ + unsigned int R; + unsigned int G; + unsigned int B; + + static void readColor(gl::ColorF *dst, const R32G32B32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R32G32B32 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R32G32B32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned int>(src->red); + dst->G = gl::floatToNormalized<unsigned int>(src->green); + dst->B = gl::floatToNormalized<unsigned int>(src->blue); + } + + static void writeColor(R32G32B32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned int>(src->red); + dst->G = static_cast<unsigned int>(src->green); + dst->B = static_cast<unsigned int>(src->blue); + } + + static void average(R32G32B32 *dst, const R32G32B32 *src1, const R32G32B32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R32G32B32A32 +{ + unsigned int R; + unsigned int G; + unsigned int B; + unsigned int A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const R32G32B32A32 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R32G32B32A32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<unsigned int>(src->red); + dst->G = gl::floatToNormalized<unsigned int>(src->green); + dst->B = gl::floatToNormalized<unsigned int>(src->blue); + dst->A = gl::floatToNormalized<unsigned int>(src->alpha); + } + + static void writeColor(R32G32B32A32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned int>(src->red); + dst->G = static_cast<unsigned int>(src->green); + dst->B = static_cast<unsigned int>(src->blue); + dst->A = static_cast<unsigned int>(src->alpha); + } + + static void average(R32G32B32A32 *dst, const R32G32B32A32 *src1, const R32G32B32A32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R8S +{ + char R; + + static void readColor(gl::ColorF *dst, const R8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R8S *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<char>(src->red); + } + + static void writeColor(R8S *dst, const gl::ColorI *src) + { + dst->R = static_cast<char>(src->red); + } + + static void average(R8S *dst, const R8S *src1, const R8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R8G8S +{ + char R; + char G; + + static void readColor(gl::ColorF *dst, const R8G8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R8G8S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8G8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<char>(src->red); + dst->G = gl::floatToNormalized<char>(src->green); + } + + static void writeColor(R8G8S *dst, const gl::ColorI *src) + { + dst->R = static_cast<char>(src->red); + dst->G = static_cast<char>(src->green); + } + + static void average(R8G8S *dst, const R8G8S *src1, const R8G8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R8G8B8S +{ + char R; + char G; + char B; + + static void readColor(gl::ColorF *dst, const R8G8B8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R8G8B8S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R8G8B8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<char>(src->red); + dst->G = gl::floatToNormalized<char>(src->green); + dst->B = gl::floatToNormalized<char>(src->blue); + } + + static void writeColor(R8G8B8S *dst, const gl::ColorI *src) + { + dst->R = static_cast<char>(src->red); + dst->G = static_cast<char>(src->green); + dst->B = static_cast<char>(src->blue); + } + + static void average(R8G8B8S *dst, const R8G8B8S *src1, const R8G8B8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R8G8B8A8S +{ + char R; + char G; + char B; + char A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorI *dst, const R8G8B8A8S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R8G8B8A8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<char>(src->red); + dst->G = gl::floatToNormalized<char>(src->green); + dst->B = gl::floatToNormalized<char>(src->blue); + dst->A = gl::floatToNormalized<char>(src->alpha); + } + + static void writeColor(R8G8B8A8S *dst, const gl::ColorI *src) + { + dst->R = static_cast<char>(src->red); + dst->G = static_cast<char>(src->green); + dst->B = static_cast<char>(src->blue); + dst->A = static_cast<char>(src->alpha); + } + + static void average(R8G8B8A8S *dst, const R8G8B8A8S *src1, const R8G8B8A8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R16S +{ + short R; + + static void readColor(gl::ColorF *dst, const R16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R16S *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<short>(src->red); + } + + static void writeColor(R16S *dst, const gl::ColorI *src) + { + dst->R = static_cast<short>(src->red); + } + + static void average(R16S *dst, const R16S *src1, const R16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R16G16S +{ + short R; + short G; + + static void readColor(gl::ColorF *dst, const R16G16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R16G16S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16G16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<short>(src->red); + dst->G = gl::floatToNormalized<short>(src->green); + } + + static void writeColor(R16G16S *dst, const gl::ColorI *src) + { + dst->R = static_cast<short>(src->red); + dst->G = static_cast<short>(src->green); + } + + static void average(R16G16S *dst, const R16G16S *src1, const R16G16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R16G16B16S +{ + short R; + short G; + short B; + + static void readColor(gl::ColorF *dst, const R16G16B16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R16G16B16S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R16G16B16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<short>(src->red); + dst->G = gl::floatToNormalized<short>(src->green); + dst->B = gl::floatToNormalized<short>(src->blue); + } + + static void writeColor(R16G16B16S *dst, const gl::ColorI *src) + { + dst->R = static_cast<short>(src->red); + dst->G = static_cast<short>(src->green); + dst->B = static_cast<short>(src->blue); + } + + static void average(R16G16B16S *dst, const R16G16B16S *src1, const R16G16B16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R16G16B16A16S +{ + short R; + short G; + short B; + short A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorI *dst, const R16G16B16A16S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R16G16B16A16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<short>(src->red); + dst->G = gl::floatToNormalized<short>(src->green); + dst->B = gl::floatToNormalized<short>(src->blue); + dst->A = gl::floatToNormalized<short>(src->alpha); + } + + static void writeColor(R16G16B16A16S *dst, const gl::ColorI *src) + { + dst->R = static_cast<short>(src->red); + dst->G = static_cast<short>(src->green); + dst->B = static_cast<short>(src->blue); + dst->A = static_cast<short>(src->alpha); + } + + static void average(R16G16B16A16S *dst, const R16G16B16A16S *src1, const R16G16B16A16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32S +{ + int R; + + static void readColor(gl::ColorF *dst, const R32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R32S *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<int>(src->red); + } + + static void writeColor(R32S *dst, const gl::ColorI *src) + { + dst->R = static_cast<int>(src->red); + } + + static void average(R32S *dst, const R32S *src1, const R32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R32G32S +{ + int R; + int G; + + static void readColor(gl::ColorF *dst, const R32G32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R32G32S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32G32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<int>(src->red); + dst->G = gl::floatToNormalized<int>(src->green); + } + + static void writeColor(R32G32S *dst, const gl::ColorI *src) + { + dst->R = static_cast<int>(src->red); + dst->G = static_cast<int>(src->green); + } + + static void average(R32G32S *dst, const R32G32S *src1, const R32G32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R32G32B32S +{ + int R; + int G; + int B; + + static void readColor(gl::ColorF *dst, const R32G32B32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R32G32B32S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R32G32B32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<int>(src->red); + dst->G = gl::floatToNormalized<int>(src->green); + dst->B = gl::floatToNormalized<int>(src->blue); + } + + static void writeColor(R32G32B32S *dst, const gl::ColorI *src) + { + dst->R = static_cast<int>(src->red); + dst->G = static_cast<int>(src->green); + dst->B = static_cast<int>(src->blue); + } + + static void average(R32G32B32S *dst, const R32G32B32S *src1, const R32G32B32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R32G32B32A32S +{ + int R; + int G; + int B; + int A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorI *dst, const R32G32B32A32S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R32G32B32A32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<int>(src->red); + dst->G = gl::floatToNormalized<int>(src->green); + dst->B = gl::floatToNormalized<int>(src->blue); + dst->A = gl::floatToNormalized<int>(src->alpha); + } + + static void writeColor(R32G32B32A32S *dst, const gl::ColorI *src) + { + dst->R = static_cast<int>(src->red); + dst->G = static_cast<int>(src->green); + dst->B = static_cast<int>(src->blue); + dst->A = static_cast<int>(src->alpha); + } + + static void average(R32G32B32A32S *dst, const R32G32B32A32S *src1, const R32G32B32A32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct A16B16G16R16F +{ + unsigned short A; + unsigned short R; + unsigned short G; + unsigned short B; + + static void readColor(gl::ColorF *dst, const A16B16G16R16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(A16B16G16R16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct R16G16B16A16F +{ + unsigned short R; + unsigned short G; + unsigned short B; + unsigned short A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(R16G16B16A16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(R16G16B16A16F *dst, const R16G16B16A16F *src1, const R16G16B16A16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct R16F +{ + unsigned short R; + + static void readColor(gl::ColorF *dst, const R16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + } + + static void average(R16F *dst, const R16F *src1, const R16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + } +}; + +struct A16F +{ + unsigned short A; + + static void readColor(gl::ColorF *dst, const A16F *src) + { + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(A16F *dst, const gl::ColorF *src) + { + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(A16F *dst, const A16F *src1, const A16F *src2) + { + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct L16F +{ + unsigned short L; + + static void readColor(gl::ColorF *dst, const L16F *src) + { + float lum = gl::float16ToFloat32(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = 1.0f; + } + + static void writeColor(L16F *dst, const gl::ColorF *src) + { + dst->L = gl::float32ToFloat16((src->red + src->green + src->blue) / 3.0f); + } + + static void average(L16F *dst, const L16F *src1, const L16F *src2) + { + dst->L = gl::averageHalfFloat(src1->L, src2->L); + } +}; + +struct L16A16F +{ + unsigned short L; + unsigned short A; + + static void readColor(gl::ColorF *dst, const L16A16F *src) + { + float lum = gl::float16ToFloat32(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(L16A16F *dst, const gl::ColorF *src) + { + dst->L = gl::float32ToFloat16((src->red + src->green + src->blue) / 3.0f); + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(L16A16F *dst, const L16A16F *src1, const L16A16F *src2) + { + dst->L = gl::averageHalfFloat(src1->L, src2->L); + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct R16G16F +{ + unsigned short R; + unsigned short G; + + static void readColor(gl::ColorF *dst, const R16G16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R16G16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + } + + static void average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + } +}; + +struct R16G16B16F +{ + unsigned short R; + unsigned short G; + unsigned short B; + + static void readColor(gl::ColorF *dst, const R16G16B16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = 1.0f; + } + + static void writeColor(R16G16B16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + } + + static void average(R16G16B16F *dst, const R16G16B16F *src1, const R16G16B16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + } +}; + +struct A32B32G32R32F +{ + float A; + float R; + float G; + float B; + + static void readColor(gl::ColorF *dst, const A32B32G32R32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(A32B32G32R32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + dst->A = src->alpha; + } + + static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32G32B32A32F +{ + float R; + float G; + float B; + float A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R32G32B32A32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + dst->A = src->alpha; + } + + static void average(R32G32B32A32F *dst, const R32G32B32A32F *src1, const R32G32B32A32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32F +{ + float R; + + static void readColor(gl::ColorF *dst, const R32F *src) + { + dst->red = src->R; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + } + + static void average(R32F *dst, const R32F *src1, const R32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct A32F +{ + float A; + + static void readColor(gl::ColorF *dst, const A32F *src) + { + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = src->A; + } + + static void writeColor(A32F *dst, const gl::ColorF *src) + { + dst->A = src->alpha; + } + + static void average(A32F *dst, const A32F *src1, const A32F *src2) + { + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct L32F +{ + float L; + + static void readColor(gl::ColorF *dst, const L32F *src) + { + dst->red = src->L; + dst->green = src->L; + dst->blue = src->L; + dst->alpha = 1.0f; + } + + static void writeColor(L32F *dst, const gl::ColorF *src) + { + dst->L = (src->red + src->green + src->blue) / 3.0f; + } + + static void average(L32F *dst, const L32F *src1, const L32F *src2) + { + dst->L = gl::average(src1->L, src2->L); + } +}; + +struct L32A32F +{ + float L; + float A; + + static void readColor(gl::ColorF *dst, const L32A32F *src) + { + dst->red = src->L; + dst->green = src->L; + dst->blue = src->L; + dst->alpha = src->A; + } + + static void writeColor(L32A32F *dst, const gl::ColorF *src) + { + dst->L = (src->red + src->green + src->blue) / 3.0f; + dst->A = src->alpha; + } + + static void average(L32A32F *dst, const L32A32F *src1, const L32A32F *src2) + { + dst->L = gl::average(src1->L, src2->L); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32G32F +{ + float R; + float G; + + static void readColor(gl::ColorF *dst, const R32G32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R32G32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + } + + static void average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R32G32B32F +{ + float R; + float G; + float B; + + static void readColor(gl::ColorF *dst, const R32G32B32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1.0f; + } + + static void writeColor(R32G32B32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + } + + static void average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R10G10B10A2 +{ + unsigned int R : 10; + unsigned int G : 10; + unsigned int B : 10; + unsigned int A : 2; + + static void readColor(gl::ColorF *dst, const R10G10B10A2 *src) + { + dst->red = gl::normalizedToFloat<10>(src->R); + dst->green = gl::normalizedToFloat<10>(src->G); + dst->blue = gl::normalizedToFloat<10>(src->B); + dst->alpha = gl::normalizedToFloat< 2>(src->A); + } + + static void readColor(gl::ColorUI *dst, const R10G10B10A2 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R10G10B10A2 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<10, unsigned int>(src->red); + dst->G = gl::floatToNormalized<10, unsigned int>(src->green); + dst->B = gl::floatToNormalized<10, unsigned int>(src->blue); + dst->A = gl::floatToNormalized< 2, unsigned int>(src->alpha); + } + + static void writeColor(R10G10B10A2 *dst, const gl::ColorUI *src) + { + dst->R = static_cast<unsigned int>(src->red); + dst->G = static_cast<unsigned int>(src->green); + dst->B = static_cast<unsigned int>(src->blue); + dst->A = static_cast<unsigned int>(src->alpha); + } + + static void average(R10G10B10A2 *dst, const R10G10B10A2 *src1, const R10G10B10A2 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R9G9B9E5 +{ + unsigned int R : 9; + unsigned int G : 9; + unsigned int B : 9; + unsigned int E : 5; + + static void readColor(gl::ColorF *dst, const R9G9B9E5 *src) + { + gl::convert999E5toRGBFloats(gl::bitCast<unsigned int>(*src), &dst->red, &dst->green, &dst->blue); + dst->alpha = 1.0f; + } + + static void writeColor(R9G9B9E5 *dst, const gl::ColorF *src) + { + *reinterpret_cast<unsigned int*>(dst) = gl::convertRGBFloatsTo999E5(src->red, + src->green, + src->blue); + } + + static void average(R9G9B9E5 *dst, const R9G9B9E5 *src1, const R9G9B9E5 *src2) + { + float r1, g1, b1; + gl::convert999E5toRGBFloats(*reinterpret_cast<const unsigned int*>(src1), &r1, &g1, &b1); + + float r2, g2, b2; + gl::convert999E5toRGBFloats(*reinterpret_cast<const unsigned int*>(src2), &r2, &g2, &b2); + + *reinterpret_cast<unsigned int*>(dst) = gl::convertRGBFloatsTo999E5(gl::average(r1, r2), + gl::average(g1, g2), + gl::average(b1, b2)); + } +}; + +struct R11G11B10F +{ + unsigned int R : 11; + unsigned int G : 11; + unsigned int B : 10; + + static void readColor(gl::ColorF *dst, const R11G11B10F *src) + { + dst->red = gl::float11ToFloat32(src->R); + dst->green = gl::float11ToFloat32(src->G); + dst->blue = gl::float10ToFloat32(src->B); + dst->alpha = 1.0f; + } + + static void writeColor(R11G11B10F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat11(src->red); + dst->G = gl::float32ToFloat11(src->green); + dst->B = gl::float32ToFloat10(src->blue); + } + + static void average(R11G11B10F *dst, const R11G11B10F *src1, const R11G11B10F *src2) + { + dst->R = gl::averageFloat11(src1->R, src2->R); + dst->G = gl::averageFloat11(src1->G, src2->G); + dst->B = gl::averageFloat10(src1->B, src2->B); + } +}; + +} + +#endif // LIBGLESV2_RENDERER_IMAGEFORMATS_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.cpp new file mode 100644 index 0000000000..4a294608ae --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.cpp @@ -0,0 +1,662 @@ +#include "precompiled.h" +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// loadimage.cpp: Defines image loading functions. + +#include "libGLESv2/renderer/loadimage.h" + +namespace rx +{ + +void LoadA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = static_cast<uint32_t>(source[x]) << 24; + } + } + } +} + +void LoadA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); +} + +void LoadA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0.0f; + dest[4 * x + 1] = 0.0f; + dest[4 * x + 2] = 0.0f; + dest[4 * x + 3] = source[x]; + } + } + } +} + +void LoadA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0; + dest[4 * x + 1] = 0; + dest[4 * x + 2] = 0; + dest[4 * x + 3] = source[x]; + } + } + } +} + +void LoadL8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadL8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadL8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); +} + +void LoadL32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 1.0f; + } + } + } +} + +void LoadL16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = gl::Float16One; + } + } + } +} + +void LoadLA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadLA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadLA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); +} + +void LoadLA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = OffsetDataPointer<float>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadLA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadRGB8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x * 3 + 2]; + dest[4 * x + 1] = source[x * 3 + 1]; + dest[4 * x + 2] = source[x * 3 + 0]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadRG8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0x00; + dest[4 * x + 1] = source[x * 2 + 1]; + dest[4 * x + 2] = source[x * 2 + 0]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0x00; + dest[4 * x + 1] = 0x00; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR5G6B5ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgb = source[x]; + dest[4 * x + 0] = ((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2); + dest[4 * x + 1] = ((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9); + dest[4 * x + 2] = ((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13); + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR5G6B5ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgb = source[x]; + dest[4 * x + 0] = ((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13); + dest[4 * x + 1] = ((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9); + dest[4 * x + 2] = ((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2); + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadRGBA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } + } +} + +void LoadRGBA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); + dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); + dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); + dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); + } + } + } +} + +void LoadRGBA4ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); + dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); + dest[4 * x + 2] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); + dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); + } + } + } +} + +void LoadBGRA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t bgra = source[x]; + dest[4 * x + 0] = ((bgra & 0xF000) >> 8) | ((bgra & 0xF000) >> 12); + dest[4 * x + 1] = ((bgra & 0x0F00) >> 4) | ((bgra & 0x0F00) >> 8); + dest[4 * x + 2] = ((bgra & 0x00F0) << 0) | ((bgra & 0x00F0) >> 4); + dest[4 * x + 3] = ((bgra & 0x000F) << 4) | ((bgra & 0x000F) >> 0); + } + } + } +} + +void LoadRGB5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); + dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); + dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); + dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; + } + } + } +} + +void LoadRGB5A1ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); + dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); + dest[4 * x + 2] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); + dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; + } + } + } +} + + +void LoadBGR5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t bgra = source[x]; + dest[4 * x + 0] = ((bgra & 0xF800) >> 8) | ((bgra & 0xF800) >> 13); + dest[4 * x + 1] = ((bgra & 0x07C0) >> 3) | ((bgra & 0x07C0) >> 8); + dest[4 * x + 2] = ((bgra & 0x003E) << 2) | ((bgra & 0x003E) >> 3); + dest[4 * x + 3] = (bgra & 0x0001) ? 0xFF : 0; + } + } + } +} + +void LoadRGB10A2ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba = source[x]; + dest[4 * x + 0] = (rgba & 0x000003FF) >> 2; + dest[4 * x + 1] = (rgba & 0x000FFC00) >> 12; + dest[4 * x + 2] = (rgba & 0x3FF00000) >> 22; + dest[4 * x + 3] = ((rgba & 0xC0000000) >> 30) * 0x55; + } + } + } +} + +void LoadRGB16FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::convertRGBFloatsTo999E5(gl::float16ToFloat32(source[x * 3 + 0]), + gl::float16ToFloat32(source[x * 3 + 1]), + gl::float16ToFloat32(source[x * 3 + 2])); + } + } + } +} + +void LoadRGB32FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::convertRGBFloatsTo999E5(source[x * 3 + 0], source[x * 3 + 1], source[x * 3 + 2]); + } + } + } +} + +void LoadRGB16FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 0])) << 0) | + (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 1])) << 11) | + (gl::float32ToFloat10(gl::float16ToFloat32(source[x * 3 + 2])) << 22); + } + } + } +} + +void LoadRGB32FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = (gl::float32ToFloat11(source[x * 3 + 0]) << 0) | + (gl::float32ToFloat11(source[x * 3 + 1]) << 11) | + (gl::float32ToFloat10(source[x * 3 + 2]) << 22); + } + } + } +} + +void LoadG8R24ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t d = source[x] >> 8; + uint8_t s = source[x] & 0xFF; + dest[x] = d | (s << 24); + } + } + } +} + +void LoadRGB32FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x * 4 + 0] = gl::float32ToFloat16(source[x * 3 + 0]); + dest[x * 4 + 1] = gl::float32ToFloat16(source[x * 3 + 1]); + dest[x * 4 + 2] = gl::float32ToFloat16(source[x * 3 + 2]); + dest[x * 4 + 3] = gl::Float16One; + } + } + } +} + +void LoadR32ToR16(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = source[x] >> 16; + } + } + } +} + +void LoadR32ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x++) + { + dest[x] = source[x] >> 8; + } + } + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.h b/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.h new file mode 100644 index 0000000000..bcdff24a66 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.h @@ -0,0 +1,193 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// loadimage.h: Defines image loading functions + +#ifndef LIBGLESV2_RENDERER_LOADIMAGE_H_ +#define LIBGLESV2_RENDERER_LOADIMAGE_H_ + +#include "libGLESv2/angletypes.h" + +#include <cstdint> + +namespace rx +{ + +void LoadA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRG8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR5G6B5ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR5G6B5ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA4ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadBGRA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB5A1ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadBGR5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB10A2ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB16FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB32FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB16FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB32FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadG8R24ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template <typename type, size_t componentCount> +inline void LoadToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template <typename type, uint32_t fourthComponentBits> +inline void LoadToNative3To4(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template <size_t componentCount> +inline void Load32FTo16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB32FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template <size_t blockWidth, size_t blockHeight, size_t blockSize> +inline void LoadCompressedToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR32ToR16(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template <typename type, uint32_t firstBits, uint32_t secondBits, uint32_t thirdBits, uint32_t fourthBits> +inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR32ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template <typename T> +inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch); + +template <typename T> +inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch); + +} + +#include "loadimage.inl" + +#endif // LIBGLESV2_RENDERER_LOADIMAGE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.inl b/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.inl new file mode 100644 index 0000000000..abd0a3673c --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.inl @@ -0,0 +1,156 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "common/mathutil.h" + +namespace rx +{ + +template <typename T> +inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast<T*>(data + (y * rowPitch) + (z * depthPitch)); +} + +template <typename T> +inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast<const T*>(data + (y * rowPitch) + (z * depthPitch)); +} + +template <typename type, size_t componentCount> +inline void LoadToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t rowSize = width * sizeof(type) * componentCount; + const size_t layerSize = rowSize * height; + const size_t imageSize = layerSize * depth; + + if (layerSize == inputDepthPitch && layerSize == outputDepthPitch) + { + ASSERT(rowSize == inputRowPitch && rowSize == outputRowPitch); + memcpy(output, input, imageSize); + } + else if (rowSize == inputRowPitch && rowSize == outputRowPitch) + { + for (size_t z = 0; z < depth; z++) + { + const type *source = OffsetDataPointer<type>(input, 0, z, inputRowPitch, inputDepthPitch); + type *dest = OffsetDataPointer<type>(output, 0, z, outputRowPitch, outputDepthPitch); + + memcpy(dest, source, layerSize); + } + } + else + { + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const type *source = OffsetDataPointer<type>(input, y, z, inputRowPitch, inputDepthPitch); + type *dest = OffsetDataPointer<type>(output, y, z, outputRowPitch, outputDepthPitch); + memcpy(dest, source, width * sizeof(type) * componentCount); + } + } + } +} + +template <typename type, uint32_t fourthComponentBits> +inline void LoadToNative3To4(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const type fourthValue = gl::bitCast<type>(fourthComponentBits); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const type *source = OffsetDataPointer<type>(input, y, z, inputRowPitch, inputDepthPitch); + type *dest = OffsetDataPointer<type>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x * 4 + 0] = source[x * 3 + 0]; + dest[x * 4 + 1] = source[x * 3 + 1]; + dest[x * 4 + 2] = source[x * 3 + 2]; + dest[x * 4 + 3] = fourthValue; + } + } + } +} + +template <size_t componentCount> +inline void Load32FTo16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t elementWidth = componentCount * width; + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer<float>(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < elementWidth; x++) + { + dest[x] = gl::float32ToFloat16(source[x]); + } + } + } +} + +template <size_t blockWidth, size_t blockHeight, size_t blockSize> +inline void LoadCompressedToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t columns = (width + (blockWidth - 1)) / blockWidth; + const size_t rows = (height + (blockHeight - 1)) / blockHeight; + + for (size_t z = 0; z < depth; ++z) + { + for (size_t y = 0; y < rows; ++y) + { + const uint8_t *source = OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch); + memcpy(dest, source, columns * blockSize); + } + } +} + +template <typename type, uint32_t firstBits, uint32_t secondBits, uint32_t thirdBits, uint32_t fourthBits> +inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + type writeValues[4] = + { + gl::bitCast<type>(firstBits), + gl::bitCast<type>(secondBits), + gl::bitCast<type>(thirdBits), + gl::bitCast<type>(fourthBits), + }; + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + type *destRow = OffsetDataPointer<type>(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + type* destPixel = destRow + x * 4; + + // This could potentially be optimized by generating an entire row of initialization + // data and copying row by row instead of pixel by pixel. + memcpy(destPixel, writeValues, sizeof(type) * 4); + } + } + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp new file mode 100644 index 0000000000..dcf347d421 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp @@ -0,0 +1,113 @@ +#include "precompiled.h" +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// loadimageSSE2.cpp: Defines image loading functions. It's +// in a separated file for GCC, which can enable SSE usage only per-file, +// not for code blocks that use SSE2 explicitly. + +#include "libGLESv2/renderer/loadimage.h" + +#if !defined(__SSE2__) && (defined(_M_X64) || _M_IX86_FP == 2) +#define __SSE2__ +#endif + +namespace rx +{ + +void LoadA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ +#ifdef __SSE2__ + __m128i zeroWide = _mm_setzero_si128(); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer<uint8_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + + size_t x = 0; + + // Make output writes aligned + for (; ((reinterpret_cast<intptr_t>(&dest[x]) & 0xF) != 0 && x < width); x++) + { + dest[x] = static_cast<uint32_t>(source[x]) << 24; + } + + for (; x + 7 < width; x += 8) + { + __m128i sourceData = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&source[x])); + // Interleave each byte to 16bit, make the lower byte to zero + sourceData = _mm_unpacklo_epi8(zeroWide, sourceData); + // Interleave each 16bit to 32bit, make the lower 16bit to zero + __m128i lo = _mm_unpacklo_epi16(zeroWide, sourceData); + __m128i hi = _mm_unpackhi_epi16(zeroWide, sourceData); + + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), lo); + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x + 4]), hi); + } + + // Handle the remainder + for (; x < width; x++) + { + dest[x] = static_cast<uint32_t>(source[x]) << 24; + } + } + } +#endif +} + +void LoadRGBA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ +#ifdef __SSE2__ + __m128i brMask = _mm_set1_epi32(0x00ff00ff); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer<uint32_t>(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer<uint32_t>(output, y, z, outputRowPitch, outputDepthPitch); + + size_t x = 0; + + // Make output writes aligned + for (; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + + for (; x + 3 < width; x += 4) + { + __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x])); + // Mask out g and a, which don't change + __m128i gaComponents = _mm_andnot_si128(brMask, sourceData); + // Mask out b and r + __m128i brComponents = _mm_and_si128(sourceData, brMask); + // Swap b and r + __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1)); + __m128i result = _mm_or_si128(gaComponents, brSwapped); + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result); + } + + // Perform leftover writes + for (; x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } + } +#endif +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/vertexconversion.h b/src/3rdparty/angle/src/libGLESv2/renderer/vertexconversion.h index 590b9d48a3..590b9d48a3 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d9/vertexconversion.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/vertexconversion.h diff --git a/src/3rdparty/angle/src/libGLESv2/utilities.cpp b/src/3rdparty/angle/src/libGLESv2/utilities.cpp deleted file mode 100644 index 30765ffba0..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/utilities.cpp +++ /dev/null @@ -1,817 +0,0 @@ -#include "precompiled.h" -// -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// utilities.cpp: Conversion functions and other utility routines. - -#include "libGLESv2/utilities.h" -#include "libGLESv2/mathutil.h" -#if defined(ANGLE_OS_WINRT) -# include <locale> -# include <codecvt> -# include <wrl.h> -# include <windows.storage.h> - using namespace Microsoft::WRL; - using namespace ABI::Windows::Storage; -#endif - -namespace gl -{ - -int UniformComponentCount(GLenum type) -{ - switch (type) - { - case GL_BOOL: - case GL_FLOAT: - case GL_INT: - case GL_SAMPLER_2D: - case GL_SAMPLER_CUBE: - return 1; - case GL_BOOL_VEC2: - case GL_FLOAT_VEC2: - case GL_INT_VEC2: - return 2; - case GL_INT_VEC3: - case GL_FLOAT_VEC3: - case GL_BOOL_VEC3: - return 3; - case GL_BOOL_VEC4: - case GL_FLOAT_VEC4: - case GL_INT_VEC4: - case GL_FLOAT_MAT2: - return 4; - case GL_FLOAT_MAT3: - return 9; - case GL_FLOAT_MAT4: - return 16; - default: - UNREACHABLE(); - } - - return 0; -} - -GLenum UniformComponentType(GLenum type) -{ - switch(type) - { - case GL_BOOL: - case GL_BOOL_VEC2: - case GL_BOOL_VEC3: - case GL_BOOL_VEC4: - return GL_BOOL; - case GL_FLOAT: - case GL_FLOAT_VEC2: - case GL_FLOAT_VEC3: - case GL_FLOAT_VEC4: - case GL_FLOAT_MAT2: - case GL_FLOAT_MAT3: - case GL_FLOAT_MAT4: - return GL_FLOAT; - case GL_INT: - case GL_SAMPLER_2D: - case GL_SAMPLER_CUBE: - case GL_INT_VEC2: - case GL_INT_VEC3: - case GL_INT_VEC4: - return GL_INT; - default: - UNREACHABLE(); - } - - return GL_NONE; -} - -size_t UniformComponentSize(GLenum type) -{ - switch(type) - { - case GL_BOOL: return sizeof(GLint); - case GL_FLOAT: return sizeof(GLfloat); - case GL_INT: return sizeof(GLint); - default: UNREACHABLE(); - } - - return 0; -} - -size_t UniformInternalSize(GLenum type) -{ - // Expanded to 4-element vectors - return UniformComponentSize(UniformComponentType(type)) * VariableRowCount(type) * 4; -} - -size_t UniformExternalSize(GLenum type) -{ - return UniformComponentSize(UniformComponentType(type)) * UniformComponentCount(type); -} - -int VariableRowCount(GLenum type) -{ - switch (type) - { - case GL_NONE: - return 0; - case GL_BOOL: - case GL_FLOAT: - case GL_INT: - case GL_BOOL_VEC2: - case GL_FLOAT_VEC2: - case GL_INT_VEC2: - case GL_INT_VEC3: - case GL_FLOAT_VEC3: - case GL_BOOL_VEC3: - case GL_BOOL_VEC4: - case GL_FLOAT_VEC4: - case GL_INT_VEC4: - case GL_SAMPLER_2D: - case GL_SAMPLER_CUBE: - return 1; - case GL_FLOAT_MAT2: - return 2; - case GL_FLOAT_MAT3: - return 3; - case GL_FLOAT_MAT4: - return 4; - default: - UNREACHABLE(); - } - - return 0; -} - -int VariableColumnCount(GLenum type) -{ - switch (type) - { - case GL_NONE: - return 0; - case GL_BOOL: - case GL_FLOAT: - case GL_INT: - case GL_SAMPLER_2D: - case GL_SAMPLER_CUBE: - return 1; - case GL_BOOL_VEC2: - case GL_FLOAT_VEC2: - case GL_INT_VEC2: - case GL_FLOAT_MAT2: - return 2; - case GL_INT_VEC3: - case GL_FLOAT_VEC3: - case GL_BOOL_VEC3: - case GL_FLOAT_MAT3: - return 3; - case GL_BOOL_VEC4: - case GL_FLOAT_VEC4: - case GL_INT_VEC4: - case GL_FLOAT_MAT4: - return 4; - default: - UNREACHABLE(); - } - - return 0; -} - -int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize) -{ - ASSERT(allocationSize <= bitsSize); - - unsigned int mask = std::numeric_limits<unsigned int>::max() >> (std::numeric_limits<unsigned int>::digits - allocationSize); - - for (unsigned int i = 0; i < bitsSize - allocationSize + 1; i++) - { - if ((*bits & mask) == 0) - { - *bits |= mask; - return i; - } - - mask <<= 1; - } - - return -1; -} - -GLsizei ComputePitch(GLsizei width, GLint internalformat, GLint alignment) -{ - ASSERT(alignment > 0 && isPow2(alignment)); - - GLsizei rawPitch = ComputePixelSize(internalformat) * width; - return (rawPitch + alignment - 1) & ~(alignment - 1); -} - -GLsizei ComputeCompressedPitch(GLsizei width, GLenum internalformat) -{ - return ComputeCompressedSize(width, 1, internalformat); -} - -GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum internalformat) -{ - switch (internalformat) - { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - return 8 * ((width + 3) / 4) * ((height + 3) / 4); - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - return 16 * ((width + 3) / 4) * ((height + 3) / 4); - default: - return 0; - } -} - -GLsizei ComputeTypeSize(GLenum type) -{ - switch (type) - { - case GL_BYTE: return 1; - case GL_UNSIGNED_BYTE: return 1; - case GL_SHORT: return 2; - case GL_UNSIGNED_SHORT: return 2; - case GL_INT: return 4; - case GL_UNSIGNED_INT: return 4; - case GL_FLOAT: return 4; - case GL_HALF_FLOAT_OES: return 2; - case GL_UNSIGNED_SHORT_5_6_5: return 2; - case GL_UNSIGNED_SHORT_4_4_4_4: return 2; - case GL_UNSIGNED_SHORT_5_5_5_1: return 2; - case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: return 2; - case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: return 2; - case GL_UNSIGNED_INT_2_10_10_10_REV_EXT: return 4; - case GL_UNSIGNED_INT_24_8_OES: return 4; - default: UNREACHABLE(); return 0; - } -} - -bool IsCompressed(GLenum format) -{ - if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || - format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || - format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE || - format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE) - { - return true; - } - else - { - return false; - } -} - -bool IsDepthTexture(GLenum format) -{ - if (format == GL_DEPTH_COMPONENT || - format == GL_DEPTH_STENCIL_OES || - format == GL_DEPTH_COMPONENT16 || - format == GL_DEPTH_COMPONENT32_OES || - format == GL_DEPTH24_STENCIL8_OES) - { - return true; - } - - return false; -} - -bool IsStencilTexture(GLenum format) -{ - if (format == GL_DEPTH_STENCIL_OES || - format == GL_DEPTH24_STENCIL8_OES) - { - return true; - } - - return false; -} - -void MakeValidSize(bool isImage, bool isCompressed, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) -{ - int upsampleCount = 0; - - if (isCompressed) - { - // Don't expand the size of full textures that are at least 4x4 - // already. - if (isImage || *requestWidth < 4 || *requestHeight < 4) - { - while (*requestWidth % 4 != 0 || *requestHeight % 4 != 0) - { - *requestWidth <<= 1; - *requestHeight <<= 1; - upsampleCount++; - } - } - } - *levelOffset = upsampleCount; -} - -// Returns the size, in bytes, of a single texel in an Image -int ComputePixelSize(GLint internalformat) -{ - switch (internalformat) - { - case GL_ALPHA8_EXT: return sizeof(unsigned char); - case GL_LUMINANCE8_EXT: return sizeof(unsigned char); - case GL_ALPHA32F_EXT: return sizeof(float); - case GL_LUMINANCE32F_EXT: return sizeof(float); - case GL_ALPHA16F_EXT: return sizeof(unsigned short); - case GL_LUMINANCE16F_EXT: return sizeof(unsigned short); - case GL_LUMINANCE8_ALPHA8_EXT: return sizeof(unsigned char) * 2; - case GL_LUMINANCE_ALPHA32F_EXT: return sizeof(float) * 2; - case GL_LUMINANCE_ALPHA16F_EXT: return sizeof(unsigned short) * 2; - case GL_RGB8_OES: return sizeof(unsigned char) * 3; - case GL_RGB565: return sizeof(unsigned short); - case GL_RGB32F_EXT: return sizeof(float) * 3; - case GL_RGB16F_EXT: return sizeof(unsigned short) * 3; - case GL_RGBA8_OES: return sizeof(unsigned char) * 4; - case GL_RGBA4: return sizeof(unsigned short); - case GL_RGB5_A1: return sizeof(unsigned short); - case GL_RGBA32F_EXT: return sizeof(float) * 4; - case GL_RGBA16F_EXT: return sizeof(unsigned short) * 4; - case GL_BGRA8_EXT: return sizeof(unsigned char) * 4; - case GL_BGRA4_ANGLEX: return sizeof(unsigned short); - case GL_BGR5_A1_ANGLEX: return sizeof(unsigned short); - default: UNREACHABLE(); - } - - return 0; -} - -bool IsCubemapTextureTarget(GLenum target) -{ - return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); -} - -bool IsInternalTextureTarget(GLenum target) -{ - return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target); -} - -GLint ConvertSizedInternalFormat(GLenum format, GLenum type) -{ - switch (format) - { - case GL_ALPHA: - switch (type) - { - case GL_UNSIGNED_BYTE: return GL_ALPHA8_EXT; - case GL_FLOAT: return GL_ALPHA32F_EXT; - case GL_HALF_FLOAT_OES: return GL_ALPHA16F_EXT; - default: UNIMPLEMENTED(); - } - break; - case GL_LUMINANCE: - switch (type) - { - case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_EXT; - case GL_FLOAT: return GL_LUMINANCE32F_EXT; - case GL_HALF_FLOAT_OES: return GL_LUMINANCE16F_EXT; - default: UNIMPLEMENTED(); - } - break; - case GL_LUMINANCE_ALPHA: - switch (type) - { - case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_ALPHA8_EXT; - case GL_FLOAT: return GL_LUMINANCE_ALPHA32F_EXT; - case GL_HALF_FLOAT_OES: return GL_LUMINANCE_ALPHA16F_EXT; - default: UNIMPLEMENTED(); - } - break; - case GL_RGB: - switch (type) - { - case GL_UNSIGNED_BYTE: return GL_RGB8_OES; - case GL_UNSIGNED_SHORT_5_6_5: return GL_RGB565; - case GL_FLOAT: return GL_RGB32F_EXT; - case GL_HALF_FLOAT_OES: return GL_RGB16F_EXT; - default: UNIMPLEMENTED(); - } - break; - case GL_RGBA: - switch (type) - { - case GL_UNSIGNED_BYTE: return GL_RGBA8_OES; - case GL_UNSIGNED_SHORT_4_4_4_4: return GL_RGBA4; - case GL_UNSIGNED_SHORT_5_5_5_1: return GL_RGB5_A1; - case GL_FLOAT: return GL_RGBA32F_EXT; - case GL_HALF_FLOAT_OES: return GL_RGBA16F_EXT; - break; - default: UNIMPLEMENTED(); - } - break; - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: return GL_BGRA8_EXT; - case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: return GL_BGRA4_ANGLEX; - case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: return GL_BGR5_A1_ANGLEX; - default: UNIMPLEMENTED(); - } - break; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - return format; - case GL_DEPTH_COMPONENT: - switch (type) - { - case GL_UNSIGNED_SHORT: return GL_DEPTH_COMPONENT16; - case GL_UNSIGNED_INT: return GL_DEPTH_COMPONENT32_OES; - default: UNIMPLEMENTED(); - } - break; - case GL_DEPTH_STENCIL_OES: - switch (type) - { - case GL_UNSIGNED_INT_24_8_OES: return GL_DEPTH24_STENCIL8_OES; - default: UNIMPLEMENTED(); - } - break; - default: - UNIMPLEMENTED(); - } - - return GL_NONE; -} - -GLenum ExtractFormat(GLenum internalformat) -{ - switch (internalformat) - { - case GL_RGB565: return GL_RGB; - case GL_RGBA4: return GL_RGBA; - case GL_RGB5_A1: return GL_RGBA; - case GL_RGB8_OES: return GL_RGB; - case GL_RGBA8_OES: return GL_RGBA; - case GL_LUMINANCE8_ALPHA8_EXT: return GL_LUMINANCE_ALPHA; - case GL_LUMINANCE8_EXT: return GL_LUMINANCE; - case GL_ALPHA8_EXT: return GL_ALPHA; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; - case GL_RGBA32F_EXT: return GL_RGBA; - case GL_RGB32F_EXT: return GL_RGB; - case GL_ALPHA32F_EXT: return GL_ALPHA; - case GL_LUMINANCE32F_EXT: return GL_LUMINANCE; - case GL_LUMINANCE_ALPHA32F_EXT: return GL_LUMINANCE_ALPHA; - case GL_RGBA16F_EXT: return GL_RGBA; - case GL_RGB16F_EXT: return GL_RGB; - case GL_ALPHA16F_EXT: return GL_ALPHA; - case GL_LUMINANCE16F_EXT: return GL_LUMINANCE; - case GL_LUMINANCE_ALPHA16F_EXT: return GL_LUMINANCE_ALPHA; - case GL_BGRA8_EXT: return GL_BGRA_EXT; - case GL_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT; - case GL_DEPTH_COMPONENT32_OES: return GL_DEPTH_COMPONENT; - case GL_DEPTH24_STENCIL8_OES: return GL_DEPTH_STENCIL_OES; - default: return GL_NONE; // Unsupported - } -} - -GLenum ExtractType(GLenum internalformat) -{ - switch (internalformat) - { - case GL_RGB565: return GL_UNSIGNED_SHORT_5_6_5; - case GL_RGBA4: return GL_UNSIGNED_SHORT_4_4_4_4; - case GL_RGB5_A1: return GL_UNSIGNED_SHORT_5_5_5_1; - case GL_RGB8_OES: return GL_UNSIGNED_BYTE; - case GL_RGBA8_OES: return GL_UNSIGNED_BYTE; - case GL_LUMINANCE8_ALPHA8_EXT: return GL_UNSIGNED_BYTE; - case GL_LUMINANCE8_EXT: return GL_UNSIGNED_BYTE; - case GL_ALPHA8_EXT: return GL_UNSIGNED_BYTE; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_UNSIGNED_BYTE; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_UNSIGNED_BYTE; - case GL_RGBA32F_EXT: return GL_FLOAT; - case GL_RGB32F_EXT: return GL_FLOAT; - case GL_ALPHA32F_EXT: return GL_FLOAT; - case GL_LUMINANCE32F_EXT: return GL_FLOAT; - case GL_LUMINANCE_ALPHA32F_EXT: return GL_FLOAT; - case GL_RGBA16F_EXT: return GL_HALF_FLOAT_OES; - case GL_RGB16F_EXT: return GL_HALF_FLOAT_OES; - case GL_ALPHA16F_EXT: return GL_HALF_FLOAT_OES; - case GL_LUMINANCE16F_EXT: return GL_HALF_FLOAT_OES; - case GL_LUMINANCE_ALPHA16F_EXT: return GL_HALF_FLOAT_OES; - case GL_BGRA8_EXT: return GL_UNSIGNED_BYTE; - case GL_DEPTH_COMPONENT16: return GL_UNSIGNED_SHORT; - case GL_DEPTH_COMPONENT32_OES: return GL_UNSIGNED_INT; - case GL_DEPTH24_STENCIL8_OES: return GL_UNSIGNED_INT_24_8_OES; - default: return GL_NONE; // Unsupported - } -} - -bool IsColorRenderable(GLenum internalformat) -{ - switch (internalformat) - { - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGB565: - case GL_RGB8_OES: - case GL_RGBA8_OES: - return true; - case GL_DEPTH_COMPONENT16: - case GL_STENCIL_INDEX8: - case GL_DEPTH24_STENCIL8_OES: - return false; - case GL_BGRA8_EXT: - return true; - default: - UNIMPLEMENTED(); - } - - return false; -} - -bool IsDepthRenderable(GLenum internalformat) -{ - switch (internalformat) - { - case GL_DEPTH_COMPONENT16: - case GL_DEPTH24_STENCIL8_OES: - return true; - case GL_STENCIL_INDEX8: - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGB565: - case GL_RGB8_OES: - case GL_RGBA8_OES: - return false; - default: - UNIMPLEMENTED(); - } - - return false; -} - -bool IsStencilRenderable(GLenum internalformat) -{ - switch (internalformat) - { - case GL_STENCIL_INDEX8: - case GL_DEPTH24_STENCIL8_OES: - return true; - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGB565: - case GL_RGB8_OES: - case GL_RGBA8_OES: - case GL_DEPTH_COMPONENT16: - return false; - default: - UNIMPLEMENTED(); - } - - return false; -} - -bool IsFloat32Format(GLint internalformat) -{ - switch (internalformat) - { - case GL_RGBA32F_EXT: - case GL_RGB32F_EXT: - case GL_ALPHA32F_EXT: - case GL_LUMINANCE32F_EXT: - case GL_LUMINANCE_ALPHA32F_EXT: - return true; - default: - return false; - } -} - -bool IsFloat16Format(GLint internalformat) -{ - switch (internalformat) - { - case GL_RGBA16F_EXT: - case GL_RGB16F_EXT: - case GL_ALPHA16F_EXT: - case GL_LUMINANCE16F_EXT: - case GL_LUMINANCE_ALPHA16F_EXT: - return true; - default: - return false; - } -} - -unsigned int GetAlphaSize(GLenum colorFormat) -{ - switch (colorFormat) - { - case GL_RGBA16F_EXT: - return 16; - case GL_RGBA32F_EXT: - return 32; - case GL_RGBA4: - return 4; - case GL_RGBA8_OES: - case GL_BGRA8_EXT: - return 8; - case GL_RGB5_A1: - return 1; - case GL_RGB8_OES: - case GL_RGB565: - case GL_RGB32F_EXT: - case GL_RGB16F_EXT: - return 0; - default: - return 0; - } -} - -unsigned int GetRedSize(GLenum colorFormat) -{ - switch (colorFormat) - { - case GL_RGBA16F_EXT: - case GL_RGB16F_EXT: - return 16; - case GL_RGBA32F_EXT: - case GL_RGB32F_EXT: - return 32; - case GL_RGBA4: - return 4; - case GL_RGBA8_OES: - case GL_BGRA8_EXT: - case GL_RGB8_OES: - return 8; - case GL_RGB5_A1: - case GL_RGB565: - return 5; - default: - return 0; - } -} - -unsigned int GetGreenSize(GLenum colorFormat) -{ - switch (colorFormat) - { - case GL_RGBA16F_EXT: - case GL_RGB16F_EXT: - return 16; - case GL_RGBA32F_EXT: - case GL_RGB32F_EXT: - return 32; - case GL_RGBA4: - return 4; - case GL_RGBA8_OES: - case GL_BGRA8_EXT: - case GL_RGB8_OES: - return 8; - case GL_RGB5_A1: - return 5; - case GL_RGB565: - return 6; - default: - return 0; - } -} - -unsigned int GetBlueSize(GLenum colorFormat) -{ - switch (colorFormat) - { - case GL_RGBA16F_EXT: - case GL_RGB16F_EXT: - return 16; - case GL_RGBA32F_EXT: - case GL_RGB32F_EXT: - return 32; - case GL_RGBA4: - return 4; - case GL_RGBA8_OES: - case GL_BGRA8_EXT: - case GL_RGB8_OES: - return 8; - case GL_RGB5_A1: - case GL_RGB565: - return 5; - default: - return 0; - } -} - -unsigned int GetDepthSize(GLenum depthFormat) -{ - switch (depthFormat) - { - case GL_DEPTH_COMPONENT16: return 16; - case GL_DEPTH_COMPONENT32_OES: return 32; - case GL_DEPTH24_STENCIL8_OES: return 24; - default: return 0; - } -} - -unsigned int GetStencilSize(GLenum stencilFormat) -{ - switch (stencilFormat) - { - case GL_DEPTH24_STENCIL8_OES: return 8; - default: return 0; - } -} - -bool IsTriangleMode(GLenum drawMode) -{ - switch (drawMode) - { - case GL_TRIANGLES: - case GL_TRIANGLE_FAN: - case GL_TRIANGLE_STRIP: - return true; - case GL_POINTS: - case GL_LINES: - case GL_LINE_LOOP: - case GL_LINE_STRIP: - return false; - default: UNREACHABLE(); - } - - return false; -} - -} - -std::string getTempPath() -{ -#if !defined(ANGLE_OS_WINRT) - char path[MAX_PATH]; - DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path); - if (pathLen == 0) - { - UNREACHABLE(); - return std::string(); - } - - UINT unique = GetTempFileNameA(path, "sh", 0, path); - if (unique == 0) - { - UNREACHABLE(); - return std::string(); - } -#else - static std::string path; - - while (path.empty()) { - ComPtr<IApplicationDataStatics> factory; - Wrappers::HStringReference classId(RuntimeClass_Windows_Storage_ApplicationData); - HRESULT result = RoGetActivationFactory(classId.Get(), IID_PPV_ARGS(&factory)); - if (FAILED(result)) - break; - - ComPtr<IApplicationData> applicationData; - result = factory->get_Current(&applicationData); - if (FAILED(result)) - break; - - ComPtr<IStorageFolder> storageFolder; - result = applicationData->get_LocalFolder(&storageFolder); - if (FAILED(result)) - break; - - ComPtr<IStorageItem> localFolder; - result = storageFolder.As(&localFolder); - if (FAILED(result)) - break; - - HSTRING localFolderPath; - result = localFolder->get_Path(&localFolderPath); - if (FAILED(result)) - break; - - std::wstring_convert< std::codecvt_utf8<wchar_t> > converter; - path = converter.to_bytes(WindowsGetStringRawBuffer(localFolderPath, NULL)); - if (path.empty()) - { - UNREACHABLE(); - break; - } - } -#endif - - return path; -} - -void writeFile(const char* path, const void* content, size_t size) -{ - FILE* file = fopen(path, "w"); - if (!file) - { - UNREACHABLE(); - return; - } - - fwrite(content, sizeof(char), size, file); - fclose(file); -} diff --git a/src/3rdparty/angle/src/libGLESv2/utilities.h b/src/3rdparty/angle/src/libGLESv2/utilities.h deleted file mode 100644 index ed663ebca2..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/utilities.h +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// utilities.h: Conversion functions and other utility routines. - -#ifndef LIBGLESV2_UTILITIES_H -#define LIBGLESV2_UTILITIES_H - -#define GL_APICALL -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - -#include <string> - -namespace gl -{ - -struct Color; - -int UniformComponentCount(GLenum type); -GLenum UniformComponentType(GLenum type); -size_t UniformInternalSize(GLenum type); -size_t UniformExternalSize(GLenum type); -int VariableRowCount(GLenum type); -int VariableColumnCount(GLenum type); - -int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize); - -void MakeValidSize(bool isImage, bool isCompressed, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); -int ComputePixelSize(GLint internalformat); -GLsizei ComputePitch(GLsizei width, GLint internalformat, GLint alignment); -GLsizei ComputeCompressedPitch(GLsizei width, GLenum format); -GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format); -GLsizei ComputeTypeSize(GLenum type); -bool IsCompressed(GLenum format); -bool IsDepthTexture(GLenum format); -bool IsStencilTexture(GLenum format); -bool IsCubemapTextureTarget(GLenum target); -bool IsInternalTextureTarget(GLenum target); -GLint ConvertSizedInternalFormat(GLenum format, GLenum type); -GLenum ExtractFormat(GLenum internalformat); -GLenum ExtractType(GLenum internalformat); - -bool IsColorRenderable(GLenum internalformat); -bool IsDepthRenderable(GLenum internalformat); -bool IsStencilRenderable(GLenum internalformat); - -bool IsFloat32Format(GLint internalformat); -bool IsFloat16Format(GLint internalformat); - -GLuint GetAlphaSize(GLenum colorFormat); -GLuint GetRedSize(GLenum colorFormat); -GLuint GetGreenSize(GLenum colorFormat); -GLuint GetBlueSize(GLenum colorFormat); -GLuint GetDepthSize(GLenum depthFormat); -GLuint GetStencilSize(GLenum stencilFormat); -bool IsTriangleMode(GLenum drawMode); - -} - -std::string getTempPath(); -void writeFile(const char* path, const void* data, size_t size); - -#endif // LIBGLESV2_UTILITIES_H diff --git a/src/3rdparty/angle/src/libGLESv2/validationES.cpp b/src/3rdparty/angle/src/libGLESv2/validationES.cpp new file mode 100644 index 0000000000..309c4daedb --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/validationES.cpp @@ -0,0 +1,1583 @@ +#include "precompiled.h" +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES.h: Validation functions for generic OpenGL ES entry point parameters + +#include "libGLESv2/validationES.h" +#include "libGLESv2/validationES2.h" +#include "libGLESv2/validationES3.h" +#include "libGLESv2/Context.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/main.h" +#include "libGLESv2/Query.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/TransformFeedback.h" +#include "libGLESv2/VertexArray.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace gl +{ + +bool ValidCap(const Context *context, GLenum cap) +{ + switch (cap) + { + case GL_CULL_FACE: + case GL_POLYGON_OFFSET_FILL: + case GL_SAMPLE_ALPHA_TO_COVERAGE: + case GL_SAMPLE_COVERAGE: + case GL_SCISSOR_TEST: + case GL_STENCIL_TEST: + case GL_DEPTH_TEST: + case GL_BLEND: + case GL_DITHER: + return true; + case GL_PRIMITIVE_RESTART_FIXED_INDEX: + case GL_RASTERIZER_DISCARD: + return (context->getClientVersion() >= 3); + default: + return false; + } +} + +bool ValidTextureTarget(const Context *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + return true; + + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + return (context->getClientVersion() >= 3); + + default: + return false; + } +} + +// This function differs from ValidTextureTarget in that the target must be +// usable as the destination of a 2D operation-- so a cube face is valid, but +// GL_TEXTURE_CUBE_MAP is not. +// Note: duplicate of IsInternalTextureTarget +bool ValidTexture2DDestinationTarget(const Context *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + return true; + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_3D: + return (context->getClientVersion() >= 3); + default: + return false; + } +} + +bool ValidFramebufferTarget(GLenum target) +{ + META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER); + + switch (target) + { + case GL_FRAMEBUFFER: return true; + case GL_READ_FRAMEBUFFER: return true; + case GL_DRAW_FRAMEBUFFER: return true; + default: return false; + } +} + +bool ValidBufferTarget(const Context *context, GLenum target) +{ + switch (target) + { + case GL_ARRAY_BUFFER: + case GL_ELEMENT_ARRAY_BUFFER: + return true; + + case GL_PIXEL_PACK_BUFFER: + case GL_PIXEL_UNPACK_BUFFER: + return context->getExtensions().pixelBufferObject; + + case GL_COPY_READ_BUFFER: + case GL_COPY_WRITE_BUFFER: + case GL_TRANSFORM_FEEDBACK_BUFFER: + case GL_UNIFORM_BUFFER: + return (context->getClientVersion() >= 3); + + default: + return false; + } +} + +bool ValidBufferParameter(const Context *context, GLenum pname) +{ + switch (pname) + { + case GL_BUFFER_USAGE: + case GL_BUFFER_SIZE: + return true; + + // GL_BUFFER_MAP_POINTER is a special case, and may only be + // queried with GetBufferPointerv + case GL_BUFFER_ACCESS_FLAGS: + case GL_BUFFER_MAPPED: + case GL_BUFFER_MAP_OFFSET: + case GL_BUFFER_MAP_LENGTH: + return (context->getClientVersion() >= 3); + + default: + return false; + } +} + +bool ValidMipLevel(const Context *context, GLenum target, GLint level) +{ + size_t maxDimension = 0; + switch (target) + { + case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break; + case GL_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break; + case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break; + case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break; + default: UNREACHABLE(); + } + + return level <= gl::log2(maxDimension); +} + +bool ValidImageSize(const gl::Context *context, GLenum target, GLint level, + GLsizei width, GLsizei height, GLsizei depth) +{ + if (level < 0 || width < 0 || height < 0 || depth < 0) + { + return false; + } + + if (!context->getExtensions().textureNPOT && + (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))) + { + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + return false; + } + + return true; +} + +bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height) +{ + if (!IsFormatCompressed(internalFormat)) + { + return false; + } + + GLint blockWidth = GetCompressedBlockWidth(internalFormat); + GLint blockHeight = GetCompressedBlockHeight(internalFormat); + if (width < 0 || (width > blockWidth && width % blockWidth != 0) || + height < 0 || (height > blockHeight && height % blockHeight != 0)) + { + return false; + } + + return true; +} + +bool ValidQueryType(const Context *context, GLenum queryType) +{ + META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT); + META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT); + + switch (queryType) + { + case GL_ANY_SAMPLES_PASSED: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: + return true; + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + return (context->getClientVersion() >= 3); + default: + return false; + } +} + +bool ValidProgram(const Context *context, GLuint id) +{ + // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the + // error INVALID_VALUE if the provided name is not the name of either a shader or program object and + // INVALID_OPERATION if the provided name identifies an object that is not the expected type." + + if (context->getProgram(id) != NULL) + { + return true; + } + else if (context->getShader(id) != NULL) + { + // ID is the wrong type + return gl::error(GL_INVALID_OPERATION, false); + } + else + { + // No shader/program object has this ID + return gl::error(GL_INVALID_VALUE, false); + } +} + +bool ValidateAttachmentTarget(const gl::Context *context, GLenum attachment) +{ + if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + { + const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + + if (colorAttachment >= context->getCaps().maxColorAttachments) + { + return gl::error(GL_INVALID_VALUE, false); + } + } + else + { + switch (attachment) + { + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + + case GL_DEPTH_STENCIL_ATTACHMENT: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + + default: + return gl::error(GL_INVALID_ENUM, false); + } + } + + return true; +} + +bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height, + bool angleExtension) +{ + switch (target) + { + case GL_RENDERBUFFER: + break; + default: + return gl::error(GL_INVALID_ENUM, false); + } + + if (width < 0 || height < 0 || samples < 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (!gl::IsValidInternalFormat(internalformat, context->getExtensions(), context->getClientVersion())) + { + return gl::error(GL_INVALID_ENUM, false); + } + + // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be + // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains + // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the + // internal format must be sized and not an integer format if samples is greater than zero. + if (!gl::IsSizedInternalFormat(internalformat)) + { + return gl::error(GL_INVALID_ENUM, false); + } + + GLenum componentType = gl::GetComponentType(internalformat); + if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (!formatCaps.renderable) + { + return gl::error(GL_INVALID_ENUM, false); + } + + if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize) + { + return gl::error(GL_INVALID_VALUE, false); + } + + // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal + // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2) + // states that samples must be less than or equal to the maximum samples for the specified + // internal format. + if (angleExtension) + { + if (samples > context->getMaxSupportedSamples()) + { + return gl::error(GL_INVALID_VALUE, false); + } + } + else + { + if (samples > context->getMaxSupportedFormatSamples(internalformat)) + { + return gl::error(GL_INVALID_VALUE, false); + } + } + + GLuint handle = context->getState().getRenderbufferId(); + if (handle == 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + return true; +} + +bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment, + GLenum renderbuffertarget, GLuint renderbuffer) +{ + if (!ValidFramebufferTarget(target)) + { + return gl::error(GL_INVALID_ENUM, false); + } + + gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id(); + + if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (!ValidateAttachmentTarget(context, attachment)) + { + return false; + } + + // [OpenGL ES 2.0.25] Section 4.4.3 page 112 + // [OpenGL ES 3.0.2] Section 4.4.2 page 201 + // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of + // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated. + if (renderbuffer != 0) + { + if (!context->getRenderbuffer(renderbuffer)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + return true; +} + +static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) +{ + if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || + dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() || + srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight()) + { + return true; + } + else if (context->getState().isScissorTestEnabled()) + { + const Rectangle &scissor = context->getState().getScissor(); + + return scissor.x > 0 || scissor.y > 0 || + scissor.width < writeBuffer->getWidth() || + scissor.height < writeBuffer->getHeight(); + } + else + { + return false; + } +} + +bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, + GLenum filter, bool fromAngleExtension) +{ + switch (filter) + { + case GL_NEAREST: + break; + case GL_LINEAR: + if (fromAngleExtension) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + default: + return gl::error(GL_INVALID_ENUM, false); + } + + if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (mask == 0) + { + // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no + // buffers are copied. + return false; + } + + if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)) + { + ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation."); + return gl::error(GL_INVALID_OPERATION, false); + } + + // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the + // color buffer, leaving only nearest being unfiltered from above + if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id()) + { + if (fromAngleExtension) + { + ERR("Blits with the same source and destination framebuffer are not supported by this " + "implementation."); + } + return gl::error(GL_INVALID_OPERATION, false); + } + + gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); + gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer(); + if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE || + !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); + } + + if (drawFramebuffer->getSamples() != 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1; + + if (mask & GL_COLOR_BUFFER_BIT) + { + gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer(); + gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer(); + + if (readColorBuffer && drawColorBuffer) + { + GLenum readInternalFormat = readColorBuffer->getActualFormat(); + GLenum readComponentType = gl::GetComponentType(readInternalFormat); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++) + { + if (drawFramebuffer->isEnabledColorAttachment(i)) + { + GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat(); + GLenum drawComponentType = gl::GetComponentType(drawInternalFormat); + + // The GL ES 3.0.2 spec (pg 193) states that: + // 1) If the read buffer is fixed point format, the draw buffer must be as well + // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well + // 3) If the read buffer is a signed integer format, the draw buffer must be as well + if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) && + !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (readComponentType == GL_INT && drawComponentType != GL_INT) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + } + + if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (fromAngleExtension) + { + const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType(); + if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) + { + if (drawFramebuffer->isEnabledColorAttachment(colorAttachment)) + { + FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment); + ASSERT(attachment); + + if (attachment->type() != GL_TEXTURE_2D && attachment->type() != GL_RENDERBUFFER) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (attachment->getActualFormat() != readColorBuffer->getActualFormat()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + } + if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer, + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + } + } + + if (mask & GL_DEPTH_BUFFER_BIT) + { + gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer(); + gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer(); + + if (readDepthBuffer && drawDepthBuffer) + { + if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (readDepthBuffer->getSamples() > 0 && !sameBounds) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (fromAngleExtension) + { + if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer, + srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) + { + ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); + return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted + } + + if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + } + } + + if (mask & GL_STENCIL_BUFFER_BIT) + { + gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer(); + gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer(); + + if (readStencilBuffer && drawStencilBuffer) + { + if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (readStencilBuffer->getSamples() > 0 && !sameBounds) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (fromAngleExtension) + { + if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer, + srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) + { + ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); + return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted + } + + if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + } + } + + return true; +} + +bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion) +{ + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + case GL_CURRENT_VERTEX_ATTRIB: + return true; + + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses + // the same constant. + META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE); + return true; + + case GL_VERTEX_ATTRIB_ARRAY_INTEGER: + return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false)); + + default: + return gl::error(GL_INVALID_ENUM, false); + } +} + +bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param) +{ + switch (pname) + { + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + + default: break; + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + switch (param) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: + return true; + default: + return gl::error(GL_INVALID_ENUM, false); + } + + case GL_TEXTURE_MIN_FILTER: + switch (param) + { + case GL_NEAREST: + case GL_LINEAR: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + return true; + default: + return gl::error(GL_INVALID_ENUM, false); + } + break; + + case GL_TEXTURE_MAG_FILTER: + switch (param) + { + case GL_NEAREST: + case GL_LINEAR: + return true; + default: + return gl::error(GL_INVALID_ENUM, false); + } + break; + + case GL_TEXTURE_USAGE_ANGLE: + switch (param) + { + case GL_NONE: + case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: + return true; + default: + return gl::error(GL_INVALID_ENUM, false); + } + break; + + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->getExtensions().textureFilterAnisotropic) + { + return gl::error(GL_INVALID_ENUM, false); + } + + // we assume the parameter passed to this validation method is truncated, not rounded + if (param < 1) + { + return gl::error(GL_INVALID_VALUE, false); + } + return true; + + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + // any value is permissible + return true; + + case GL_TEXTURE_COMPARE_MODE: + // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17 + switch (param) + { + case GL_NONE: + case GL_COMPARE_REF_TO_TEXTURE: + return true; + default: + return gl::error(GL_INVALID_ENUM, false); + } + break; + + case GL_TEXTURE_COMPARE_FUNC: + // Acceptable function parameters from GLES 3.0.2 spec, table 3.17 + switch (param) + { + case GL_LEQUAL: + case GL_GEQUAL: + case GL_LESS: + case GL_GREATER: + case GL_EQUAL: + case GL_NOTEQUAL: + case GL_ALWAYS: + case GL_NEVER: + return true; + default: + return gl::error(GL_INVALID_ENUM, false); + } + break; + + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + switch (param) + { + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_ZERO: + case GL_ONE: + return true; + default: + return gl::error(GL_INVALID_ENUM, false); + } + break; + + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + if (param < 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + return true; + + default: + return gl::error(GL_INVALID_ENUM, false); + } +} + +bool ValidateSamplerObjectParameter(GLenum pname) +{ + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + return true; + + default: + return gl::error(GL_INVALID_ENUM, false); + } +} + +bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels) +{ + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + ASSERT(framebuffer); + + if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); + } + + if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (!framebuffer->getReadColorbuffer()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + GLenum currentInternalFormat, currentFormat, currentType; + GLuint clientVersion = context->getClientVersion(); + + context->getCurrentReadFormatType(¤tInternalFormat, ¤tFormat, ¤tType); + + bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) : + ValidES3ReadFormatType(context, currentInternalFormat, format, type); + + if (!(currentFormat == format && currentType == type) && !validReadFormat) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format + : GetSizedInternalFormat(format, type); + + GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, width, context->getState().getPackAlignment()); + // sized query sanity check + if (bufSize) + { + int requiredSize = outputPitch * height; + if (requiredSize > *bufSize) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + return true; +} + +bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id) +{ + if (!ValidQueryType(context, target)) + { + return gl::error(GL_INVALID_ENUM, false); + } + + if (id == 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id> + // of zero, if the active query object name for <target> is non-zero (for the + // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if + // the active query for either target is non-zero), if <id> is the name of an + // existing query object whose type does not match <target>, or if <id> is the + // active query object name for any query type, the error INVALID_OPERATION is + // generated. + + // Ensure no other queries are active + // NOTE: If other queries than occlusion are supported, we will need to check + // separately that: + // a) The query ID passed is not the current active query for any target/type + // b) There are no active queries for the requested target (and in the case + // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, + // no query may be active for either if glBeginQuery targets either. + if (context->getState().isQueryActive()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + Query *queryObject = context->getQuery(id, true, target); + + // check that name was obtained with glGenQueries + if (!queryObject) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + // check for type mismatch + if (queryObject->getType() != target) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + return true; +} + +bool ValidateEndQuery(gl::Context *context, GLenum target) +{ + if (!ValidQueryType(context, target)) + { + return gl::error(GL_INVALID_ENUM, false); + } + + const Query *queryObject = context->getState().getActiveQuery(target); + + if (queryObject == NULL) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (!queryObject->isStarted()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + return true; +} + +static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType, + GLint location, GLsizei count, LinkedUniform **uniformOut) +{ + if (count < 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + if (!programBinary) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (location == -1) + { + // Silently ignore the uniform command + return false; + } + + if (!programBinary->isValidUniformLocation(location)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + LinkedUniform *uniform = programBinary->getUniformByLocation(location); + + // attempting to write an array to a non-array uniform is an INVALID_OPERATION + if (uniform->elementCount() == 1 && count > 1) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + *uniformOut = uniform; + return true; +} + +bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count) +{ + // Check for ES3 uniform entry points + if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + LinkedUniform *uniform = NULL; + if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform)) + { + return false; + } + + GLenum targetBoolType = VariableBoolVectorType(uniformType); + bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT); + if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + return true; +} + +bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count, + GLboolean transpose) +{ + // Check for ES3 uniform entry points + int rows = VariableRowCount(matrixType); + int cols = VariableColumnCount(matrixType); + if (rows != cols && context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (transpose != GL_FALSE && context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_VALUE, false); + } + + LinkedUniform *uniform = NULL; + if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform)) + { + return false; + } + + if (uniform->type != matrixType) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + return true; +} + +bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams) +{ + if (!context->getQueryParameterInfo(pname, nativeType, numParams)) + { + return gl::error(GL_INVALID_ENUM, false); + } + + if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15) + { + unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0); + + if (colorAttachment >= context->getCaps().maxDrawBuffers) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + switch (pname) + { + case GL_TEXTURE_BINDING_2D: + case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_TEXTURE_BINDING_3D: + case GL_TEXTURE_BINDING_2D_ARRAY: + if (context->getState().getActiveSampler() >= context->getMaximumCombinedTextureImageUnits()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + { + Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + ASSERT(framebuffer); + if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); + if (!attachment) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + break; + + default: + break; + } + + // pname is valid, but there are no parameters to return + if (numParams == 0) + { + return false; + } + + return true; +} + +bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border, GLenum *textureFormatOut) +{ + + if (!ValidTexture2DDestinationTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM, false); + } + + if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (border != 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (!ValidMipLevel(context, target, level)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); + } + + if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + const gl::Caps &caps = context->getCaps(); + + gl::Texture *texture = NULL; + GLenum textureInternalFormat = GL_NONE; + bool textureCompressed = false; + bool textureIsDepth = false; + GLint textureLevelWidth = 0; + GLint textureLevelHeight = 0; + GLint textureLevelDepth = 0; + GLuint maxDimension = 0; + + switch (target) + { + case GL_TEXTURE_2D: + { + gl::Texture2D *texture2d = context->getTexture2D(); + if (texture2d) + { + textureInternalFormat = texture2d->getInternalFormat(level); + textureCompressed = texture2d->isCompressed(level); + textureIsDepth = texture2d->isDepth(level); + textureLevelWidth = texture2d->getWidth(level); + textureLevelHeight = texture2d->getHeight(level); + textureLevelDepth = 1; + texture = texture2d; + maxDimension = caps.max2DTextureSize; + } + } + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + { + gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); + if (textureCube) + { + textureInternalFormat = textureCube->getInternalFormat(target, level); + textureCompressed = textureCube->isCompressed(target, level); + textureIsDepth = false; + textureLevelWidth = textureCube->getWidth(target, level); + textureLevelHeight = textureCube->getHeight(target, level); + textureLevelDepth = 1; + texture = textureCube; + maxDimension = caps.maxCubeMapTextureSize; + } + } + break; + + case GL_TEXTURE_2D_ARRAY: + { + gl::Texture2DArray *texture2dArray = context->getTexture2DArray(); + if (texture2dArray) + { + textureInternalFormat = texture2dArray->getInternalFormat(level); + textureCompressed = texture2dArray->isCompressed(level); + textureIsDepth = texture2dArray->isDepth(level); + textureLevelWidth = texture2dArray->getWidth(level); + textureLevelHeight = texture2dArray->getHeight(level); + textureLevelDepth = texture2dArray->getLayers(level); + texture = texture2dArray; + maxDimension = caps.max2DTextureSize; + } + } + break; + + case GL_TEXTURE_3D: + { + gl::Texture3D *texture3d = context->getTexture3D(); + if (texture3d) + { + textureInternalFormat = texture3d->getInternalFormat(level); + textureCompressed = texture3d->isCompressed(level); + textureIsDepth = texture3d->isDepth(level); + textureLevelWidth = texture3d->getWidth(level); + textureLevelHeight = texture3d->getHeight(level); + textureLevelDepth = texture3d->getDepth(level); + texture = texture3d; + maxDimension = caps.max3DTextureSize; + } + } + break; + + default: + return gl::error(GL_INVALID_ENUM, false); + } + + if (!texture) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (texture->isImmutable() && !isSubImage) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (textureIsDepth) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (textureCompressed) + { + GLint blockWidth = GetCompressedBlockWidth(textureInternalFormat); + GLint blockHeight = GetCompressedBlockHeight(textureInternalFormat); + + if (((width % blockWidth) != 0 && width != textureLevelWidth) || + ((height % blockHeight) != 0 && height != textureLevelHeight)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + if (isSubImage) + { + if (xoffset + width > textureLevelWidth || + yoffset + height > textureLevelHeight || + zoffset >= textureLevelDepth) + { + return gl::error(GL_INVALID_VALUE, false); + } + } + else + { + if (IsCubemapTextureTarget(target) && width != height) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (!IsValidInternalFormat(internalformat, context->getExtensions(), context->getClientVersion())) + { + return gl::error(GL_INVALID_ENUM, false); + } + + int maxLevelDimension = (maxDimension >> level); + if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension) + { + return gl::error(GL_INVALID_VALUE, false); + } + } + + *textureFormatOut = textureInternalFormat; + return true; +} + +static bool ValidateDrawBase(const gl::Context *context, GLenum mode, GLsizei count) +{ + switch (mode) + { + case GL_POINTS: + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + case GL_TRIANGLES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + break; + default: + return gl::error(GL_INVALID_ENUM, false); + } + + if (count < 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + // Check for mapped buffers + if (context->hasMappedBuffer(GL_ARRAY_BUFFER)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + const gl::DepthStencilState &depthStencilState = context->getState().getDepthStencilState(); + if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask || + context->getState().getStencilRef() != context->getState().getStencilBackRef() || + depthStencilState.stencilMask != depthStencilState.stencilBackMask) + { + // Note: these separate values are not supported in WebGL, due to D3D's limitations. + // See Section 6.10 of the WebGL 1.0 spec + ERR("This ANGLE implementation does not support separate front/back stencil " + "writemasks, reference values, or stencil mask values."); + return gl::error(GL_INVALID_OPERATION, false); + } + + const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer(); + if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); + } + + if (context->getState().getCurrentProgramId() == 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); + if (!programBinary->validateSamplers(NULL)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + // No-op if zero count + return (count > 0); +} + +bool ValidateDrawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count) +{ + if (first < 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + gl::TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() && + curTransformFeedback->getDrawMode() != mode) + { + // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode + // that does not match the current transform feedback object's draw mode (if transform feedback + // is active), (3.0.2, section 2.14, pg 86) + return gl::error(GL_INVALID_OPERATION, false); + } + + if (!ValidateDrawBase(context, mode, count)) + { + return false; + } + + return true; +} + +bool ValidateDrawArraysInstanced(const gl::Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + if (primcount < 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (!ValidateDrawArrays(context, mode, first, count)) + { + return false; + } + + // No-op if zero primitive count + return (primcount > 0); +} + +bool ValidateDrawElements(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + break; + case GL_UNSIGNED_INT: + if (!context->getExtensions().elementIndexUint) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + default: + return gl::error(GL_INVALID_ENUM, false); + } + + gl::TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) + { + // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced + // while transform feedback is active, (3.0.2, section 2.14, pg 86) + return gl::error(GL_INVALID_OPERATION, false); + } + + // Check for mapped buffers + if (context->hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + gl::VertexArray *vao = context->getState().getVertexArray(); + if (!indices && !vao->getElementArrayBuffer()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (!ValidateDrawBase(context, mode, count)) + { + return false; + } + + return true; +} + +bool ValidateDrawElementsInstanced(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei primcount) +{ + if (primcount < 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (!ValidateDrawElements(context, mode, count, type, indices)) + { + return false; + } + + // No-op zero primitive count + return (primcount > 0); +} + +bool ValidateFramebufferTextureBase(const gl::Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level) +{ + if (!ValidFramebufferTarget(target)) + { + return gl::error(GL_INVALID_ENUM, false); + } + + if (!ValidateAttachmentTarget(context, attachment)) + { + return false; + } + + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + + if (tex == NULL) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (level < 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + } + + const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id(); + + if (framebufferHandle == 0 || !framebuffer) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + return true; +} + +bool ValidateFramebufferTexture2D(const gl::Context *context, GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + // Attachments are required to be bound to level 0 in ES2 + if (context->getClientVersion() < 3 && level != 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + { + return false; + } + + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + ASSERT(tex); + + const gl::Caps &caps = context->getCaps(); + + switch (textarget) + { + case GL_TEXTURE_2D: + { + if (level > gl::log2(caps.max2DTextureSize)) + { + return gl::error(GL_INVALID_VALUE, false); + } + if (tex->getTarget() != GL_TEXTURE_2D) + { + return gl::error(GL_INVALID_OPERATION, false); + } + gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex); + if (tex2d->isCompressed(level)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + { + if (level > gl::log2(caps.maxCubeMapTextureSize)) + { + return gl::error(GL_INVALID_VALUE, false); + } + if (tex->getTarget() != GL_TEXTURE_CUBE_MAP) + { + return gl::error(GL_INVALID_OPERATION, false); + } + gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex); + if (texcube->isCompressed(textarget, level)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + break; + + default: + return gl::error(GL_INVALID_ENUM, false); + } + } + + return true; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/validationES.h b/src/3rdparty/angle/src/libGLESv2/validationES.h new file mode 100644 index 0000000000..849df36588 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/validationES.h @@ -0,0 +1,75 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES.h: Validation functions for generic OpenGL ES entry point parameters + +#ifndef LIBGLESV2_VALIDATION_ES_H +#define LIBGLESV2_VALIDATION_ES_H + +namespace gl +{ + +class Context; + +bool ValidCap(const Context *context, GLenum cap); +bool ValidTextureTarget(const Context *context, GLenum target); +bool ValidTexture2DDestinationTarget(const Context *context, GLenum target); +bool ValidFramebufferTarget(GLenum target); +bool ValidBufferTarget(const Context *context, GLenum target); +bool ValidBufferParameter(const Context *context, GLenum pname); +bool ValidMipLevel(const Context *context, GLenum target, GLint level); +bool ValidImageSize(const gl::Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth); +bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height); +bool ValidQueryType(const gl::Context *context, GLenum queryType); +bool ValidProgram(const gl::Context *context, GLuint id); + +bool ValidateAttachmentTarget(const gl::Context *context, GLenum attachment); +bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height, + bool angleExtension); +bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment, + GLenum renderbuffertarget, GLuint renderbuffer); + +bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, + GLenum filter, bool fromAngleExtension); + +bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion); + +bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param); + +bool ValidateSamplerObjectParameter(GLenum pname); + +bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels); + +bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id); +bool ValidateEndQuery(gl::Context *context, GLenum target); + +bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count); +bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count, + GLboolean transpose); + +bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams); + +bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border, GLenum *textureInternalFormatOut); + +bool ValidateDrawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count); +bool ValidateDrawArraysInstanced(const gl::Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); +bool ValidateDrawElements(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); +bool ValidateDrawElementsInstanced(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei primcount); + +bool ValidateFramebufferTextureBase(const gl::Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level); +bool ValidateFramebufferTexture2D(const gl::Context *context, GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level); + +} + +#endif // LIBGLESV2_VALIDATION_ES_H diff --git a/src/3rdparty/angle/src/libGLESv2/validationES2.cpp b/src/3rdparty/angle/src/libGLESv2/validationES2.cpp new file mode 100644 index 0000000000..1a09400322 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/validationES2.cpp @@ -0,0 +1,892 @@ +#include "precompiled.h" +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES2.cpp: Validation functions for OpenGL ES 2.0 entry point parameters + +#include "libGLESv2/validationES2.h" +#include "libGLESv2/validationES.h" +#include "libGLESv2/Context.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/main.h" +#include "libGLESv2/FramebufferAttachment.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace gl +{ + +static bool validateSubImageParams2D(bool compressed, GLsizei width, GLsizei height, + GLint xoffset, GLint yoffset, GLint level, GLenum format, GLenum type, + gl::Texture2D *texture) +{ + if (!texture) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (compressed != texture->isCompressed(level)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (format != GL_NONE) + { + GLenum internalformat = gl::GetSizedInternalFormat(format, type); + if (internalformat != texture->getInternalFormat(level)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + if (compressed) + { + if ((width % 4 != 0 && width != texture->getWidth(level)) || + (height % 4 != 0 && height != texture->getHeight(level))) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + if (xoffset + width > texture->getWidth(level) || + yoffset + height > texture->getHeight(level)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + return true; +} + +static bool validateSubImageParamsCube(bool compressed, GLsizei width, GLsizei height, + GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, GLenum type, + gl::TextureCubeMap *texture) +{ + if (!texture) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (compressed != texture->isCompressed(target, level)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (format != GL_NONE) + { + GLenum internalformat = gl::GetSizedInternalFormat(format, type); + if (internalformat != texture->getInternalFormat(target, level)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + if (compressed) + { + if ((width % 4 != 0 && width != texture->getWidth(target, 0)) || + (height % 4 != 0 && height != texture->getHeight(target, 0))) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + if (xoffset + width > texture->getWidth(target, level) || + yoffset + height > texture->getHeight(target, level)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + return true; +} + +bool ValidateES2TexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + if (!ValidTexture2DDestinationTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM, false); + } + + if (!ValidImageSize(context, target, level, width, height, 1)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (level < 0 || xoffset < 0 || + std::numeric_limits<GLsizei>::max() - xoffset < width || + std::numeric_limits<GLsizei>::max() - yoffset < height) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (!isSubImage && !isCompressed && internalformat != format) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + const gl::Caps &caps = context->getCaps(); + + gl::Texture *texture = NULL; + bool textureCompressed = false; + GLenum textureInternalFormat = GL_NONE; + GLint textureLevelWidth = 0; + GLint textureLevelHeight = 0; + switch (target) + { + case GL_TEXTURE_2D: + { + if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) || + static_cast<GLuint>(height) > (caps.max2DTextureSize >> level)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + gl::Texture2D *tex2d = context->getTexture2D(); + if (tex2d) + { + textureCompressed = tex2d->isCompressed(level); + textureInternalFormat = tex2d->getInternalFormat(level); + textureLevelWidth = tex2d->getWidth(level); + textureLevelHeight = tex2d->getHeight(level); + texture = tex2d; + } + + if (isSubImage && !validateSubImageParams2D(isCompressed, width, height, xoffset, yoffset, + level, format, type, tex2d)) + { + return false; + } + + texture = tex2d; + } + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + { + if (!isSubImage && width != height) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (static_cast<GLuint>(width) > (caps.maxCubeMapTextureSize >> level) || + static_cast<GLuint>(height) > (caps.maxCubeMapTextureSize >> level)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + gl::TextureCubeMap *texCube = context->getTextureCubeMap(); + if (texCube) + { + textureCompressed = texCube->isCompressed(target, level); + textureInternalFormat = texCube->getInternalFormat(target, level); + textureLevelWidth = texCube->getWidth(target, level); + textureLevelHeight = texCube->getHeight(target, level); + texture = texCube; + } + + if (isSubImage && !validateSubImageParamsCube(isCompressed, width, height, xoffset, yoffset, + target, level, format, type, texCube)) + { + return false; + } + } + break; + + default: + return gl::error(GL_INVALID_ENUM, false); + } + + if (!texture) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (!isSubImage && texture->isImmutable()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + // Verify zero border + if (border != 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat; + if (isCompressed) + { + if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + switch (actualInternalFormat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->getExtensions().textureCompressionDXT1) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->getExtensions().textureCompressionDXT1) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->getExtensions().textureCompressionDXT5) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + default: + return gl::error(GL_INVALID_ENUM, false); + } + } + else + { + // validate <type> by itself (used as secondary key below) + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_24_8_OES: + case GL_HALF_FLOAT_OES: + case GL_FLOAT: + break; + default: + return gl::error(GL_INVALID_ENUM, false); + } + + // validate <format> + <type> combinations + // - invalid <format> -> sets INVALID_ENUM + // - invalid <format>+<type> combination -> sets INVALID_OPERATION + switch (format) + { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_RED: + case GL_RG: + if (!context->getExtensions().textureRG) + { + return gl::error(GL_INVALID_ENUM, false); + } + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_SRGB_EXT: + case GL_SRGB_ALPHA_EXT: + if (!context->getExtensions().sRGB) + { + return gl::error(GL_INVALID_ENUM, false); + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + break; + case GL_DEPTH_COMPONENT: + switch (type) + { + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + break; + default: + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_DEPTH_STENCIL_OES: + switch (type) + { + case GL_UNSIGNED_INT_24_8_OES: + break; + default: + return gl::error(GL_INVALID_OPERATION, false); + } + break; + default: + return gl::error(GL_INVALID_ENUM, false); + } + + switch (format) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->getExtensions().textureCompressionDXT1) + { + return gl::error(GL_INVALID_OPERATION, false); + } + else + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->getExtensions().textureCompressionDXT3) + { + return gl::error(GL_INVALID_OPERATION, false); + } + else + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->getExtensions().textureCompressionDXT5) + { + return gl::error(GL_INVALID_OPERATION, false); + } + else + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + if (!context->getExtensions().depthTextures) + { + return gl::error(GL_INVALID_VALUE, false); + } + if (target != GL_TEXTURE_2D) + { + return gl::error(GL_INVALID_OPERATION, false); + } + // OES_depth_texture supports loading depth data and multiple levels, + // but ANGLE_depth_texture does not + if (pixels != NULL || level != 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + default: + break; + } + + if (type == GL_FLOAT) + { + if (!context->getExtensions().textureFloat) + { + return gl::error(GL_INVALID_ENUM, false); + } + } + else if (type == GL_HALF_FLOAT_OES) + { + if (!context->getExtensions().textureHalfFloat) + { + return gl::error(GL_INVALID_ENUM, false); + } + } + } + + return true; +} + + + +bool ValidateES2CopyTexImageParameters(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border) +{ + GLenum textureInternalFormat = GL_NONE; + + if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, + xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat)) + { + return false; + } + + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat(); + GLenum textureFormat = gl::GetFormat(textureInternalFormat); + + // [OpenGL ES 2.0.24] table 3.9 + if (isSubImage) + { + switch (textureFormat) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_LUMINANCE: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_RED_EXT: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_RG_EXT: + if (colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return gl::error(GL_INVALID_OPERATION, false); + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + return gl::error(GL_INVALID_OPERATION, false); + default: + return gl::error(GL_INVALID_OPERATION, false); + } + } + else + { + switch (internalformat) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_LUMINANCE: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_RED_EXT: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_RG_EXT: + if (colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->getExtensions().textureCompressionDXT1) + { + return gl::error(GL_INVALID_OPERATION, false); + } + else + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->getExtensions().textureCompressionDXT3) + { + return gl::error(GL_INVALID_OPERATION, false); + } + else + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->getExtensions().textureCompressionDXT5) + { + return gl::error(GL_INVALID_OPERATION, false); + } + else + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH_STENCIL_OES: + case GL_DEPTH24_STENCIL8_OES: + if (context->getExtensions().depthTextures) + { + return gl::error(GL_INVALID_OPERATION, false); + } + else + { + return gl::error(GL_INVALID_ENUM, false); + } + default: + return gl::error(GL_INVALID_ENUM, false); + } + } + + // If width or height is zero, it is a no-op. Return false without setting an error. + return (width > 0 && height > 0); +} + +bool ValidateES2TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height) +{ + if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) + { + return gl::error(GL_INVALID_ENUM, false); + } + + if (width < 1 || height < 1 || levels < 1) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (target == GL_TEXTURE_CUBE_MAP && width != height) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + GLenum format = gl::GetFormat(internalformat); + GLenum type = gl::GetType(internalformat); + + if (format == GL_NONE || type == GL_NONE) + { + return gl::error(GL_INVALID_ENUM, false); + } + + const gl::Caps &caps = context->getCaps(); + + switch (target) + { + case GL_TEXTURE_2D: + if (static_cast<GLuint>(width) > caps.max2DTextureSize || + static_cast<GLuint>(height) > caps.max2DTextureSize) + { + return gl::error(GL_INVALID_VALUE, false); + } + break; + case GL_TEXTURE_CUBE_MAP: + if (static_cast<GLuint>(width) > caps.maxCubeMapTextureSize || + static_cast<GLuint>(height) > caps.maxCubeMapTextureSize) + { + return gl::error(GL_INVALID_VALUE, false); + } + break; + default: + return gl::error(GL_INVALID_ENUM, false); + } + + if (levels != 1 && !context->getExtensions().textureNPOT) + { + if (!gl::isPow2(width) || !gl::isPow2(height)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + switch (internalformat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->getExtensions().textureCompressionDXT1) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->getExtensions().textureCompressionDXT3) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->getExtensions().textureCompressionDXT5) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_RGBA32F_EXT: + case GL_RGB32F_EXT: + case GL_ALPHA32F_EXT: + case GL_LUMINANCE32F_EXT: + case GL_LUMINANCE_ALPHA32F_EXT: + if (!context->getExtensions().textureFloat) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_RGBA16F_EXT: + case GL_RGB16F_EXT: + case GL_ALPHA16F_EXT: + case GL_LUMINANCE16F_EXT: + case GL_LUMINANCE_ALPHA16F_EXT: + if (!context->getExtensions().textureHalfFloat) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_R8_EXT: + case GL_RG8_EXT: + case GL_R16F_EXT: + case GL_RG16F_EXT: + case GL_R32F_EXT: + case GL_RG32F_EXT: + if (!context->getExtensions().textureRG) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH24_STENCIL8_OES: + if (!context->getExtensions().depthTextures) + { + return gl::error(GL_INVALID_ENUM, false); + } + if (target != GL_TEXTURE_2D) + { + return gl::error(GL_INVALID_OPERATION, false); + } + // ANGLE_depth_texture only supports 1-level textures + if (levels != 1) + { + return gl::error(GL_INVALID_OPERATION, false); + } + break; + default: + break; + } + + gl::Texture *texture = NULL; + switch(target) + { + case GL_TEXTURE_2D: + texture = context->getTexture2D(); + break; + case GL_TEXTURE_CUBE_MAP: + texture = context->getTextureCubeMap(); + break; + default: + UNREACHABLE(); + } + + if (!texture || texture->id() == 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (texture->isImmutable()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + return true; +} + +// check for combinations of format and type that are valid for ReadPixels +bool ValidES2ReadFormatType(gl::Context *context, GLenum format, GLenum type) +{ + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + break; + default: + return false; + } + break; + case GL_RG_EXT: + case GL_RED_EXT: + if (!context->getExtensions().textureRG) + { + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; + + default: + return false; + } + return true; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/validationES2.h b/src/3rdparty/angle/src/libGLESv2/validationES2.h new file mode 100644 index 0000000000..e41e345876 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/validationES2.h @@ -0,0 +1,32 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES2.h: Validation functions for OpenGL ES 2.0 entry point parameters + +#ifndef LIBGLESV2_VALIDATION_ES2_H +#define LIBGLESV2_VALIDATION_ES2_H + +namespace gl +{ + +class Context; + +bool ValidateES2TexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const GLvoid *pixels); + +bool ValidateES2CopyTexImageParameters(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border); + +bool ValidateES2TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height); + +bool ValidES2ReadFormatType(gl::Context *context, GLenum format, GLenum type); + +} + +#endif // LIBGLESV2_VALIDATION_ES2_H diff --git a/src/3rdparty/angle/src/libGLESv2/validationES3.cpp b/src/3rdparty/angle/src/libGLESv2/validationES3.cpp new file mode 100644 index 0000000000..a584a7127b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/validationES3.cpp @@ -0,0 +1,682 @@ +#include "precompiled.h" +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters + +#include "libGLESv2/validationES3.h" +#include "libGLESv2/validationES.h" +#include "libGLESv2/Context.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/main.h" +#include "libGLESv2/FramebufferAttachment.h" + +#include "common/mathutil.h" + +namespace gl +{ + +bool ValidateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + if (!ValidTexture2DDestinationTarget(context, target)) + { + return gl::error(GL_INVALID_ENUM, false); + } + + // Validate image size + if (!ValidImageSize(context, target, level, width, height, depth)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + // Verify zero border + if (border != 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (xoffset < 0 || yoffset < 0 || zoffset < 0 || + std::numeric_limits<GLsizei>::max() - xoffset < width || + std::numeric_limits<GLsizei>::max() - yoffset < height || + std::numeric_limits<GLsizei>::max() - zoffset < depth) + { + return gl::error(GL_INVALID_VALUE, false); + } + + const gl::Caps &caps = context->getCaps(); + + gl::Texture *texture = NULL; + bool textureCompressed = false; + GLenum textureInternalFormat = GL_NONE; + GLint textureLevelWidth = 0; + GLint textureLevelHeight = 0; + GLint textureLevelDepth = 0; + switch (target) + { + case GL_TEXTURE_2D: + { + if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) || + static_cast<GLuint>(height) > (caps.max2DTextureSize >> level)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + gl::Texture2D *texture2d = context->getTexture2D(); + if (texture2d) + { + textureCompressed = texture2d->isCompressed(level); + textureInternalFormat = texture2d->getInternalFormat(level); + textureLevelWidth = texture2d->getWidth(level); + textureLevelHeight = texture2d->getHeight(level); + textureLevelDepth = 1; + texture = texture2d; + } + } + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + { + if (!isSubImage && width != height) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (static_cast<GLuint>(width) > (caps.maxCubeMapTextureSize >> level)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); + if (textureCube) + { + textureCompressed = textureCube->isCompressed(target, level); + textureInternalFormat = textureCube->getInternalFormat(target, level); + textureLevelWidth = textureCube->getWidth(target, level); + textureLevelHeight = textureCube->getHeight(target, level); + textureLevelDepth = 1; + texture = textureCube; + } + } + break; + + case GL_TEXTURE_3D: + { + if (static_cast<GLuint>(width) > (caps.max3DTextureSize >> level) || + static_cast<GLuint>(height) > (caps.max3DTextureSize >> level) || + static_cast<GLuint>(depth) > (caps.max3DTextureSize >> level)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + gl::Texture3D *texture3d = context->getTexture3D(); + if (texture3d) + { + textureCompressed = texture3d->isCompressed(level); + textureInternalFormat = texture3d->getInternalFormat(level); + textureLevelWidth = texture3d->getWidth(level); + textureLevelHeight = texture3d->getHeight(level); + textureLevelDepth = texture3d->getDepth(level); + texture = texture3d; + } + } + break; + + case GL_TEXTURE_2D_ARRAY: + { + if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) || + static_cast<GLuint>(height) > (caps.max2DTextureSize >> level) || + static_cast<GLuint>(depth) > (caps.maxArrayTextureLayers >> level)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + gl::Texture2DArray *texture2darray = context->getTexture2DArray(); + if (texture2darray) + { + textureCompressed = texture2darray->isCompressed(level); + textureInternalFormat = texture2darray->getInternalFormat(level); + textureLevelWidth = texture2darray->getWidth(level); + textureLevelHeight = texture2darray->getHeight(level); + textureLevelDepth = texture2darray->getLayers(level); + texture = texture2darray; + } + } + break; + + default: + return gl::error(GL_INVALID_ENUM, false); + } + + if (!texture) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (texture->isImmutable() && !isSubImage) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + // Validate texture formats + GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat; + if (isCompressed) + { + if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (!gl::IsFormatCompressed(actualInternalFormat)) + { + return gl::error(GL_INVALID_ENUM, false); + } + + if (target == GL_TEXTURE_3D) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + else + { + // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid + // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d) + if (!gl::IsValidInternalFormat(actualInternalFormat, context->getExtensions(), context->getClientVersion()) || + !gl::IsValidFormat(format, context->getExtensions(), context->getClientVersion()) || + !gl::IsValidType(type, context->getExtensions(), context->getClientVersion())) + { + return gl::error(GL_INVALID_ENUM, false); + } + + if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getExtensions(), context->getClientVersion())) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + // Validate sub image parameters + if (isSubImage) + { + if (isCompressed != textureCompressed) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (isCompressed) + { + if ((width % 4 != 0 && width != textureLevelWidth) || + (height % 4 != 0 && height != textureLevelHeight)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + if (width == 0 || height == 0 || depth == 0) + { + return false; + } + + if (xoffset < 0 || yoffset < 0 || zoffset < 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (std::numeric_limits<GLsizei>::max() - xoffset < width || + std::numeric_limits<GLsizei>::max() - yoffset < height || + std::numeric_limits<GLsizei>::max() - zoffset < depth) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (xoffset + width > textureLevelWidth || + yoffset + height > textureLevelHeight || + zoffset + depth > textureLevelDepth) + { + return gl::error(GL_INVALID_VALUE, false); + } + } + + // Check for pixel unpack buffer related API errors + gl::Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER); + if (pixelUnpackBuffer != NULL) + { + // ...the data would be unpacked from the buffer object such that the memory reads required + // would exceed the data store size. + size_t widthSize = static_cast<size_t>(width); + size_t heightSize = static_cast<size_t>(height); + size_t depthSize = static_cast<size_t>(depth); + GLenum sizedFormat = gl::IsSizedInternalFormat(actualInternalFormat) ? actualInternalFormat + : gl::GetSizedInternalFormat(actualInternalFormat, type); + + size_t pixelBytes = static_cast<size_t>(gl::GetPixelBytes(sizedFormat)); + + if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) || + !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) || + !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes)) + { + // Overflow past the end of the buffer + return gl::error(GL_INVALID_OPERATION, false); + } + + size_t copyBytes = widthSize * heightSize * depthSize * pixelBytes; + size_t offset = reinterpret_cast<size_t>(pixels); + + if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) || + ((offset + copyBytes) > static_cast<size_t>(pixelUnpackBuffer->getSize()))) + { + // Overflow past the end of the buffer + return gl::error(GL_INVALID_OPERATION, false); + } + + // ...data is not evenly divisible into the number of bytes needed to store in memory a datum + // indicated by type. + size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeBytes(type)); + + if ((offset % dataBytesPerPixel) != 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + // ...the buffer object's data store is currently mapped. + if (pixelUnpackBuffer->isMapped()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + return true; +} + +bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, + bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + GLenum textureInternalFormat; + if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, + xoffset, yoffset, zoffset, x, y, width, height, + border, &textureInternalFormat)) + { + return false; + } + + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + + if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); + } + + if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer(); + GLenum colorbufferInternalFormat = source->getInternalFormat(); + + if (isSubImage) + { + if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat, + context->getState().getReadFramebuffer()->id(), + context->getClientVersion())) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + else + { + if (!gl::IsValidCopyTexImageCombination(internalformat, colorbufferInternalFormat, + context->getState().getReadFramebuffer()->id(), + context->getClientVersion())) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + + // If width or height is zero, it is a no-op. Return false without setting an error. + return (width > 0 && height > 0); +} + +bool ValidateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth) +{ + if (width < 1 || height < 1 || depth < 1 || levels < 1) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + const gl::Caps &caps = context->getCaps(); + + gl::Texture *texture = NULL; + switch (target) + { + case GL_TEXTURE_2D: + { + texture = context->getTexture2D(); + + if (static_cast<GLuint>(width) > caps.max2DTextureSize || + static_cast<GLuint>(height) > caps.max2DTextureSize) + { + return gl::error(GL_INVALID_VALUE, false); + } + } + break; + + case GL_TEXTURE_CUBE_MAP: + { + texture = context->getTextureCubeMap(); + + if (width != height) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (static_cast<GLuint>(width) > caps.maxCubeMapTextureSize) + { + return gl::error(GL_INVALID_VALUE, false); + } + } + break; + + case GL_TEXTURE_3D: + { + texture = context->getTexture3D(); + + if (static_cast<GLuint>(width) > caps.max3DTextureSize || + static_cast<GLuint>(height) > caps.max3DTextureSize || + static_cast<GLuint>(depth) > caps.max3DTextureSize) + { + return gl::error(GL_INVALID_VALUE, false); + } + } + break; + + case GL_TEXTURE_2D_ARRAY: + { + texture = context->getTexture2DArray(); + + if (static_cast<GLuint>(width) > caps.max2DTextureSize || + static_cast<GLuint>(height) > caps.max2DTextureSize || + static_cast<GLuint>(depth) > caps.maxArrayTextureLayers) + { + return gl::error(GL_INVALID_VALUE, false); + } + } + break; + + default: + return gl::error(GL_INVALID_ENUM, false); + } + + if (!texture || texture->id() == 0) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (texture->isImmutable()) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (!gl::IsValidInternalFormat(internalformat, context->getExtensions(), context->getClientVersion())) + { + return gl::error(GL_INVALID_ENUM, false); + } + + if (!gl::IsSizedInternalFormat(internalformat)) + { + return gl::error(GL_INVALID_ENUM, false); + } + + return true; +} + +bool ValidateFramebufferTextureLayer(const gl::Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer) +{ + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + if (layer < 0) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + { + return false; + } + + const gl::Caps &caps = context->getCaps(); + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + ASSERT(tex); + + switch (tex->getTarget()) + { + case GL_TEXTURE_2D_ARRAY: + { + if (level > gl::log2(caps.max2DTextureSize)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (static_cast<GLuint>(layer) >= caps.maxArrayTextureLayers) + { + return gl::error(GL_INVALID_VALUE, false); + } + + gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex); + if (texArray->isCompressed(level)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + break; + + case GL_TEXTURE_3D: + { + if (level > gl::log2(caps.max3DTextureSize)) + { + return gl::error(GL_INVALID_VALUE, false); + } + + if (static_cast<GLuint>(layer) >= caps.max3DTextureSize) + { + return gl::error(GL_INVALID_VALUE, false); + } + + gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex); + if (tex3d->isCompressed(level)) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + break; + + default: + return gl::error(GL_INVALID_OPERATION, false); + } + } + + return true; +} + +bool ValidES3ReadFormatType(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type) +{ + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + if (internalFormat != GL_RGB10_A2) + { + return false; + } + break; + case GL_FLOAT: + if (gl::GetComponentType(internalFormat) != GL_FLOAT) + { + return false; + } + break; + default: + return false; + } + break; + case GL_RGBA_INTEGER: + switch (type) + { + case GL_INT: + if (gl::GetComponentType(internalFormat) != GL_INT) + { + return false; + } + break; + case GL_UNSIGNED_INT: + if (gl::GetComponentType(internalFormat) != GL_UNSIGNED_INT) + { + return false; + } + break; + default: + return false; + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + break; + default: + return false; + } + break; + case GL_RG_EXT: + case GL_RED_EXT: + if (!context->getExtensions().textureRG) + { + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; + default: + return false; + } + return true; +} + +bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments, + const GLenum* attachments) +{ + bool defaultFramebuffer = false; + + switch (target) + { + case GL_DRAW_FRAMEBUFFER: + case GL_FRAMEBUFFER: + defaultFramebuffer = context->getState().getDrawFramebuffer()->id() == 0; + break; + case GL_READ_FRAMEBUFFER: + defaultFramebuffer = context->getState().getReadFramebuffer()->id() == 0; + break; + default: + return gl::error(GL_INVALID_ENUM, false); + } + + for (int i = 0; i < numAttachments; ++i) + { + if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) + { + if (defaultFramebuffer) + { + return gl::error(GL_INVALID_ENUM, false); + } + + if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments) + { + return gl::error(GL_INVALID_OPERATION, false); + } + } + else + { + switch (attachments[i]) + { + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + case GL_DEPTH_STENCIL_ATTACHMENT: + if (defaultFramebuffer) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + case GL_COLOR: + case GL_DEPTH: + case GL_STENCIL: + if (!defaultFramebuffer) + { + return gl::error(GL_INVALID_ENUM, false); + } + break; + default: + return gl::error(GL_INVALID_ENUM, false); + } + } + } + + return true; +} + +bool ValidateClearBuffer(const gl::Context *context) +{ + if (context->getClientVersion() < 3) + { + return gl::error(GL_INVALID_OPERATION, false); + } + + const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer(); + if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); + } + + return true; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/validationES3.h b/src/3rdparty/angle/src/libGLESv2/validationES3.h new file mode 100644 index 0000000000..4d068bd094 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/validationES3.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES3.h: Validation functions for OpenGL ES 3.0 entry point parameters + +#ifndef LIBGLESV2_VALIDATION_ES3_H +#define LIBGLESV2_VALIDATION_ES3_H + +namespace gl +{ + +class Context; + +bool ValidateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, const GLvoid *pixels); + +bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, + bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, + GLsizei width, GLsizei height, GLint border); + +bool ValidateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth); + +bool ValidateFramebufferTextureLayer(const gl::Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer); + +bool ValidES3ReadFormatType(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type); + +bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments, + const GLenum* attachments); + +bool ValidateClearBuffer(const gl::Context *context); + +} + +#endif // LIBGLESV2_VALIDATION_ES3_H |