author | Benoit Jacob <bjacob@mozilla.com> |
Sat, 19 Nov 2011 18:18:59 -0500 | |
changeset 82499 | 18e1ab585ad04b7f121a1dedb64d5697e4e18de8 |
parent 82498 | 4c45c9b2cc0c7196d626caeb8c5f23d49228a69a |
child 82500 | 6d1339ba711e2b89ac15c03a9ae77561bea87d12 |
push id | 114 |
push user | ffxbld |
push date | Fri, 09 Mar 2012 01:01:18 +0000 |
treeherder | mozilla-release@c081ebf13261 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 703917 |
milestone | 11.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/angle/README.mozilla +++ b/gfx/angle/README.mozilla @@ -1,11 +1,11 @@ This is the ANGLE project, from http://code.google.com/p/angleproject/ -Current revision: r809 +Current revision: r885 == Applied local patches == In this order: angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error angle-limit-identifiers-to-250-chars.patch - see bug 675625 angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands.
--- a/gfx/angle/angle-intrinsic-msvc2005.patch +++ b/gfx/angle/angle-intrinsic-msvc2005.patch @@ -1,10 +1,10 @@ # HG changeset patch -# Parent b5604c321da4e3b5d6b0a940d18022a827061579 +# Parent d9b887da80f5bc18854fb3e5e43637c18d2a25ae diff --git a/gfx/angle/src/libGLESv2/Texture.cpp b/gfx/angle/src/libGLESv2/Texture.cpp --- a/gfx/angle/src/libGLESv2/Texture.cpp +++ b/gfx/angle/src/libGLESv2/Texture.cpp @@ -8,16 +8,22 @@ // Texture2D and TextureCubeMap. Implements GL texture objects and related // functionality. [OpenGL ES 2.0.24] section 3.7 page 63. #include "libGLESv2/Texture.h"
--- a/gfx/angle/angle-renaming-debug.patch +++ b/gfx/angle/angle-renaming-debug.patch @@ -1,10 +1,10 @@ # HG changeset patch -# Parent 0239f15c7212413b5cffe66aee9ae5a4feb28f16 +# Parent eae39c479485f310e937d8550afc6596aec20159 diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in --- a/gfx/angle/Makefile.in +++ b/gfx/angle/Makefile.in @@ -73,17 +73,17 @@ CPPSRCS = \ parseConst.cpp \ ParseHelper.cpp \ PoolAlloc.cpp \ QualifierAlive.cpp \
--- a/gfx/angle/angle-use-xmalloc.patch +++ b/gfx/angle/angle-use-xmalloc.patch @@ -1,18 +1,18 @@ # HG changeset patch -# Parent fecc64a6df53a9056b21958affad38c80ca38496 +# Parent 85ffde53712cab3c217bbbf0c1ec9b7ec2ae8ea6 diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in --- a/gfx/angle/Makefile.in +++ b/gfx/angle/Makefile.in @@ -127,16 +127,18 @@ CSRCS = \ $(NULL) - DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD + DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD -DCOMPILER_IMPLEMENTATION #these defines are from ANGLE's build_angle.gyp DEFINES += -DANGLE_DISABLE_TRACE DEFINES += -DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0 +EXTRA_DSO_LDOPTS = $(MOZALLOC_LIB) + ifdef MOZ_ANGLE @@ -22,47 +22,33 @@ diff --git a/gfx/angle/Makefile.in b/gfx libs:: expand "$(MOZ_D3DX9_CAB)" -F:$(MOZ_D3DX9_DLL) "$(DIST)/bin" expand "$(MOZ_D3DCOMPILER_CAB)" -F:$(MOZ_D3DCOMPILER_DLL) "$(DIST)/bin" diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla --- a/gfx/angle/README.mozilla +++ b/gfx/angle/README.mozilla @@ -3,16 +3,17 @@ This is the ANGLE project, from http://c - Current revision: r774 + Current revision: r885 == Applied local patches == In this order: - angle-renaming.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles - angle-instrinsic-msvc2005.patch - work around a MSVC 2005 compile error + angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles + angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error angle-limit-identifiers-to-250-chars.patch - see bug 675625 + angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands. In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE. == How to update this ANGLE copy == 1. Unapply patches 2. Apply diff with new ANGLE version 3. Reapply patches. -diff --git a/gfx/angle/angle-limit-identifiers-to-250-chars.patch b/gfx/angle/angle-limit-identifiers-to-250-chars.patch ---- a/gfx/angle/angle-limit-identifiers-to-250-chars.patch -+++ b/gfx/angle/angle-limit-identifiers-to-250-chars.patch -@@ -1,8 +1,10 @@ -+# HG changeset patch -+# Parent f9415c10c3ebd27856500cca7a0ee0f28a16f53c - diff --git a/gfx/angle/src/compiler/preprocessor/scanner.h b/gfx/angle/src/compiler/preprocessor/scanner.h - --- a/gfx/angle/src/compiler/preprocessor/scanner.h - +++ b/gfx/angle/src/compiler/preprocessor/scanner.h - @@ -44,17 +44,19 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILI - // - // scanner.h - // - diff --git a/gfx/angle/src/compiler/preprocessor/atom.c b/gfx/angle/src/compiler/preprocessor/atom.c --- a/gfx/angle/src/compiler/preprocessor/atom.c +++ b/gfx/angle/src/compiler/preprocessor/atom.c @@ -48,16 +48,18 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILI #include <stdlib.h> #include <stdio.h> #include <string.h>
new file mode 100644 --- /dev/null +++ b/gfx/angle/extensions/ANGLE_texture_usage.txt @@ -0,0 +1,202 @@ +Name + + ANGLE_texture_usage + +Name Strings + + GL_ANGLE_texture_usage + +Contributors + + Nicolas Capens, TransGaming + Daniel Koch, TransGaming + +Contact + + Daniel Koch, TransGaming (daniel 'at' transgaming.com) + +Status + + Complete + +Version + + Last Modified Date: November 10, 2011 + Version: 2 + +Number + + TBD + +Dependencies + + This extension is written against the OpenGL ES 2.0 Specification. + +Overview + + In some implementations it is advantageous to know the expected + usage of a texture before the backing storage for it is allocated. + This can help to inform the implementation's choice of format + and type of memory used for the allocation. If the usage is not + known in advance, the implementation essentially has to make a + guess as to how it will be used. If it is later proven wrong, + it may need to perform costly re-allocations and/or reformatting + of the texture data, resulting in reduced performance. + + This extension adds a texture usage flag that is specified via + the TEXTURE_USAGE_ANGLE TexParameter. This can be used to + indicate that the application knows that this texture will be + used for rendering. + +IP Status + + No known IP claims. + +New Procedures and Functions + + None + +New Tokens + + Accepted as a value for <pname> for the TexParameter{if} and + TexParameter{if}v commands and for the <value> parameter of + GetTexParameter{if}v: + + TEXTURE_USAGE_ANGLE 0x93A2 + + Accepted as a value to <param> for the TexParameter{if} and + to <params> for the TexParameter{if}v commands with a <pname> of + TEXTURE_USAGE_ANGLE; returned as possible values for <data> when + GetTexParameter{if}v is queried with a <value> of TEXTURE_USAGE_ANGLE: + + NONE 0x0000 + FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3 + +Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL ES Operation) + + None + +Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization) + + Add a new row to Table 3.10 (Texture parameters and their values): + + Name | Type | Legal Values + ------------------------------------------------------------ + TEXTURE_USAGE_ANGLE | enum | NONE, FRAMEBUFFER_ATTACHMENT_ANGLE + + Add a new section 3.7.x (Texture Usage) before section 3.7.12 and + renumber the subsequent sections: + + "3.7.x Texture Usage + + Texture usage can be specified via the TEXTURE_USAGE_ANGLE value + for the <pname> argument to TexParameter{if}[v]. In order to take effect, + the texture usage must be specified before the texture contents are + defined either via TexImage2D or TexStorage2DEXT. + + The usage values can impact the layout and type of memory used for the + texture data. Specifying incorrect usage values may result in reduced + functionality and/or significantly degraded performance. + + Possible values for <params> when <pname> is TEXTURE_USAGE_ANGLE are: + + NONE - the default. No particular usage has been specified and it is + up to the implementation to determine the usage of the texture. + Leaving the usage unspecified means that the implementation may + have to reallocate the texture data as the texture is used in + various ways. + + FRAMEBUFFER_ATTACHMENT_ANGLE - this texture will be attached to a + framebuffer object and used as a desination for rendering or blits." + + Modify section 3.7.12 (Texture State) and place the last 3 sentences + with the following: + + "Next, there are the three sets of texture properties; each consists of + the selected minification and magnification filters, the wrap modes for + <s> and <t>, and the usage flags. In the initial state, the value assigned + to TEXTURE_MIN_FILTER is NEAREST_MIPMAP_LINEAR, and the value for + TEXTURE_MAG_FILTER is LINEAR. <s> and <t> wrap modes are both set to + REPEAT. The initial value for TEXTURE_USAGE_ANGLE is NONE." + + +Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment +Operations and the Framebuffer) + + None + +Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special +Functions): + + None + +Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and +State Requests) + + None + +Dependencies on EXT_texture_storage + + If EXT_texture_storage is not supported, omit any references to + TexStorage2DEXT. + +Errors + + If TexParameter{if} or TexParamter{if}v is called with a <pname> + of TEXTURE_USAGE_ANGLE and the value of <param> or <params> is not + NONE or FRAMEBUFFER_ATTACHMENT_ANGLE the error INVALID_VALUE is + generated. + +Usage Example + + /* create and bind texture */ + glGenTextures(1, &texture); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture); + + /* specify texture parameters */ + glTexParameteri(GL_TEXTURE_2D, GL_*, ...); /* as before */ + + /* specify that we'll be rendering to the texture */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + + glTexStorage2DEXT(GL_TEXTURE_2D, levels, ...); // Allocation + for(int level = 0; level < levels; ++level) + glTexSubImage2D(GL_TEXTURE_2D, level, ...); // Initialisation + +Issues + + 1. Should there be a dynamic usage value? + + DISCUSSION: We could accept a dynamic flag to indicate that a texture will + be updated frequently. We could map this to D3D9 dynamic textures. This would + allow us to avoid creating temporary surfaces when updating the texture. + However renderable textures cannot be dynamic in D3D9, which eliminates the + primary use case for this. Furthermore, the memory usage of dynamic textures + typically increases threefold when you lock it. + + 2. Should the texture usage be an enum or a bitfield? + + UNRESOLVED. Using a bitfield would allow combination of values to be specified. + On the other hand, if combinations are really required, additional <pnames> + could be added as necessary. Querying a bitfield via the GetTexParameter command + feels a bit odd. + + 3. What should happen if TEXTURE_USAGE_ANGLE is set/changed after the texture + contents have been specified? + + RESOLVED: It will have no effect. However, if the texture is redefined (for + example by TexImage2D) the new allocation will use the updated usage. + GetTexParameter is used to query the value of the TEXTURE_USAGE_ANGLE + state that was last set by TexParameter for the currently bound texture, or + the default value if it has never been set. There is no way to determine the + usage that was in effect at the time the texture was defined. + +Revision History + + Rev. Date Author Changes + ---- ----------- --------- ---------------------------------------- + 1 10 Nov 2011 dgkoch Initial revision + 2 10 Nov 2011 dgkoch Add overview + +
new file mode 100644 --- /dev/null +++ b/gfx/angle/extensions/EGL_EXT_create_context_robustness.txt @@ -0,0 +1,169 @@ +Name + + EXT_create_context_robustness + +Name Strings + + EGL_EXT_create_context_robustness + +Contributors + + Daniel Koch, TransGaming + Contributors to EGL_KHR_create_context + +Contact + + Greg Roth (groth 'at' nvidia.com) + +Status + + Complete. + +Version + + Version 3, 2011/10/31 + +Number + + TBD + +Dependencies + + Requires EGL 1.4 + + Written against the EGL 1.4 specification. + + An OpenGL implementation supporting GL_ARB_robustness, an OpenGL ES + implementation supporting GL_EXT_robustness, or an implementation + supporting equivalent functionality is required. + +Overview + + This extension allows creating an OpenGL or OpenGL ES context + supporting robust buffer access behavior and a specified graphics + reset notification behavior. + +New Procedures and Functions + + None + +New Tokens + + Accepted as an attribute name in the <*attrib_list> argument to + eglCreateContext: + + EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF + EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 + + Accepted as an attribute value for EGL_CONTEXT_RESET_NOTIFICATION_- + STRATEGY_EXT in the <*attrib_list> argument to eglCreateContext: + + EGL_NO_RESET_NOTIFICATION_EXT 0x31BE + EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF + +Additions to the EGL 1.4 Specification + + Replace section 3.7.1 "Creating Rendering Contexts" from the + fifth paragraph through the seventh paragraph: + + <attrib_list> specifies a list of attributes for the context. The + list has the same structure as described for eglChooseConfig. If an + attribute is not specified in <attrib_list>, then the default value + specified below is used instead. <attrib_list> may be NULL or empty + (first attribute is EGL_NONE), in which case attributes assume their + default values as described below. Most attributes are only meaningful + for specific client APIs, and will generate an EGL_BAD_ATTRIBUTE + error when specified to create for another client API context. + + Context Versions + ---------------- + + EGL_CONTEXT_CLIENT_VERSION determines which version of an OpenGL ES + context to create. This attribute may only be specified when creating + an OpenGL ES context (e.g. when the current rendering API is + EGL_OPENGL_ES_API). An attribute value of 1 specifies creation of an + OpenGL ES 1.x context. An attribute value of 2 specifies creation of an + Open GL ES 2.x context. The default value for EGL_CONTEXT_CLIENT_VERSION + is 1. + + Context Robust Access + ------------- + + EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT indicates whether <robust buffer + access> should be enabled for the OpenGL ES context. Robust buffer + access is defined in the GL_EXT_robustness extension specification, + and the resulting context must support GL_EXT_robustness and robust + buffer access as described therein. The default value of + EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT is EGL_FALSE. + + Context Reset Notification + -------------------------- + + The attribute name EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_- + EXT specifies the <reset notification behavior> of the rendering + context. This attribute is only meaningful for OpenGL ES contexts, + and specifying it for other types of contexts will generate an + EGL_BAD_ATTRIBUTE error. + + Reset notification behavior is defined in the GL_EXT_robustness + extension for OpenGL ES, and the resulting context must support + GL_EXT_robustness and the specified reset strategy. The attribute + value may be either EGL_NO_RESET_NOTIFICATION_EXT or EGL_LOSE_- + CONTEXT_ON_RESET_EXT, which respectively result in disabling + delivery of reset notifications or the loss of all context state + upon reset notification as described by the GL_EXT_robustness. The + default value for EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT + is EGL_NO_RESET_NOTIFICATION_EXT. + + Add to the eglCreateContext context creation errors: + + * If <config> does not support a client API context compatible + with the requested context flags and context reset notification + behavior (for client API types where these attributes are + supported), then an EGL_BAD_CONFIG error is generated. + + * If the reset notification behavior of <share_context> and the + newly created context are different then an EGL_BAD_MATCH error is + generated. + + +Errors + + EGL_BAD_CONFIG is generated if EGL_CONTEXT_OPENGL_ROBUST_ACCESS_- + EXT is set to EGL_TRUE and no GL context supporting the GL_EXT_- + robustness extension and robust access as described therein can be + created. + + EGL_BAD_CONFIG is generated if no GL context supporting the + GL_EXT_robustness extension and the specified reset notification + behavior (the value of attribute EGL_CONTEXT_RESET_NOTIFICATION_- + STRATEGY_EXT) can be created. + + BAD_MATCH is generated if the reset notification behavior of + <share_context> does not match the reset notification behavior of + the context being created. + +New State + + None + +Conformance Tests + + TBD + +Sample Code + + TBD + +Issues + + None + +Revision History + + Rev. Date Author Changes + ---- ------------ --------- ---------------------------------------- + 3 31 Oct 2011 groth Reverted to attribute for robust access. Now it's a + companion to rather than subset of KHR_create_context + 2 11 Oct 2011 groth Merged ANGLE and NV extensions. + 1 15 July 2011 groth Initial version
new file mode 100644 --- /dev/null +++ b/gfx/angle/extensions/EXT_robustness.txt @@ -0,0 +1,365 @@ +Name + + EXT_robustness + +Name Strings + + GL_EXT_robustness + +Contributors + + Daniel Koch, TransGaming + Nicolas Capens, TransGaming + Contributors to ARB_robustness + +Contact + + Greg Roth, NVIDIA (groth 'at' nvidia.com) + +Status + + Complete. + +Version + + Version 3, 2011/10/31 + +Number + + TBD + +Dependencies + + This extension is written against the OpenGL ES 2.0 Specification + but can apply to OpenGL ES 1.1 and up. + + EGL_EXT_create_context_robustness is used to determine if a context + implementing this extension supports robust buffer access, and if it + supports reset notification. + +Overview + + Several recent trends in how OpenGL integrates into modern computer + systems have created new requirements for robustness and security + for OpenGL rendering contexts. + + Additionally GPU architectures now support hardware fault detection; + for example, video memory supporting ECC (error correcting codes) + and error detection. OpenGL contexts should be capable of recovering + from hardware faults such as uncorrectable memory errors. Along with + recovery from such hardware faults, the recovery mechanism can + also allow recovery from video memory access exceptions and system + software failures. System software failures can be due to device + changes or driver failures. + + OpenGL queries that that return (write) some number of bytes to a + buffer indicated by a pointer parameter introduce risk of buffer + overflows that might be exploitable by malware. To address this, + queries with return value sizes that are not expressed directly by + the parameters to the query itself are given additional API + functions with an additional parameter that specifies the number of + bytes in the buffer and never writing bytes beyond that limit. This + is particularly useful for multi-threaded usage of OpenGL contexts + in a "share group" where one context can change objects in ways that + can cause buffer overflows for another context's OpenGL queries. + + The original ARB_vertex_buffer_object extension includes an issue + that explicitly states program termination is allowed when + out-of-bounds vertex buffer object fetches occur. Modern graphics + hardware is capable well-defined behavior in the case of out-of- + bounds vertex buffer object fetches. Older hardware may require + extra checks to enforce well-defined (and termination free) + behavior, but this expense is warranted when processing potentially + untrusted content. + + The intent of this extension is to address some specific robustness + goals: + + * For all existing OpenGL queries, provide additional "safe" APIs + that limit data written to user pointers to a buffer size in + bytes that is an explicit additional parameter of the query. + + * Provide a mechanism for an OpenGL application to learn about + graphics resets that affect the context. When a graphics reset + occurs, the OpenGL context becomes unusable and the application + must create a new context to continue operation. Detecting a + graphics reset happens through an inexpensive query. + + * Provide an enable to guarantee that out-of-bounds buffer object + accesses by the GPU will have deterministic behavior and preclude + application instability or termination due to an incorrect buffer + access. Such accesses include vertex buffer fetches of + attributes and indices, and indexed reads of uniforms or + parameters from buffers. + +New Procedures and Functions + + enum GetGraphicsResetStatusEXT(); + + void ReadnPixelsEXT(int x, int y, sizei width, sizei height, + enum format, enum type, sizei bufSize, + void *data); + + void GetnUniformfvEXT(uint program, int location, sizei bufSize, + float *params); + void GetnUniformivEXT(uint program, int location, sizei bufSize, + int *params); + +New Tokens + + Returned by GetGraphicsResetStatusEXT: + + NO_ERROR 0x0000 + GUILTY_CONTEXT_RESET_EXT 0x8253 + INNOCENT_CONTEXT_RESET_EXT 0x8254 + UNKNOWN_CONTEXT_RESET_EXT 0x8255 + + Accepted by the <value> parameter of GetBooleanv, GetIntegerv, + and GetFloatv: + + CONTEXT_ROBUST_ACCESS_EXT 0x90F3 + RESET_NOTIFICATION_STRATEGY_EXT 0x8256 + + Returned by GetIntegerv and related simple queries when <value> is + RESET_NOTIFICATION_STRATEGY_EXT : + + LOSE_CONTEXT_ON_RESET_EXT 0x8252 + NO_RESET_NOTIFICATION_EXT 0x8261 + +Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL ES Operation) + +Add a new subsection after 2.5 "GL Errors" and renumber subsequent +sections accordingly. + + 2.6 "Graphics Reset Recovery" + + Certain events can result in a reset of the GL context. Such a reset + causes all context state to be lost. Recovery from such events + requires recreation of all objects in the affected context. The + current status of the graphics reset state is returned by + + enum GetGraphicsResetStatusEXT(); + + The symbolic constant returned indicates if the GL context has been + in a reset state at any point since the last call to + GetGraphicsResetStatusEXT. NO_ERROR indicates that the GL context + has not been in a reset state since the last call. + GUILTY_CONTEXT_RESET_EXT indicates that a reset has been detected + that is attributable to the current GL context. + INNOCENT_CONTEXT_RESET_EXT indicates a reset has been detected that + is not attributable to the current GL context. + UNKNOWN_CONTEXT_RESET_EXT indicates a detected graphics reset whose + cause is unknown. + + If a reset status other than NO_ERROR is returned and subsequent + calls return NO_ERROR, the context reset was encountered and + completed. If a reset status is repeatedly returned, the context may + be in the process of resetting. + + Reset notification behavior is determined at context creation time, + and may be queried by calling GetIntegerv with the symbolic constant + RESET_NOTIFICATION_STRATEGY_EXT. + + If the reset notification behavior is NO_RESET_NOTIFICATION_EXT, + then the implementation will never deliver notification of reset + events, and GetGraphicsResetStatusEXT will always return + NO_ERROR[fn1]. + [fn1: In this case it is recommended that implementations should + not allow loss of context state no matter what events occur. + However, this is only a recommendation, and cannot be relied + upon by applications.] + + If the behavior is LOSE_CONTEXT_ON_RESET_EXT, a graphics reset will + result in the loss of all context state, requiring the recreation of + all associated objects. In this case GetGraphicsResetStatusEXT may + return any of the values described above. + + If a graphics reset notification occurs in a context, a notification + must also occur in all other contexts which share objects with that + context[fn2]. + [fn2: The values returned by GetGraphicsResetStatusEXT in the + different contexts may differ.] + + Add to Section 2.8 "Vertex Arrays" before subsection "Transferring + Array Elements" + + Robust buffer access is enabled by creating a context with robust + access enabled through the window system binding APIs. When enabled, + indices within the vertex array that lie outside the arrays defined + for enabled attributes result in undefined values for the + corresponding attributes, but cannot result in application failure. + Robust buffer access behavior may be queried by calling GetIntegerv + with the symbolic constant CONTEXT_ROBUST_ACCESS_EXT. + +Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment +Operations and the Frame Buffer) + + Modify section 4.3.1 "Reading Pixels" + + Pixels are read using + + void ReadPixels(int x, int y, sizei width, sizei height, + enum format, enum type, void *data); + void ReadnPixelsEXT(int x, int y, sizei width, sizei height, + enum format, enum type, sizei bufSize, + void *data); + + Add to the description of ReadPixels: + + ReadnPixelsEXT behaves identically to ReadPixels except that it does + not write more than <bufSize> bytes into <data>. If the buffer size + required to fill all the requested data is greater than <bufSize> an + INVALID_OPERATION error is generated and <data> is not altered. + +Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special +Functions): + + None + +Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and +State Requests) + + Modify Section 6.1.8 "Shader and Program Queries" + + The commands + + void GetUniformfv(uint program, int location, float *params); + void GetnUniformfvEXT(uint program, int location, sizei bufSize, + float *params); + void GetUniformiv(uint program, int location, int *params); + void GetnUniformivEXT(uint program, int location, sizei bufSize, + int *params); + + return the value or values of the uniform at location <location> + for program object <program> in the array <params>. Calling + GetnUniformfvEXT or GetnUniformivEXT ensures that no more than + <bufSize> bytes are written into <params>. If the buffer size + required to fill all the requested data is greater than <bufSize> an + INVALID_OPERATION error is generated and <params> is not altered. + ... + +Additions to The OpenGL ES Shading Language Specification, Version 1. + + Append to the third paragraph of section 4.1.9 "Arrays" + + If robust buffer access is enabled via the OpenGL ES API, such + indexing must not result in abnormal program termination. The + results are still undefined, but implementations are encouraged to + produce zero values for such accesses. + +Interactions with EGL_EXT_create_context_robustness + + If the EGL window-system binding API is used to create a context, + the EGL_EXT_create_context_robustness extension is supported, and + the attribute EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT is set to + EGL_TRUE when eglCreateContext is called, the resulting context will + perform robust buffer access as described above in section 2.8, and + the CONTEXT_ROBUST_ACCESS_EXT query will return GL_TRUE as described + above in section 6.1.5. + + If the EGL window-system binding API is used to create a context and + the EGL_EXT_create_context_robustness extension is supported, then + the value of attribute EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT + determines the reset notification behavior and the value of + RESET_NOTIFICATION_STRATEGY_EXT, as described in section 2.6. + +Errors + + ReadnPixelsEXT, GetnUniformfvEXT, and GetnUniformivEXT share all the + errors of their unsized buffer query counterparts with the addition + that INVALID_OPERATION is generated if the buffer size required to + fill all the requested data is greater than <bufSize>. + +New Implementation Dependent State + + Get Value Type Get Command Minimum Value Description Sec. Attribute + --------- ---- ----------- ------------- --------------------------- ----- --------- + CONTEXT_ROBUST_ACCESS_EXT B GetIntegerv - Robust access enabled 6.1.5 - + RESET_NOTIFICATION_STRATEGY_EXT Z_2 GetIntegerv See sec. 2.6 Reset notification behavior 2.6 - + +Issues + + + 1. What should this extension be called? + + RESOLVED: EXT_robustness + + Since this is intended to be a version of ARB_robustness for + OpenGL ES, it should be named accordingly. + + 2. How does this extension differ from Desktop GL's ARB_robustness? + + RESOLVED: Because EGL_EXT_create_context_robustness uses a + separate attribute to enable robust buffer access, a + corresponding query is added here. + + 3. Should we provide a context creation mechanism to enable this extension? + + RESOLVED. Yes. + + Currently, EGL_EXT_create_context_robustness provides this + mechanism via two unique attributes. These attributes differ + from those specified by KHR_create_context to allow for + differences in what functionality those attributes define. + + 4. What can cause a graphics reset? + + Either user or implementor errors may result in a graphics reset. + If the application attempts to perform a rendering that takes too long + whether due to an infinite loop in a shader or even just a rendering + operation that takes too long on the given hardware. Implementation + errors may produce badly formed hardware commands. Memory access errors + may result from user or implementor mistakes. On some systems, power + management events such as system sleep, screen saver activation, or + pre-emption may also context resets to occur. Any of these events may + result in a graphics reset event that will be detectable by the + mechanism described in this extension. + + 5. How should the application react to a reset context event? + + RESOLVED: For this extension, the application is expected to query + the reset status until NO_ERROR is returned. If a reset is encountered, + at least one *RESET* status will be returned. Once NO_ERROR is again + encountered, the application can safely destroy the old context and + create a new one. + + After a reset event, apps should not use a context for any purpose + other than determining its reset status, and then destroying it. If a + context receives a reset event, all other contexts in its share group + will also receive reset events, and should be destroyed and + recreated. + + Apps should be cautious in interpreting the GUILTY and INNOCENT reset + statuses. These are guidelines to the immediate cause of a reset, but + not guarantees of the ultimate cause. + + 6. If a graphics reset occurs in a shared context, what happens in + shared contexts? + + RESOLVED: A reset in one context will result in a reset in all other + contexts in its share group. + + 7. How can an application query for robust buffer access support, + since this is now determined at context creation time? + + RESOLVED. The application can query the value of ROBUST_ACCESS_EXT + using GetIntegerv. If true, this functionality is enabled. + + 8. How is the reset notification behavior controlled? + + RESOLVED: Reset notification behavior is determined at context + creation time using EGL/GLX/WGL/etc. mechanisms. In order that shared + objects be handled predictably, a context cannot share with + another context unless both have the same reset notification + behavior. + + +Revision History + + Rev. Date Author Changes + ---- ------------ --------- ---------------------------------------- + 3 31 Oct 2011 groth Reverted to attribute for robust access. Now it's a + companion to rather than subset of KHR_create_context + 2 11 Oct 2011 groth Merged ANGLE and NV extensions. + Convert to using flag to indicate robust access. + 1 15 July 2011 groth Initial version
new file mode 100644 --- /dev/null +++ b/gfx/angle/extensions/EXT_texture_storage.txt @@ -0,0 +1,1090 @@ +Name + + EXT_texture_storage + +Name Strings + + GL_EXT_texture_storage + +Contact + + Bruce Merry (bmerry 'at' gmail.com) + Ian Romanick, Intel (ian.d.romanick 'at' intel.com) + +Contributors + + Jeremy Sandmel, Apple + Bruce Merry, ARM + Tom Olson, ARM + Benji Bowman, Imagination Technologies + Ian Romanick, Intel + Jeff Bolz, NVIDIA + Pat Brown, NVIDIA + Maurice Ribble, Qualcomm + Lingjun Chen, Qualcomm + Daniel Koch, Transgaming Inc + +Status + + Complete. + +Version + + Last Modified Date: November 11, 2011 + Author Revision: 24 + +Number + + XXX - not assigned yet + +Dependencies + + OpenGL ES 1.0, OpenGL ES 2.0 or OpenGL 1.2 is required. + + OES_texture_npot, OES_texture_cube_map, OES_texture_3D, + OES_depth_texture, OES_packed_depth_stencil, + OES_compressed_paletted_texture, OES_texture_float, OES_texture_half_float + EXT_texture_type_2_10_10_10_REV, EXT_texture_format_BGRA8888, + EXT_texture3D, OES_texture_npot, APPLE_texture_2D_limited_npot, + ARB_texture_cube_map, ARB_texture_cube_map_array, + ARB_texture_rectangle, SGIS_generate_mipmap, + EXT_direct_state_access, OES_EGL_image, WGL_ARB_render_texture, + GLX_EXT_texture_from_pixmap, and core specifications that + incorporate these extensions affect the definition of this + extension. + + This extension is written against the OpenGL 3.2 Core Profile + specification. + +Overview + + The texture image specification commands in OpenGL allow each level + to be separately specified with different sizes, formats, types and + so on, and only imposes consistency checks at draw time. This adds + overhead for implementations. + + This extension provides a mechanism for specifying the entire + structure of a texture in a single call, allowing certain + consistency checks and memory allocations to be done up front. Once + specified, the format and dimensions of the image array become + immutable, to simplify completeness checks in the implementation. + + When using this extension, it is no longer possible to supply texture + data using TexImage*. Instead, data can be uploaded using TexSubImage*, + or produced by other means (such as render-to-texture, mipmap generation, + or rendering to a sibling EGLImage). + + This extension has complicated interactions with other extensions. + The goal of most of these interactions is to ensure that a texture + is always mipmap complete (and cube complete for cubemap textures). + +IP Status + + No known IP claims + +New Procedures and Functions + + void TexStorage1DEXT(enum target, sizei levels, + enum internalformat, + sizei width); + + void TexStorage2DEXT(enum target, sizei levels, + enum internalformat, + sizei width, sizei height); + + void TexStorage3DEXT(enum target, sizei levels, + enum internalformat, + sizei width, sizei height, sizei depth); + + void TextureStorage1DEXT(uint texture, enum target, sizei levels, + enum internalformat, + sizei width); + + void TextureStorage2DEXT(uint texture, enum target, sizei levels, + enum internalformat, + sizei width, sizei height); + + void TextureStorage3DEXT(uint texture, enum target, sizei levels, + enum internalformat, + sizei width, sizei height, sizei depth); + +New Types + + None + +New Tokens + + Accepted by the <value> parameter of GetTexParameter{if}v: + + TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F + + Accepted by the <internalformat> parameter of TexStorage* when + implemented on OpenGL ES: + + ALPHA8_EXT 0x803C /* reuse tokens from EXT_texture */ + LUMINANCE8_EXT 0x8040 + LUMINANCE8_ALPHA8_EXT 0x8045 + + (if OES_texture_float is supported) + RGBA32F_EXT 0x8814 /* reuse tokens from ARB_texture_float */ + RGB32F_EXT 0x8815 + ALPHA32F_EXT 0x8816 + LUMINANCE32F_EXT 0x8818 + LUMINANCE_ALPHA32F_EXT 0x8819 + + (if OES_texture_half_float is supported) + RGBA16F_EXT 0x881A /* reuse tokens from ARB_texture_float */ + RGB16F_EXT 0x881B + ALPHA16F_EXT 0x881C + LUMINANCE16F_EXT 0x881E + LUMINANCE_ALPHA16F_EXT 0x881F + + (if EXT_texture_type_2_10_10_10_REV is supported) + RGB10_A2_EXT 0x8059 /* reuse tokens from EXT_texture */ + RGB10_EXT 0x8052 + + (if EXT_texture_format_BGRA8888 is supported) + BGRA8_EXT 0x93A1 + + +Additions to Chapter 2 of the OpenGL 3.2 Core Profile Specification +(OpenGL Operation) + + None + +Additions to Chapter 3 of the OpenGL 3.2 Core Profile Specification +(Rasterization) + + After section 3.8.1 (Texture Image Specification) add a new + subsection called "Immutable-format texture images": + + "An alterative set of commands is provided for specifying the + properties of all levels of a texture at once. Once a texture is + specified with such a command, the format and dimensions of all + levels becomes immutable, unless it is a proxy texture (since + otherwise it would no longer be possible to use the proxy). The + contents of the images and the parameters can still be modified. + Such a texture is referred to as an "immutable-format" texture. The + immutability status of a texture can be determined by calling + GetTexParameter with <pname> TEXTURE_IMMUTABLE_FORMAT_EXT. + + Each of the commands below is described by pseudo-code which + indicates the effect on the dimensions and format of the texture. + For all of the commands, the following apply in addition to the + pseudo-code: + + - If the default texture object is bound to <target>, an + INVALID_OPERATION error is generated. + - If executing the pseudo-code would lead to an error, the error is + generated and the command will have no effect. + - Any existing levels that are not replaced are reset to their + initial state. + - If <width>, <height>, <depth> or <levels> is less than 1, the + error INVALID_VALUE is generated. + - Since no pixel data are provided, the <format> and <type> values + used in the pseudo-code are irrelevant; they can be considered to + be any values that are legal to use with <internalformat>. + - If the command is successful, TEXTURE_IMMUTABLE_FORMAT_EXT becomes + TRUE. + - If <internalformat> is a specific compressed texture format, then + references to TexImage* should be replaced by CompressedTexImage*, + with <format>, <type> and <data> replaced by any valid <imageSize> and + <data>. If there is no <imageSize> for which this command would have + been valid, an INVALID_OPERATION error is generated [fn: This + condition is not required for OpenGL, but is necessary for OpenGL + ES which does not support on-the-fly compression.] + - If <internalformat> is one of the internal formats listed in table + 3.11, an INVALID_ENUM error is generated. [fn: The corresponding table + in OpenGL ES 2.0 is table 3.8.] + + The command + + void TexStorage1DEXT(enum target, sizei levels, + enum internalformat, + sizei width); + + specifies all the levels of a one-dimensional texture (or proxy) at + the same time. It is described by the pseudo-code below: + + for (i = 0; i < levels; i++) + { + TexImage1D(target, i, internalformat, width, 0, + format, type, NULL); + width = max(1, floor(width / 2)); + } + + If <target> is not TEXTURE_1D or PROXY_TEXTURE_1D then INVALID_ENUM + is generated. If <levels> is greater than floor(log_2(width)) + 1 + then INVALID_OPERATION is generated. + + The command + + void TexStorage2DEXT(enum target, sizei levels, + enum internalformat, + sizei width, sizei height); + + specifies all the levels of a two-dimensional, cube-map, + one-dimension array or rectangle texture (or proxy) at the same + time. The pseudo-code depends on the <target>: + + [PROXY_]TEXTURE_2D, [PROXY_]TEXTURE_RECTANGLE or + PROXY_TEXTURE_CUBE_MAP: + + for (i = 0; i < levels; i++) + { + TexImage2D(target, i, internalformat, width, height, 0, + format, type, NULL); + width = max(1, floor(width / 2)); + height = max(1, floor(height / 2)); + } + + TEXTURE_CUBE_MAP: + + for (i = 0; i < levels; i++) + { + for face in (+X, -X, +Y, -Y, +Z, -Z) + { + TexImage2D(face, i, internalformat, width, height, 0, + format, type, NULL); + } + width = max(1, floor(width / 2)); + height = max(1, floor(height / 2)); + } + + [PROXY_]TEXTURE_1D_ARRAY: + + for (i = 0; i < levels; i++) + { + TexImage2D(target, i, internalformat, width, height, 0, + format, type, NULL); + width = max(1, floor(width / 2)); + } + + If <target> is not one of those listed above, the error INVALID_ENUM + is generated. + + The error INVALID_OPERATION is generated if any of the following + conditions hold: + - <target> is [PROXY_]TEXTURE_1D_ARRAY and <levels> is greater than + floor(log_2(width)) + 1 + - <target> is not [PROXY_]TEXTURE_1D_ARRAY and <levels> is greater + than floor(log_2(max(width, height))) + 1 + + The command + + void TexStorage3DEXT(enum target, sizei levels, enum internalformat, + sizei width, sizei height, sizei depth); + + specifies all the levels of a three-dimensional, two-dimensional + array texture, or cube-map array texture (or proxy). The pseudo-code + depends on <target>: + + [PROXY_]TEXTURE_3D: + + for (i = 0; i < levels; i++) + { + TexImage3D(target, i, internalformat, width, height, depth, 0, + format, type, NULL); + width = max(1, floor(width / 2)); + height = max(1, floor(height / 2)); + depth = max(1, floor(depth / 2)); + } + + [PROXY_]TEXTURE_2D_ARRAY, [PROXY_]TEXTURE_CUBE_MAP_ARRAY_ARB: + + for (i = 0; i < levels; i++) + { + TexImage3D(target, i, internalformat, width, height, depth, 0, + format, type, NULL); + width = max(1, floor(width / 2)); + height = max(1, floor(height / 2)); + } + + If <target> is not one of those listed above, the error INVALID_ENUM + is generated. + + The error INVALID_OPERATION is generated if any of the following + conditions hold: + - <target> is [PROXY_]TEXTURE_3D and <levels> is greater than + floor(log_2(max(width, height, depth))) + 1 + - <target> is [PROXY_]TEXTURE_2D_ARRAY or + [PROXY_]TEXTURE_CUBE_MAP_ARRAY_EXT and <levels> is greater than + floor(log_2(max(width, height))) + 1 + + After a successful call to any TexStorage* command with a non-proxy + target, the value of TEXTURE_IMMUTABLE_FORMAT_EXT for this texture + object is set to TRUE, and no further changes to the dimensions or + format of the texture object may be made. Other commands may only + alter the texel values and texture parameters. Using any of the + following commands with the same texture will result in the error + INVALID_OPERATION being generated, even if it does not affect the + dimensions or format: + + - TexImage* + - CompressedTexImage* + - CopyTexImage* + - TexStorage* + + The TextureStorage* commands operate identically to the + corresponding command where "Texture" is substituted for "Tex" + except, rather than updating the current bound texture for the + texture unit indicated by the current active texture state and the + target parameter, these "Texture" commands update the texture object + named by the initial texture parameter. The error INVALID_VALUE + is generated if <texture> is zero. + " + + In section 3.8.6 (Texture Parameters), after the sentence + + "In the remainder of section 3.8, denote by lod_min, lod_max, + level_base, and level_max the values of the texture parameters + TEXTURE_MIN_LOD, TEXTURE_MAX_LOD, TEXTURE_BASE_LEVEL, and + TEXTURE_MAX_LEVEL respectively." + + add + + "However, if TEXTURE_IMMUTABLE_FORMAT_EXT is + TRUE, then level_base is clamped to the range [0, <levels> - 1] and + level_max is then clamped to the range [level_base, <levels> - 1], + where <levels> is the parameter passed the call to TexStorage* for + the texture object. + + In section 3.8.9 (Rendering feedback loops) replace all references + to TEXTURE_BASE_LEVEL by level_base. + + In section 3.8.9 (Mipmapping), replace the paragraph starting "Each + array in a mipmap is defined..." by + + "Each array in a mipmap is defined using TexImage3D, TexImage2D, + CopyTexImage2D, TexImage1D, CopyTexImage1D, or by functions that are + defined in terms of these functions. Level-of-detail numbers proceed + from level_base for the original texel array through the maximum + level p, with each unit increase indicating an array of half the + dimensions of the previous one (rounded down to the next integer if + fractional) as already described. For immutable-format textures, + p is one less than the <levels> parameter passed to TexStorage*; + otherwise p = floor(log_2(maxsize)) + level_base. All arrays from + level_base through q = min(p, level_max) must be defined, as + discussed in section 3.8.12." + + In section 3.8.12 (Texture Completeness), modify the last sentence + to avoid refering to level_base and level_max: + + "An implementation may allow a texture image array of level 1 or + greater to be created only if a mipmap complete set of image arrays + consistent with the requested array can be supported where the + values of TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL are 0 and 1000 + respectively." + + Modify section 3.8.13 (Texture State and Proxy State) to add the new + state: + + "Each set consists of ..., and a boolean flag indicating whether the + format and dimensions of the texture are immutable." + + Add + "The initial value of TEXTURE_IMMUTABLE_FORMAT_EXT is FALSE." + +Additions to Chapter 4 of the OpenGL 3.2 Core Profile Specification +(Per-Fragment Operations and the Frame Buffer) + + None + +Additions to Chapter 5 of the OpenGL 3.2 Compatibility Profile Specification +(Special Functions) + + In section 5.4.1 (Commands Not Usable in Display Lists), add + TexStorage* to the list of commands that cannot be used. + +Additions to Chapter 6 of the OpenGL 3.2 Core Profile Specification +(State and State Requests) + + Replace the following statement in 6.1.3 (Enumerated Queries): + + "<value> must be one of the symbolic values in table 3.10." + + with + + "<value> must be TEXTURE_IMMUTABLE_FORMAT_EXT or one of the symbolic + values in table 3.22." + +Additions to the AGL/EGL/GLX/WGL Specifications + + None + +Additions to OES_compressed_ETC1_RGB8_texture + + Add the following to the additions to Chapter 3: + + "Since ETC1 images are easily edited along 4x4 texel boundaries, the + limitations on CompressedTexSubImage2D are relaxed. + CompressedTexSubImage2D will result in an INVALID_OPERATION error + only if one of the following conditions occurs: + + * <width> is not a multiple of four, and <width> plus <xoffset> is not + equal to the texture width; + + * <height> is not a multiple of four, and <height> plus <yoffset> is + not equal to the texture height; or + + * <xoffset> or <yoffset> is not a multiple of four. + + Remove CompressedTexSubImage2D from this error: + + "INVALID_OPERATION is generated by CompressedTexSubImage2D, + TexSubImage2D, or CopyTexSubImage2D if the texture image <level> + bound to <target> has internal format ETC1_RGB8_OES." + + Add the following error: + + "INVALID_OPERATION is generated by CompressedTexSubImage2D + if the region to be modified is not aligned to block boundaries + (refer to the extension text for details)." + +Additions to AMD_compressed_ATC_texture and AMD_compressed_3DC_texture: + + Apply the same changes as for OES_compressed_ETC1_RGB8_texture + above, substituting the appropriate internal format tokens from + these extensions. + +Dependencies on EXT_direct_state_access + + If EXT_direct_state_access is not present, references to + TextureStorage* should be ignored. + +Dependencies on OpenGL ES + + On OpenGL ES without extensions introducing TEXTURE_MAX_LEVEL, + mipmapped textures specified with TexStorage are required to have a + full set of mipmaps. If TEXTURE_MAX_LEVEL is not supported, this + extension is modified as follows: + + - Where an upper bound is placed on <levels> in this extension (i.e. + the maximum number of mipmap levels for a texture of the given + target and dimensions), an INVALID_OPERATION error is generated if + <levels> is neither 1 nor this upper bound. + - q (the effective maximum number of levels) is redefined to clamp + to the number of levels present in immutable-format textures. + + OpenGL ES does not accept sized internal formats (e.g., RGBA8) and + instead derives an internal format from the <format> and <type> + parameters of TexImage2D. Since TexStorage* does not specify texel + data, the API doesn't include <format> and <type> parameters. + On an OpenGL ES implementation, the values in the <internalformat> + column in the tables below are accepted as <internalformat> + parameters, and base internal formats are not accepted. The + TexImage* calls in the TexStorage* pseudocode are modified so that + the <internalformat>, <format> and <type> parameters are + taken from the <format>, <format> and <type> columns (respectively) + in the tables below, according to the <internalformat> + specified in the TexStorage* command. + + <internalformat> <format> <type> + ---------------- -------- ------ + RGB565 RGB UNSIGNED_SHORT_5_6_5 + RGBA4 RGBA UNSIGNED_SHORT_4_4_4_4 + RGB5_A1 RGBA UNSIGNED_SHORT_5_5_5_1 + RGB8_OES RGB UNSIGNED_BYTE + RGBA8_OES RGBA UNSIGNED_BYTE + LUMINANCE8_ALPHA8_EXT LUMINANCE_ALPHA UNSIGNED_BYTE + LUMINANCE8_EXT LUMINANCE UNSIGNED_BYTE + ALPHA8_EXT ALPHA UNSIGNED_BYTE + + If OES_depth_texture is supported: + + <internalformat> <format> <type> + ---------------- -------- ------ + DEPTH_COMPONENT16_OES DEPTH_COMPONENT UNSIGNED_SHORT + DEPTH_COMPONENT32_OES DEPTH_COMPONENT UNSIGNED_INT + + If OES_packed_depth_stencil is supported: + + <internalformat> <format> <type> + ---------------- -------- ------ + DEPTH24_STENCIL8_OES DEPTH_STENCIL_OES UNSIGNED_INT + + If OES_texture_float is supported: + + <internalformat> <format> <type> + ---------------- -------- ------ + RGBA32F_EXT RGBA FLOAT + RGB32F_EXT RGB FLOAT + LUMINANCE_ALPHA32F_EXT LUMINANCE_ALPHA FLOAT + LUMINANCE32F_EXT LUMINANCE FLOAT + ALPHA32F_EXT ALPHA FLOAT + + If OES_texture_half_float is supported: + + <internalformat> <format> <type> + ---------------- -------- ------ + RGBA16F_EXT RGBA HALF_FLOAT_OES + RGB16F_EXT RGB HALF_FLOAT_OES + LUMINANCE_ALPHA16F_EXT LUMINANCE_ALPHA HALF_FLOAT_OES + LUMINANCE16F_EXT LUMINANCE HALF_FLOAT_OES + ALPHA16F_EXT ALPHA HALF_FLOAT_OES + + If EXT_texture_type_2_10_10_10_REV is supported: + + <internalformat> <format> <type> + ---------------- -------- ------ + RGB10_A2_EXT RGBA UNSIGNED_INT_2_10_10_10_REV_EXT + RGB10_EXT RGB UNSIGNED_INT_2_10_10_10_REV_EXT + + If EXT_texture_format_BGRA8888 is supported: + + <internalformat> <format> <type> + ---------------- -------- ------ + BGRA8_EXT BGRA_EXT UNSIGNED_BYTE + + +Dependencies on texture targets + + If a particular texture target is not supported by the + implementation, passing it as a <target> to TexStorage* will + generate an INVALID_ENUM error. If as a result, any of the commands + defined in this extension would no longer have any valid <target>, + all references to the command should be ignored. + + In particular, note that OpenGL ES 1.x/2.0 do not have proxy textures, + 1D textures, or 3D textures, and thus only the TexStorage2DEXT + entry point is required. If OES_texture_3D is supported, the + TexStorage3DEXT entry point is also required. + +Dependencies on OES_texture_npot + + If OpenGL ES 2.0 or APPLE_texture_2D_limited_npot is present but + OES_texture_npot is not present, then INVALID_OPERATION is + generated by TexStorage* and TexStorage3DEXT if <levels> is + not one and <width>, <height> or <depth> is not a power of + two. + +Dependencies on WGL_ARB_render_texture, GLX_EXT_texture_from_pixmap, EGL +1.4 and GL_OES_EGL_image + + The commands eglBindTexImage, wglBindTexImageARB, glXBindTexImageEXT or + EGLImageTargetTexture2DOES are not permitted on an immutable-format + texture. + They will generate the following errors: + - EGLImageTargetTexture2DOES: INVALID_OPERATION + - eglBindTexImage: EGL_BAD_MATCH + - wglBindTexImage: ERROR_INVALID_OPERATION + - glXBindTexImageEXT: BadMatch + +Dependencies on OES_compressed_paletted_texture + + The compressed texture formats exposed by + OES_compressed_paletted_texture are not supported by TexStorage*. + Passing one of these tokens to TexStorage* will generate an + INVALID_ENUM error. + +Errors + + Note that dependencies above modify the errors. + + If TexStorage* is called with a <width>, <height>, <depth> or + <levels> parameter that is less than one, then the error + INVALID_VALUE is generated. + + If the <target> parameter to TexStorage1DEXT is not + [PROXY_]TEXTURE_1D, then the error INVALID_ENUM is generated. + + If the <target> parameter to TexStorage2DEXT is not + [PROXY_]TEXTURE_2D, [PROXY_]TEXTURE_CUBE_MAP, + [PROXY_]TEXTURE_RECTANGLE or [PROXY_]TEXTURE_1D_ARRAY, then the + error INVALID_ENUM is generated. + + If the <target> parameter to TexStorage3DEXT is not + [PROXY_]TEXTURE_3D, [PROXY_]TEXTURE_2D_ARRAY or + [PROXY_]TEXTURE_CUBE_MAP_ARRAY then the error INVALID_ENUM is + generated. + + If the <levels> parameter to TexStorage* is greater than the + <target>-specific value listed below then the error + INVALID_OPERATION is generated: + [PROXY_]TEXTURE_{1D,1D_ARRAY}: + floor(log_2(width)) + 1 + [PROXY_]TEXTURE_{2D,2D_ARRAY,CUBE_MAP,CUBE_MAP_ARRAY}: + floor(log_2(max(width, height))) + 1 + [PROXY_]TEXTURE_3D: + floor(log_2(max(width, height, depth))) + 1 + [PROXY_]TEXTURE_RECTANGLE: + 1 + + If the default texture object is bound to the <target> passed to + TexStorage*, then the error INVALID_OPERATION is generated. + + If the <target> parameter to TextureStorage* does not match the + dimensionality of <texture>, then the error INVALID_OPERATION is + generated. + + If the <texture> parameter to TextureStorage* is zero, then the + INVALID_VALUE is generated. + + If any pseudo-code listed in this extension would generate an error, + then that error is generated. + + Calling any of the following functions on a texture for which + TEXTURE_IMMUTABLE_FORMAT_EXT is TRUE will generate an + INVALID_OPERATION error: + - TexImage* + - CompressedTexImage* + - CopyTexImage* + +New State + + Additions to Table 6.8 Textures (state per texture object) + + Initial + Get Value Type Get Command Value Description Sec. + --------- ---- ----------- ------- ----------- ---- + TEXTURE_IMMUTABLE_FORMAT_EXT B GetTexParameter FALSE Size and format immutable 2.6 + +New Implementation Dependent State + + None + +Issues + + 1. What should this extension be called? + + RESOLVED: EXT_texture_storage is chosen for consistency with the + glRenderbufferStorage entry point. + + 2. Should TexStorage* accept a border parameter? + + RESOLVED: no. + + DISCUSSION: Currently it does not, since borders are a deprecated + feature which is not supported by all hardware. Users of the + compatibility profile can continue to use the existing texture + specification functions, but there is an argument that users of + compatibility profile may also want to use this extension. + + 3. What is the correct error when <levels> specifies a partial + mipmap pyramid for OpenGL ES? + + RESOLVED: INVALID_OPERATION, since it is an interaction between + parameters rather than a single value being invalid. It also makes + sense to relax this condition for desktop GL where it makes sense to + use a truncated pyramid with TEXTURE_MAX_LEVEL. + + 4. Should use of these entry-points make the metadata (format and + dimensions) immutable? + + RESOLVED: Yes. + + DISCUSSION: The benefits of knowing metadata can't change will + probably outweigh the extra cost of checking the + TEXTURE_IMMUTABLE_FORMAT_EXT flag on each texture specification + call. + + 5. Should it be legal to completely replace the texture using a new call + to TexStorage*? + + RESOLVED. It will not be allowed. + + DISCUSSION: This is useful to invalidate all levels of a texture. + Allowing the metadata to be changed here seems easier than trying to + define a portable definition of what it means to change the metadata + (e.g. what if you used an unsized internal format the first time and + the corresponding sized internal format the second time, or vice + versa)? + + However, while this is largely similar to deleting the old texture + object and replacing it with a new one, it does lose some of the + advantages of immutability. Specifically, because doing so does not + reset bindings, it doesn't allow a migration path to an API that + validates the texture format at bind time. + + 6. Should it be legal to use TexImage* after TexStorage* if it doesn't + affect the metadata? + + RESOLVED: No. + + DISCUSSION: A potential use case is to allow a single level of a + texture to be invalidated using a NULL pointer. However, as noted + above it is non-trivial to determine what constitutes a change. + + 7. How does this extension interact with APPLE_texture_2D_limited_npot? + + RESOLVED. APPLE_texture_2D_limited_npot is equivalent to the NPOT + support in OpenGL ES 2.0. + + 8. Should this extension be written to work with desktop OpenGL? + + RESOLVED: Yes. + + DISCUSSION: There has been been interest and it will future-proof it + against further additions to OpenGL ES. + + 9. Which texture targets should be supported? + + RESOLVED. All targets except multisample and buffer textures are + supported. + + Initially all targets except TEXTURE_BUFFER were supported. It was + noted that the entrypoints for multisample targets added no useful + functionality, since multisample textures have no completeness + checks beyond being non-empty. + + Rectangle textures have completeness checks to prevent filtering of + integer textures. However, since we decided to only force mipmap + completeness, this becomes less useful. + + 10. Should this extension support proxy textures? + + RESOLVED: Yes. + + DISCUSSION: It should be orthogonal. + + 11. Are the <format> and <type> parameters necessary? + + RESOLVED. No, they will be removed. + + DISCUSSION: For OpenGL ES the type parameter was necessary to + determine the precision of the texture, but this can be solved by + having these functions accept sized internal formats (which are + already accepted by renderbuffers). + + 12. Should it be legal to make the default texture (id 0) + immutable-format? + + RESOLVED: No. + + DISCUSSION: This would make it impossible to restore the context to + it's default state, which is deemed undesirable. There is no good + reason not to use named texture objects. + + 13. Should we try to guarantee that textures made through this path + will always be complete? + + RESOLVED: It should be guaranteed that the texture will be mipmap + complete. + + DISCUSSION: Future separation between images and samplers will still + allow users to create combinations that are invalid, but + constraining the simple cases will make these APIs easier to use for + beginners. + + 14. Should these functions use a EXT_direct_state_access approach to + specifying the texture objects? + + UNRESOLVED. + + DISCUSSION: as a standalone extension, no DSA-like functions will be + added. However, interactions with EXT_direct_state_access and + ARB_direct_state_access need to be resolved. + + 15. Should these functions accept generic compressed formats? + + RESOLVED: Yes. Note that the spec language will need to be modified + to allow this for ES, since the pseudocode is written in terms of + TexImage2D, which does not allow compressed texture formats in ES. + See also issues 23 and 27. + + 16. How should completeness be forced when TEXTURE_MAX_LEVEL is not + present? + + RESOLVED. The maximum level q will be redefined to clamp to the + highest level available. + + DISCUSSION: A single-level texture can be made complete either by + making it mipmap complete (by setting TEXTURE_MAX_LEVEL to 0) or by + turning off mipmapping (by choose an appropriate minification + filter). + + Some options: + + A: Specify that TexStorage* changes the default minification filter + for OpenGL ES. This makes it awkward to add TEXTURE_MAX_LEVEL + support to OpenGL ES later, since switching to match GL would break + compatibility. The two mechanisms also do not give identical + results, since the magnification threshold depends on the + minification filter. + + B: Specify that the texture behaves as though TEXTURE_MAX_LEVEL were + zero. To specify this properly probably requires fairly intrusive + changes to the OpenGL ES full specification to add back all the + language relating to the max level. It also does not solve the + similar problem of what to do with NPOT textures; and it may have + hardware impacts due to the change in the min/mag crossover. + + C: Specify that TexStorage* changes the default minification filter + for all implementations when a single-level texture is specified. + This may be slightly counter-intuitive to desktop GL users, but will + give consistent behaviour across variants of GL and avoids changing + the functional behaviour of this extension based on the presence or + absence of some other feature. + + Currently B is specified. This has potential hardware implications + for OpenGL ES because of the effect of the minification filter on + the min/mag crossover. However, C has potential hardware implications + for OpenGL due to the separation of texture and sampler state. + + 17. How should completeness be forced when only ES2-style NPOT is + available? + + RESOLVED. It is not worth trying to do this, in light of issue 13. + + Previous revisions of this extension overrode the minification + filter and wrap modes, but that is no longer the case. Since + OES_texture_npot removes the caveats on NPOT textures anyway, it + might not be worth trying to "fix" this. + + 18. For OpenGL ES, how do the new sized internal formats interact + with OES_required_internal_format? + + RESOLVED. + + If OES_required_internal_format is not present, then the + <internalformat> parameter is intended merely to indicate what the + corresponding <format> and <type> would have been, had TexImage* + been used instead. If OES_required_internal_format is present, then + it is intended that the <internalformat> will be interpreted as if + it had been passed directly to TexImage*. + + 19. Should there be some hinting mechanism to indicate whether data + is coming immediately or later? + + RESOLVED. No parameter is needed. An extension can be added to provide + a TexParameter value which is latched at TexStorage time. + + DISCUSSION: Some members felt that this would be useful so that they + could defer allocation when suitable, particularly if higher- + resolution images will be streamed in later; or to choose a memory + type or layout appropriate to the usage. However, implementation + experience with BufferData is that developers frequently provide + wrong values and implementations have to guess anyway. + + One option suggested was the <usage> parameter currently passed to + BufferData. Another option was to set it with TexParameter. + + 20. How should this extension interact with + EGLImageTargetTexture2DOES, eglBindTexImage, glXBindTexImage and + wglBindTexImage? + + RESOLVED. These functions will not be permitted after glTexStorage*. + + Several options are possible: + + A) Disallow these functions. + B) Allow them, but have them reset the TEXTURE_IMMUTABLE_FORMAT_EXT + flag. + C) Allow them unconditionally. + + C would violate the design principle that the dimensions and format + of the mipmap array are immutable. B does not so much modify the + dimension and formats as replace them with an entirely different + set. + + 21. Should there be a single function for specifying 1D, 2D and 3D + targets? + + RESOLVED. No, we will stick with existing precedent. + + 22. Is it possible to use GenerateMipmap with an incomplete mipmap + pyramid? + + RESOLVED. Yes, because the effective max level is limited to the + levels that were specified, and so GenerateMipmap does not generate + any new levels. + + However, to make automatic mipmap generation work, it is necessary + to redefine p rather than q, since automatic mipmap generation + ignores the max level. + + 23. How should this extension interact with + OES_compressed_paletted_texture? + + RESOLVED. Paletted textures will not be permitted, and will + generate INVALID_ENUM. + + DISCUSSION: OES_compressed_paletted_texture supplies all the mipmaps + in a single function call, with the palette specified once. That's + incompatible with the upload model in this extension. + + 24. How can ETC1 textures be used with this extension? + + RESOLVED. Add language in this extension to allow subregion uploads + for ETC1. + + DISCUSSION: GL_OES_compressed_ETC1_RGB8_texture doesn't allow + CompressedTexSubImage*, so it would be impossible to use this + extension with ETC1. This is seen as an oversight in the ETC1 + extension. While it cannot be fixed in that extension (since it is + already shipping), this extension can add that capability. + + 25. Should any other compressed formats be similarly modified? + + RESOLVED. Yes, AMD_compressed_ATC_texture and + AMD_compressed_3DC_texture can be modified similarly to ETC1 + (Maurice Ribble indicated that both formats use 4x4 blocks). Desktop + OpenGL requires that whole-image replacement is supported for any + compressed texture format, and the OpenGL ES extensions + EXT_texture_compression_dxt1 and IMG_texture_compression_pvrtc + already allow whole-image replacement, so it is not necessary to + modify them to be used with this extension. + + 26. Should these commands be permitted in display lists? + + RESOLVED. No. + + DISCUSSION: Display lists are most useful for repeating commands, + and TexStorage* commands cannot be repeated because the first call + makes the format immutable. + + 27. Should these commands accept unsized internal formats? + + RESOLVED: No, for both OpenGL and OpenGL ES. + + DISCUSSION: normally the <type> parameter to TexImage* can serve as + a hint to select a sized format (and in OpenGL ES, this is the only + mechanism available); since TexStorage* does not have a <type> + parameter, the implementation has no information on which to base a + decision. + +Revision History + + Revision 24, 2011/11/11 (dgkoch) + - Mark complete. Clarify ES clarifications. + + Revision 23, 2011/11/10 (dgkoch) + - Add GLES clarifcations and interactions with more GLES extensions + + Revision 22, 2011/11/10 (bmerry) + - Update my contact details + + Revision 21, 2011/07/25 (bmerry) + - Remove dangling references to MultiTexStorage in Errors section + + Revision 20, 2011/07/21 (bmerry) + - Remove dangling reference to <samples> in Errors section + + Revision 19, 2011/05/02 (Jon Leech) + - Assign enum value + + Revision 18, 2011/01/24 (bmerry) + - Disallow unsized internal formats (oversight in revision 17). + + Revision 17, 2011/01/24 (bmerry) + - Added and resolved issue 26. + - Split issue 27 out from issue 15. + - Disallow TexStorage* in display lists. + - Use the term "immutable-format" consistently (bug 7281). + + Revision 16, 2010/11/23 (bmerry) + - Disallowed TexStorage on an immutable-format texture + (resolves issue 5). + - Deleted MultiTexStorage* commands (other DSA functions still + unresolved). + - Some minor wording changes suggested by Pat Brown (bug 7002). + + Revision 15, 2010/11/09 (bmerry) + - Reopened issue 5. + - Reopened issue 14, pending stabilisation of + ARB_direct_state_access. + - Marked issue 9 resolved, pending any objections. + - Fix references to no object being bound (was meant to refer to + the default object). + - Adding missing pseudocode for TEXTURE_1D_ARRAY. + - Corrected TEXTURE_2D_ARRAY -> TEXTURE_1D_ARRAY in error checks. + - Changed "levels... are removed" to "levels... are reset to their + init state", since desktop GL has per-level state apart from the + texels. + - Miscellaneous wording fixes. + + Revision 14, 2010/09/25 (bmerry) + - Add issues 24-25 and alterations to + OES_compressed_ETC1_RGB8_texture, AMD_compressed_ATC_texture and + AMD_compressed_3DC_texture. + + Revision 13, 2010/09/19 (bmerry) + - Two typo fixes from Daniel Koch + + Revision 12, 2010/09/18 (bmerry) + - Changed resolution to issue 20 + - Added and resolved issue 23 + - Added explanation of how to upload data (in overview) + - Added spec language to implement resolution to issue 15 + + Revision 11, 2010/07/21 (bmerry) + - Resolved issue 16 + - Reopen issue 20 + - Fix some typos + + Revision 10, 2010/07/15 (bmerry) + - Update some issues to match core text + - Resolved issue 17 + + Revision 9, 2010/05/24 (bmerry) + - Marked issue 2 as resolved + - Resolved issue 19 (as no change) + - Resolved issue 20 + - Add issues 21-22 + - Add in spec language to forbid use on default textures + - Redefine level_base, level_max to be clamped forms of + TEXTURE_BASE_LEVEL/TEXTURE_MAX_LEVEL when using immutable + textures + - Redefine p to also be clamped to the provided levels for + immutable textures, to support automatic mipmap generation + - Removed multisample functions + - Removed language stating that texture parameters were reset to + defaults + + Revision 8, 2010/05/18 (bmerry) + - Added issue about EGLimage + - Marked issue 14 as resolved + + Revision 7, 2010/05/04 (bmerry) + - Removed some lingering <format>, <type> parameters to the new + functions that should have been removed in revision 4 + - Trivial typo fixes + + Revision 6, 2010/02/18 (bmerry) + - Resolved issues 5, 6 and 18 + - Added MultiTexStorage* functions for DSA interaction + - Added error for texture-target mismatch in DSA + - Allowed TexStorage* to be called again + + Revision 5, 2010/01/25 (bmerry) + - Added to contributors list + - Require OpenGL 1.2, to simplify interactions with + TEXTURE_BASE_LEVEL/TEXTURE_MAX_LEVEL and CLAMP_TO_EDGE + - Change default wrap modes to always be CLAMP_TO_EDGE + - Change default filters to always be NEAREST + - Moved language about generating new levels into an interaction, + since it can only happen on OpenGL ES + - Added interaction with EXT_direct_state_access + - Added extra <internalformats> for GL ES when OES_depth_texture, + OES_packed_depth_stencil and EXT_texture_type_2_10_10_10_REV are + present. + - Minor non-functional wording fixes and typos + - Resolved issue 16 + - Added issues 17-19 + + Revision 4, 2010/01/13 (bmerry) + - Changed suffix from ARM to EXT + - Added list of contributors + - Added language to force the texture to always be complete + - Removed <format> and <type> arguments + - Added issues 14-16 + - Reopened issue 2 + - Reformatted issues to separate resolution and discussion + - Resolved issues 1, 9 and 11-13 + - Fixed the max number of levels in a cube map array + + Revision 3, 2009/12/17 (bmerry) + - Added missing vendor suffix to TEXTURE_IMMUTABLE_FORMAT_ARM + - Rewritten to against desktop OpenGL + - Added prototypes for 1D and multisample storage functions + - Added issues 8-13 + + Revision 2, 2009/08/20 (bmerry) + - Resolved issue 2 (no border parameter) + - Resolved issue 4 (metadata becomes immutable) + - Added interaction with OES_texture_cube_map + - Added error if width != height in a cube map + - Added issues 5-7 + + Revision 1, 2009/05/06 (bmerry) + - First draft
--- a/gfx/angle/include/EGL/eglext.h +++ b/gfx/angle/include/EGL/eglext.h @@ -313,16 +313,24 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLQ #ifndef EGL_NV_coverage_sample_resolve #define EGL_NV_coverage_sample_resolve 1 #define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131 #define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132 #define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133 #endif +#ifndef EGL_EXT_create_context_robustness +#define EGL_EXT_create_context_robustness 1 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 +#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF +#endif + #if KHRONOS_SUPPORT_INT64 /* EGLTimeKHR requires 64-bit uint support */ #ifndef EGL_NV_system_time #define EGL_NV_system_time 1 typedef khronos_utime_nanoseconds_t EGLuint64NV; #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV(void);
--- a/gfx/angle/include/GLES2/gl2ext.h +++ b/gfx/angle/include/GLES2/gl2ext.h @@ -217,16 +217,22 @@ typedef void* GLeglImageOES; #define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3 #endif /* GL_ANGLE_translated_shader_source */ #ifndef GL_ANGLE_translated_shader_source #define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0 #endif +/* GL_ANGLE_texture_usage */ +#ifndef GL_ANGLE_texture_usage +#define GL_TEXTURE_USAGE_ANGLE 0x93A2 +#define GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3 +#endif + /*------------------------------------------------------------------------* * APPLE extension tokens *------------------------------------------------------------------------*/ /* GL_APPLE_rgb_422 */ #ifndef GL_APPLE_rgb_422 #define GL_RGB_422_APPLE 0x8A1F #define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA @@ -320,16 +326,52 @@ typedef void* GLeglImageOES; /* GL_EXT_unpack_subimage */ #ifndef GL_EXT_unpack_subimage #define GL_UNPACK_ROW_LENGTH 0x0CF2 #define GL_UNPACK_SKIP_ROWS 0x0CF3 #define GL_UNPACK_SKIP_PIXELS 0x0CF4 #endif +/* GL_EXT_robustness */ +#ifndef GL_EXT_robustness +#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253 +#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255 +#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3 +#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256 +#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252 +#define GL_NO_RESET_NOTIFICATION_EXT 0x8261 +#endif + +/* GL_EXT_texture_storage */ +#ifndef GL_EXT_texture_storage +#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F +#define GL_ALPHA8_EXT 0x803C +#define GL_LUMINANCE8_EXT 0x8040 +#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 +/* OES_texture_float dependent internal formats */ +#define GL_RGBA32F_EXT 0x8814 /* reuse tokens from ARB_texture_float */ +#define GL_RGB32F_EXT 0x8815 +#define GL_ALPHA32F_EXT 0x8816 +#define GL_LUMINANCE32F_EXT 0x8818 +#define GL_LUMINANCE_ALPHA32F_EXT 0x8819 +/* OES_texture_half_float dependent internal formats */ +#define GL_RGBA16F_EXT 0x881A /* reuse tokens from ARB_texture_float */ +#define GL_RGB16F_EXT 0x881B +#define GL_ALPHA16F_EXT 0x881C +#define GL_LUMINANCE16F_EXT 0x881E +#define GL_LUMINANCE_ALPHA16F_EXT 0x881F +/* EXT_texture_type_2_10_10_10_REV dependent internal formats */ +#define GL_RGB10_A2_EXT 0x8059 /* reuse tokens from EXT_texture */ +#define GL_RGB10_EXT 0x8052 +/* EXT_texture_format_BGRA8888 dependent internal formats */ +#define GL_BGRA8_EXT 0x93A1 +#endif + /*------------------------------------------------------------------------* * DMP extension tokens *------------------------------------------------------------------------*/ /* GL_DMP_shader_binary */ #ifndef GL_DMP_shader_binary #define GL_SHADER_BINARY_DMP 0x9250 #endif @@ -819,16 +861,21 @@ typedef void (GL_APIENTRYP PFNGLRENDERBU #ifndef GL_ANGLE_translated_shader_source #define GL_ANGLE_translated_shader_source 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); #endif typedef void (GL_APIENTRYP PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); #endif +/* GL_ANGLE_texture_usage */ +#ifndef GL_ANGLE_texture_usage +#define GL_ANGLE_texture_usage 1 +#endif + /*------------------------------------------------------------------------* * APPLE extension functions *------------------------------------------------------------------------*/ /* GL_APPLE_rgb_422 */ #ifndef GL_APPLE_rgb_422 #define GL_APPLE_rgb_422 1 #endif @@ -926,16 +973,40 @@ typedef void (GL_APIENTRYP PFNGLMULTIDRA #define GL_EXT_texture_compression_dxt1 1 #endif /* GL_EXT_unpack_subimage */ #ifndef GL_EXT_unpack_subimage #define GL_EXT_unpack_subimage 1 #endif +/* GL_EXT_robustness */ +#ifndef GL_EXT_robustness +#define GL_EXT_robustness 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void); +GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); +GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void); +typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); +typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); +#endif + +/* GL_EXT_texture_storage */ +#ifndef GL_EXT_texture_storage +#define GL_EXT_texture_storage 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY TexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXT) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +#endif + /*------------------------------------------------------------------------* * DMP extension functions *------------------------------------------------------------------------*/ /* GL_DMP_shader_binary */ #ifndef GL_DMP_shader_binary #define GL_DMP_shader_binary 1 #endif
--- a/gfx/angle/src/common/version.h +++ b/gfx/angle/src/common/version.h @@ -1,10 +1,10 @@ #define MAJOR_VERSION 0 #define MINOR_VERSION 0 #define BUILD_VERSION 0 -#define BUILD_REVISION 809 +#define BUILD_REVISION 885 #define STRINGIFY(x) #x #define MACRO_STRINGIFY(x) STRINGIFY(x) #define REVISION_STRING MACRO_STRINGIFY(BUILD_REVISION) #define VERSION_STRING MACRO_STRINGIFY(MAJOR_VERSION) "." MACRO_STRINGIFY(MINOR_VERSION) "." MACRO_STRINGIFY(BUILD_VERSION) "." MACRO_STRINGIFY(BUILD_REVISION)
--- a/gfx/angle/src/compiler/Initialize.cpp +++ b/gfx/angle/src/compiler/Initialize.cpp @@ -619,17 +619,17 @@ void IdentifyBuiltIns(ShShaderType type, break; default: break; } // Finally add resource-specific variables. switch(type) { case SH_FRAGMENT_SHADER: { // Set up gl_FragData. The array size. - TType fragData(EbtFloat, EbpMedium, EvqFragColor, 4, false, true); + TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, false, true); fragData.setArraySize(resources.MaxDrawBuffers); symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData)); } break; default: break; } }
--- a/gfx/angle/src/libEGL/Display.cpp +++ b/gfx/angle/src/libEGL/Display.cpp @@ -83,16 +83,17 @@ Display::Display(EGLNativeDisplayType di #else mDeviceType = D3DDEVTYPE_HAL; #endif mMinSwapInterval = 1; mMaxSwapInterval = 1; mSoftwareDevice = software; mDisplayId = displayId; + mDeviceLost = false; } Display::~Display() { terminate(); DisplayMap::iterator thisDisplay = displays.find(mDisplayId); @@ -299,17 +300,17 @@ void Display::terminate() while (!mContextSet.empty()) { destroyContext(*mContextSet.begin()); } if (mDevice) { // If the device is lost, reset it first to prevent leaving the driver in an unstable state - if (isDeviceLost()) + if (testDeviceLost()) { resetDevice(); } mDevice->Release(); mDevice = NULL; } @@ -452,33 +453,54 @@ bool Display::createDevice() mSceneStarted = false; return true; } bool Display::resetDevice() { D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); - HRESULT result; - - do + + HRESULT result = D3D_OK; + bool lost = testDeviceLost(); + int attempts = 3; + + while (lost && attempts > 0) { - Sleep(0); // Give the graphics driver some CPU time + if (mDeviceEx) + { + Sleep(500); // Give the graphics driver some CPU time + result = mDeviceEx->ResetEx(&presentParameters, NULL); + } + else + { + result = mDevice->TestCooperativeLevel(); + + while (result == D3DERR_DEVICELOST) + { + Sleep(100); // Give the graphics driver some CPU time + result = mDevice->TestCooperativeLevel(); + } - result = mDevice->Reset(&presentParameters); + if (result == D3DERR_DEVICENOTRESET) + { + result = mDevice->Reset(&presentParameters); + } + } + + lost = testDeviceLost(); + attempts --; } - while (result == D3DERR_DEVICELOST); if (FAILED(result)) { + ERR("Reset/ResetEx failed multiple times: 0x%08X", result); return error(EGL_BAD_ALLOC, false); } - ASSERT(SUCCEEDED(result)); - return true; } EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList) { const Config *configuration = mConfigSet.get(config); if (attribList) @@ -510,17 +532,18 @@ EGLSurface Display::createWindowSurface( } } if (hasExistingWindowSurface(window)) { return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); } - if (isDeviceLost()) { + if (testDeviceLost()) + { if (!restoreLostDevice()) return EGL_NO_SURFACE; } Surface *surface = new Surface(this, configuration, window); if (!surface->initialize()) { @@ -622,17 +645,18 @@ EGLSurface Display::createOffscreenSurfa } if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) || (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE)) { return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } - if (isDeviceLost()) { + if (testDeviceLost()) + { if (!restoreLostDevice()) return EGL_NO_SURFACE; } Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget); if (!surface->initialize()) { @@ -640,41 +664,48 @@ EGLSurface Display::createOffscreenSurfa return EGL_NO_SURFACE; } mSurfaceSet.insert(surface); return success(surface); } -EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext) +EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess) { if (!mDevice) { if (!createDevice()) { return NULL; } } - else if (isDeviceLost()) // Lost device + else if (testDeviceLost()) // Lost device { if (!restoreLostDevice()) return NULL; } const egl::Config *config = mConfigSet.get(configHandle); - gl::Context *context = glCreateContext(config, shareContext); + gl::Context *context = glCreateContext(config, shareContext, notifyResets, robustAccess); mContextSet.insert(context); + mDeviceLost = false; return context; } bool Display::restoreLostDevice() { + for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++) + { + if ((*ctx)->isResetNotificationEnabled()) + return false; // If reset notifications have been requested, application must delete all contexts first + } + // Release surface resources to make the Reset() succeed for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) { (*surface)->release(); } if (!resetDevice()) { @@ -698,16 +729,31 @@ void Display::destroySurface(egl::Surfac } void Display::destroyContext(gl::Context *context) { glDestroyContext(context); mContextSet.erase(context); } +void Display::notifyDeviceLost() +{ + for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) + { + (*context)->markContextLost(); + } + mDeviceLost = true; + error(EGL_CONTEXT_LOST); +} + +bool Display::isDeviceLost() +{ + return mDeviceLost; +} + bool Display::isInitialized() const { return mD3d9 != NULL && mConfigSet.size() > 0; } bool Display::isValidConfig(EGLConfig config) { return mConfigSet.get(config) != NULL; @@ -764,30 +810,53 @@ D3DCAPS9 Display::getDeviceCaps() return mDeviceCaps; } D3DADAPTER_IDENTIFIER9 *Display::getAdapterIdentifier() { return &mAdapterIdentifier; } -bool Display::isDeviceLost() +bool Display::testDeviceLost() { if (mDeviceEx) { return FAILED(mDeviceEx->CheckDeviceState(NULL)); } - else if(mDevice) + else if (mDevice) { return FAILED(mDevice->TestCooperativeLevel()); } return false; // No device yet, so no reset required } +bool Display::testDeviceResettable() +{ + HRESULT status = D3D_OK; + + if (mDeviceEx) + { + status = mDeviceEx->CheckDeviceState(NULL); + } + else if (mDevice) + { + status = mDevice->TestCooperativeLevel(); + } + + switch (status) + { + case D3DERR_DEVICENOTRESET: + case D3DERR_DEVICEHUNG: + return true; + default: + return false; + } +} + void Display::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); @@ -813,17 +882,17 @@ bool Display::getDXT3TextureSupport() bool Display::getDXT5TextureSupport() { D3DDISPLAYMODE currentDisplayMode; mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5)); } -bool Display::getFloatTextureSupport(bool *filtering, bool *renderable) +bool Display::getFloat32TextureSupport(bool *filtering, bool *renderable) { D3DDISPLAYMODE currentDisplayMode; mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); *filtering = 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)); @@ -841,17 +910,17 @@ bool Display::getFloatTextureSupport(boo D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); } else { return true; } } -bool Display::getHalfFloatTextureSupport(bool *filtering, bool *renderable) +bool Display::getFloat16TextureSupport(bool *filtering, bool *renderable) { D3DDISPLAYMODE currentDisplayMode; mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); *filtering = 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)); @@ -902,16 +971,33 @@ D3DPOOL Display::getBufferPool(DWORD usa { return D3DPOOL_MANAGED; } } return D3DPOOL_DEFAULT; } +D3DPOOL Display::getTexturePool(bool renderable) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!renderable) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + bool Display::getEventQuerySupport() { IDirect3DQuery9 *query; HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query); if (SUCCEEDED(result)) { query->Release(); } @@ -943,16 +1029,20 @@ D3DPRESENT_PARAMETERS Display::getDefaul void Display::initExtensionString() { HMODULE swiftShader = GetModuleHandle(TEXT("swiftshader_d3d9.dll")); bool isd3d9ex = isD3d9ExDevice(); mExtensionString = ""; + // Multi-vendor (EXT) extensions + mExtensionString += "EGL_EXT_create_context_robustness "; + + // ANGLE-specific extensions if (isd3d9ex) { mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer "; } mExtensionString += "EGL_ANGLE_query_surface_pointer "; if (swiftShader) {
--- a/gfx/angle/src/libEGL/Display.h +++ b/gfx/angle/src/libEGL/Display.h @@ -39,46 +39,51 @@ class Display static egl::Display *getDisplay(EGLNativeDisplayType displayId); bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig); bool getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value); EGLSurface createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList); EGLSurface createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList); - EGLContext createContext(EGLConfig configHandle, const gl::Context *shareContext); + EGLContext createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess); void destroySurface(egl::Surface *surface); void destroyContext(gl::Context *context); bool isInitialized() const; bool isValidConfig(EGLConfig config); bool isValidContext(gl::Context *context); bool isValidSurface(egl::Surface *surface); bool hasExistingWindowSurface(HWND window); EGLint getMinSwapInterval(); EGLint getMaxSwapInterval(); virtual IDirect3DDevice9 *getDevice(); virtual D3DCAPS9 getDeviceCaps(); virtual D3DADAPTER_IDENTIFIER9 *getAdapterIdentifier(); - bool isDeviceLost(); + virtual bool testDeviceLost(); + virtual bool testDeviceResettable(); virtual void getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray); virtual bool getDXT1TextureSupport(); virtual bool getDXT3TextureSupport(); virtual bool getDXT5TextureSupport(); virtual bool getEventQuerySupport(); - virtual bool getFloatTextureSupport(bool *filtering, bool *renderable); - virtual bool getHalfFloatTextureSupport(bool *filtering, bool *renderable); + virtual bool getFloat32TextureSupport(bool *filtering, bool *renderable); + virtual bool getFloat16TextureSupport(bool *filtering, bool *renderable); virtual bool getLuminanceTextureSupport(); virtual bool getLuminanceAlphaTextureSupport(); virtual bool getVertexTextureSupport() const; virtual bool getNonPower2TextureSupport() const; virtual D3DPOOL getBufferPool(DWORD usage) const; + virtual D3DPOOL getTexturePool(bool renderable) const; + + virtual void notifyDeviceLost(); + bool isDeviceLost(); bool isD3d9ExDevice() { return mD3d9Ex != NULL; } const char *getExtensionString() const; private: DISALLOW_COPY_AND_ASSIGN(Display); Display(EGLNativeDisplayType displayId, HDC deviceContext, bool software); @@ -109,16 +114,17 @@ class Display typedef std::set<Surface*> SurfaceSet; SurfaceSet mSurfaceSet; ConfigSet mConfigSet; typedef std::set<gl::Context*> ContextSet; ContextSet mContextSet; + bool mDeviceLost; bool createDevice(); bool resetDevice(); void initExtensionString(); std::string mExtensionString; }; }
--- a/gfx/angle/src/libEGL/Surface.cpp +++ b/gfx/angle/src/libEGL/Surface.cpp @@ -101,17 +101,17 @@ bool Surface::initialize() if (SUCCEEDED(result) && isComposited) { DWM_PRESENT_PARAMETERS presentParams; memset(&presentParams, 0, sizeof(presentParams)); presentParams.cbSize = sizeof(DWM_PRESENT_PARAMETERS); presentParams.cBuffer = 2; result = DwmSetPresentParameters(mWindow, &presentParams); if (FAILED(result)) - ERR("Unable to set present parameters: %081X", result); + ERR("Unable to set present parameters: 0x%08X", result); } } return true; } void Surface::release() { @@ -245,35 +245,44 @@ bool Surface::resetSwapChain(int backbuf } result = device->CreateTexture(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight, 1, D3DUSAGE_RENDERTARGET, presentParameters.BackBufferFormat, D3DPOOL_DEFAULT, &mOffscreenTexture, pShareHandle); } if (FAILED(result)) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL); + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST); ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); release(); - return error(EGL_BAD_ALLOC, false); + + if(isDeviceLostError(result)) + { + mDisplay->notifyDeviceLost(); + return false; + } + else + { + return error(EGL_BAD_ALLOC, false); + } } if (mConfig->mDepthStencilFormat != D3DFMT_UNKNOWN) { result = device->CreateDepthStencilSurface(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight, presentParameters.AutoDepthStencilFormat, presentParameters.MultiSampleType, presentParameters.MultiSampleQuality, FALSE, &mDepthStencil, NULL); } if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL); - ERR("Could not create depthstencil surface for new swap chain: %08lX", result); + ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); release(); return error(EGL_BAD_ALLOC, false); } if (mWindow) { mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mRenderTarget); InvalidateRect(mWindow, NULL, FALSE); } else { @@ -408,24 +417,25 @@ DWORD Surface::convertInterval(EGLint in bool Surface::swap() { if (mSwapChain) { mDisplay->endScene(); HRESULT result = mSwapChain->Present(NULL, NULL, NULL, NULL, 0); - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) { return error(EGL_BAD_ALLOC, false); } - if (result == D3DERR_DEVICELOST || result == D3DERR_DEVICEHUNG || result == D3DERR_DEVICEREMOVED) + if (isDeviceLostError(result)) { - return error(EGL_CONTEXT_LOST, false); + mDisplay->notifyDeviceLost(); + return false; } ASSERT(SUCCEEDED(result)); checkForOutOfDateSwapChain(); } return true;
--- a/gfx/angle/src/libEGL/libEGL.cpp +++ b/gfx/angle/src/libEGL/libEGL.cpp @@ -710,17 +710,20 @@ EGLBoolean __stdcall eglBindTexImage(EGL return error(EGL_BAD_ACCESS, EGL_FALSE); } if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) { return error(EGL_BAD_MATCH, EGL_FALSE); } - glBindTexImage(eglSurface); + if (!glBindTexImage(eglSurface)) + { + return error(EGL_BAD_MATCH, EGL_FALSE); + } return success(EGL_TRUE); } catch(std::bad_alloc&) { return error(EGL_BAD_ALLOC, EGL_FALSE); } @@ -809,46 +812,72 @@ EGLContext __stdcall eglCreateContext(EG { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLContext share_context = 0x%0.8p, " "const EGLint *attrib_list = 0x%0.8p)", dpy, config, share_context, attrib_list); try { // Get the requested client version (default is 1) and check it is two. EGLint client_version = 1; + bool reset_notification = false; + bool robust_access = false; + if (attrib_list) { for (const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) { - if (attribute[0] == EGL_CONTEXT_CLIENT_VERSION) + switch (attribute[0]) { + case EGL_CONTEXT_CLIENT_VERSION: client_version = attribute[1]; - } - else - { + break; + case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: + if (attribute[1] == EGL_TRUE) + { + return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); // Unimplemented + robust_access = true; + } + else if (attribute[1] != EGL_FALSE) + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + break; + case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: + if (attribute[1] == EGL_LOSE_CONTEXT_ON_RESET_EXT) + reset_notification = true; + else if (attribute[1] != EGL_NO_RESET_NOTIFICATION_EXT) + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + break; + default: return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); } } } if (client_version != 2) { return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); } + if (share_context && static_cast<gl::Context*>(share_context)->isResetNotificationEnabled() != reset_notification) + { + return error(EGL_BAD_MATCH, EGL_NO_CONTEXT); + } + egl::Display *display = static_cast<egl::Display*>(dpy); if (!validateConfig(display, config)) { return EGL_NO_CONTEXT; } - EGLContext context = display->createContext(config, static_cast<gl::Context*>(share_context)); + EGLContext context = display->createContext(config, static_cast<gl::Context*>(share_context), reset_notification, robust_access); - return success(context); + if (context) + return success(context); + else + return error(EGL_CONTEXT_LOST, EGL_NO_CONTEXT); } catch(std::bad_alloc&) { return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT); } return EGL_NO_CONTEXT; } @@ -890,17 +919,23 @@ EGLBoolean __stdcall eglMakeCurrent(EGLD dpy, draw, read, ctx); try { egl::Display *display = static_cast<egl::Display*>(dpy); gl::Context *context = static_cast<gl::Context*>(ctx); IDirect3DDevice9 *device = display->getDevice(); - if (!device || display->isDeviceLost()) + if (!device || display->testDeviceLost()) + { + display->notifyDeviceLost(); + return EGL_FALSE; + } + + if (display->isDeviceLost()) { return error(EGL_CONTEXT_LOST, EGL_FALSE); } if (ctx != EGL_NO_CONTEXT && !validateContext(display, context)) { return EGL_FALSE; } @@ -1072,16 +1107,21 @@ EGLBoolean __stdcall eglSwapBuffers(EGLD egl::Display *display = static_cast<egl::Display*>(dpy); egl::Surface *eglSurface = (egl::Surface*)surface; if (!validateSurface(display, eglSurface)) { return EGL_FALSE; } + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + if (surface == EGL_NO_SURFACE) { return error(EGL_BAD_SURFACE, EGL_FALSE); } if (eglSurface->swap()) { return success(EGL_TRUE); @@ -1104,16 +1144,21 @@ EGLBoolean __stdcall eglCopyBuffers(EGLD egl::Display *display = static_cast<egl::Display*>(dpy); egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); if (!validateSurface(display, eglSurface)) { return EGL_FALSE; } + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + UNIMPLEMENTED(); // FIXME return success(0); } catch(std::bad_alloc&) { return error(EGL_BAD_ALLOC, EGL_FALSE); }
--- a/gfx/angle/src/libGLESv2/Context.cpp +++ b/gfx/angle/src/libGLESv2/Context.cpp @@ -33,18 +33,20 @@ namespace { enum { CLOSING_INDEX_BUFFER_SIZE = 4096 }; } namespace gl { -Context::Context(const egl::Config *config, const gl::Context *shareContext) : mConfig(config) +Context::Context(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess) : mConfig(config) { + ASSERT(robustAccess == false); // Unimplemented + mDisplay = NULL; mDevice = NULL; mFenceHandleAllocator.setBaseHandle(0); setClearColor(0.0f, 0.0f, 0.0f, 0.0f); mState.depthClearValue = 1.0f; @@ -153,16 +155,20 @@ Context::Context(const egl::Config *conf mInvalidEnum = false; mInvalidValue = false; mInvalidOperation = false; mOutOfMemory = false; mInvalidFramebufferOperation = false; mHasBeenCurrent = false; + mContextLost = false; + mResetStatus = GL_NO_ERROR; + mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT); + mRobustAccess = robustAccess; mSupportsDXT1Textures = false; mSupportsDXT3Textures = false; mSupportsDXT5Textures = false; mSupportsEventQueries = false; mNumCompressedTextureFormats = 0; mMaxSupportedSamples = 0; mMaskedClearSavedState = NULL; @@ -285,18 +291,18 @@ void Context::makeCurrent(egl::Display * } mMaxSupportedSamples = max; mSupportsEventQueries = mDisplay->getEventQuerySupport(); mSupportsDXT1Textures = mDisplay->getDXT1TextureSupport(); mSupportsDXT3Textures = mDisplay->getDXT3TextureSupport(); mSupportsDXT5Textures = mDisplay->getDXT5TextureSupport(); - mSupportsFloatTextures = mDisplay->getFloatTextureSupport(&mSupportsFloatLinearFilter, &mSupportsFloatRenderableTextures); - mSupportsHalfFloatTextures = mDisplay->getHalfFloatTextureSupport(&mSupportsHalfFloatLinearFilter, &mSupportsHalfFloatRenderableTextures); + mSupportsFloat32Textures = mDisplay->getFloat32TextureSupport(&mSupportsFloat32LinearFilter, &mSupportsFloat32RenderableTextures); + mSupportsFloat16Textures = mDisplay->getFloat16TextureSupport(&mSupportsFloat16LinearFilter, &mSupportsFloat16RenderableTextures); mSupportsLuminanceTextures = mDisplay->getLuminanceTextureSupport(); mSupportsLuminanceAlphaTextures = mDisplay->getLuminanceAlphaTextureSupport(); mSupports32bitIndices = mDeviceCaps.MaxVertexIndex >= (1 << 16); mNumCompressedTextureFormats = 0; if (supportsDXT1Textures()) { @@ -384,16 +390,28 @@ void Context::markAllStateDirty() mScissorStateDirty = true; mSampleStateDirty = true; mDitherStateDirty = true; mFrontFaceDirty = true; mDxUniformsDirty = true; mCachedCurrentProgram = NULL; } +void Context::markContextLost() +{ + if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT) + mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT; + mContextLost = true; +} + +bool Context::isContextLost() +{ + return mContextLost; +} + void Context::setClearColor(float red, float green, float blue, float alpha) { mState.colorClearValue.red = red; mState.colorClearValue.green = green; mState.colorClearValue.blue = blue; mState.colorClearValue.alpha = alpha; } @@ -1153,34 +1171,35 @@ Texture *Context::getSamplerTexture(unsi return mState.samplerTexture[type][sampler].get(); } bool 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.depthMask; break; + case GL_SHADER_COMPILER: *params = GL_TRUE; break; + case GL_SAMPLE_COVERAGE_INVERT: *params = mState.sampleCoverageInvert; break; + case GL_DEPTH_WRITEMASK: *params = mState.depthMask; break; case GL_COLOR_WRITEMASK: params[0] = mState.colorMaskRed; params[1] = mState.colorMaskGreen; params[2] = mState.colorMaskBlue; params[3] = mState.colorMaskAlpha; break; - case GL_CULL_FACE: *params = mState.cullFace; break; - case GL_POLYGON_OFFSET_FILL: *params = mState.polygonOffsetFill; break; - case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.sampleAlphaToCoverage; break; - case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break; - case GL_SCISSOR_TEST: *params = mState.scissorTest; break; - case GL_STENCIL_TEST: *params = mState.stencilTest; break; - case GL_DEPTH_TEST: *params = mState.depthTest; break; - case GL_BLEND: *params = mState.blend; break; - case GL_DITHER: *params = mState.dither; break; + case GL_CULL_FACE: *params = mState.cullFace; break; + case GL_POLYGON_OFFSET_FILL: *params = mState.polygonOffsetFill; break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.sampleAlphaToCoverage; break; + case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break; + case GL_SCISSOR_TEST: *params = mState.scissorTest; break; + case GL_STENCIL_TEST: *params = mState.stencilTest; break; + case GL_DEPTH_TEST: *params = mState.depthTest; break; + case GL_BLEND: *params = mState.blend; break; + case GL_DITHER: *params = mState.dither; break; + case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break; default: return false; } return true; } bool Context::getFloatv(GLenum pname, GLfloat *params) @@ -1370,17 +1389,17 @@ bool Context::getIntegerv(GLenum pname, case GL_CULL_FACE_MODE: *params = mState.cullMode; break; case GL_FRONT_FACE: *params = mState.frontFace; break; case GL_RED_BITS: case GL_GREEN_BITS: case GL_BLUE_BITS: case GL_ALPHA_BITS: { gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::Colorbuffer *colorbuffer = framebuffer->getColorbuffer(); + gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(); 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; @@ -1391,32 +1410,32 @@ bool Context::getIntegerv(GLenum pname, { *params = 0; } } break; case GL_DEPTH_BITS: { gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::DepthStencilbuffer *depthbuffer = framebuffer->getDepthbuffer(); + gl::Renderbuffer *depthbuffer = framebuffer->getDepthbuffer(); if (depthbuffer) { *params = depthbuffer->getDepthSize(); } else { *params = 0; } } break; case GL_STENCIL_BITS: { gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::DepthStencilbuffer *stencilbuffer = framebuffer->getStencilbuffer(); + gl::Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer(); if (stencilbuffer) { *params = stencilbuffer->getStencilSize(); } else { *params = 0; @@ -1440,16 +1459,19 @@ bool Context::getIntegerv(GLenum pname, { error(GL_INVALID_OPERATION); return false; } *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id(); } break; + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + *params = mResetStrategy; + break; default: return false; } return true; } bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) @@ -1529,16 +1551,17 @@ bool Context::getQueryParameterInfo(GLen case GL_MAX_TEXTURE_SIZE: case GL_MAX_CUBE_MAP_TEXTURE_SIZE: case GL_SAMPLE_BUFFERS: case GL_SAMPLES: case GL_IMPLEMENTATION_COLOR_READ_TYPE: case GL_IMPLEMENTATION_COLOR_READ_FORMAT: case GL_TEXTURE_BINDING_2D: case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_RESET_NOTIFICATION_STRATEGY_EXT: { *type = GL_INT; *numParams = 1; } break; case GL_MAX_SAMPLES_ANGLE: { if (getMaxSupportedSamples() != 0) @@ -1572,16 +1595,17 @@ bool Context::getQueryParameterInfo(GLen case GL_POLYGON_OFFSET_FILL: // but can be retrieved through the Get{Type}v queries. case GL_SAMPLE_ALPHA_TO_COVERAGE: // For this purpose, they are treated here as bool-natural case GL_SAMPLE_COVERAGE: case GL_SCISSOR_TEST: case GL_STENCIL_TEST: case GL_DEPTH_TEST: case GL_BLEND: case GL_DITHER: + case GL_CONTEXT_ROBUST_ACCESS_EXT: { *type = GL_BOOL; *numParams = 1; } break; case GL_COLOR_WRITEMASK: { *type = GL_BOOL; @@ -1725,17 +1749,17 @@ bool Context::applyRenderTarget(bool ign viewport.MaxZ = zFar; } if (viewport.Width <= 0 || viewport.Height <= 0) { return false; // Nothing to render } - if (!mViewportInitialized || memcmp(&viewport, &mSetViewport, sizeof mSetViewport) != 0) + if (renderTargetChanged || !mViewportInitialized || memcmp(&viewport, &mSetViewport, sizeof mSetViewport) != 0) { mDevice->SetViewport(&viewport); mSetViewport = viewport; mViewportInitialized = true; mDxUniformsDirty = true; } if (mScissorStateDirty) @@ -1906,17 +1930,17 @@ void Context::applyState(GLenum drawMode mState.stencilRef != mState.stencilBackRef || mState.stencilMask != mState.stencilBackMask) { ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are invalid under WebGL."); return error(GL_INVALID_OPERATION); } // get the maximum size of the stencil ref - gl::DepthStencilbuffer *stencilbuffer = framebufferObject->getStencilbuffer(); + gl::Renderbuffer *stencilbuffer = framebufferObject->getStencilbuffer(); GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1; mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask); mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, es2dx::ConvertComparison(mState.stencilFunc)); mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil); mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilMask); @@ -1973,17 +1997,17 @@ void Context::applyState(GLenum drawMode mMaskStateDirty = false; } if (mPolygonOffsetStateDirty) { if (mState.polygonOffsetFill) { - gl::DepthStencilbuffer *depthbuffer = framebufferObject->getDepthbuffer(); + gl::Renderbuffer *depthbuffer = framebufferObject->getDepthbuffer(); if (depthbuffer) { mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor)); float depthBias = ldexp(mState.polygonOffsetUnits, -(int)(depthbuffer->getDepthSize())); mDevice->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&depthBias)); } } else @@ -2122,50 +2146,50 @@ void Context::applyTextures(SamplerType int d3dSampler = samplerIndex + d3dSamplerOffset; if (textureUnit != -1) { TextureType textureType = programObject->getSamplerTextureType(type, samplerIndex); Texture *texture = getSamplerTexture(textureUnit, textureType); - if (appliedTextureSerial[samplerIndex] != texture->getSerial() || texture->isDirtyParameter() || texture->isDirtyImage()) + if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyParameters() || texture->hasDirtyImages()) { IDirect3DBaseTexture9 *d3dTexture = texture->getTexture(); if (d3dTexture) { - if (appliedTextureSerial[samplerIndex] != texture->getSerial() || texture->isDirtyParameter()) + if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyParameters()) { GLenum wrapS = texture->getWrapS(); GLenum wrapT = texture->getWrapT(); GLenum minFilter = texture->getMinFilter(); GLenum magFilter = texture->getMagFilter(); mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS)); mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT)); mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter)); D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter); mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); } - if (appliedTextureSerial[samplerIndex] != texture->getSerial() || texture->isDirtyImage()) + if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyImages()) { mDevice->SetTexture(d3dSampler, d3dTexture); } } else { mDevice->SetTexture(d3dSampler, getIncompleteTexture(textureType)->getTexture()); } - appliedTextureSerial[samplerIndex] = texture->getSerial(); + appliedTextureSerial[samplerIndex] = texture->getTextureSerial(); texture->resetDirty(); } } else { if (appliedTextureSerial[samplerIndex] != 0) { mDevice->SetTexture(d3dSampler, NULL); @@ -2179,30 +2203,42 @@ void Context::applyTextures(SamplerType if (appliedTextureSerial[samplerIndex] != 0) { mDevice->SetTexture(samplerIndex + d3dSamplerOffset, NULL); appliedTextureSerial[samplerIndex] = 0; } } } -void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) +void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, void* pixels) { Framebuffer *framebuffer = getReadFramebuffer(); if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) { return error(GL_INVALID_FRAMEBUFFER_OPERATION); } if (getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0) { return error(GL_INVALID_OPERATION); } + GLsizei outputPitch = ComputePitch(width, format, type, mState.packAlignment); + // sized query sanity check + if (bufSize) + { + int requiredSize = outputPitch * height; + if (requiredSize > *bufSize) + { + return error(GL_INVALID_OPERATION); + } + } + IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget(); if (!renderTarget) { return; // Context must be lost, return silently } D3DSURFACE_DESC desc; @@ -2224,28 +2260,26 @@ void Context::readPixels(GLint x, GLint } result = mDevice->GetRenderTargetData(renderTarget, systemSurface); if (FAILED(result)) { systemSurface->Release(); - switch (result) + // It turns out that D3D will sometimes produce more error + // codes than those documented. + if (checkDeviceLost(result)) + return error(GL_OUT_OF_MEMORY); + else { - // It turns out that D3D will sometimes produce more error - // codes than those documented. - case D3DERR_DRIVERINTERNALERROR: - case D3DERR_DEVICELOST: - case D3DERR_DEVICEHUNG: - return error(GL_OUT_OF_MEMORY); - default: UNREACHABLE(); - return; // No sensible error to generate + return; } + } D3DLOCKED_RECT lock; RECT rect = transformPixelRect(x, y, width, height, desc.Height); rect.left = clamp(rect.left, 0L, static_cast<LONG>(desc.Width)); rect.top = clamp(rect.top, 0L, static_cast<LONG>(desc.Height)); rect.right = clamp(rect.right, 0L, static_cast<LONG>(desc.Width)); rect.bottom = clamp(rect.bottom, 0L, static_cast<LONG>(desc.Height)); @@ -2259,17 +2293,16 @@ void Context::readPixels(GLint x, GLint return; // No sensible error to generate } unsigned char *source = ((unsigned char*)lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); unsigned char *dest = (unsigned char*)pixels; unsigned short *dest16 = (unsigned short*)pixels; int inputPitch = -lock.Pitch; - GLsizei outputPitch = ComputePitch(width, format, type, mState.packAlignment); for (int j = 0; j < rect.bottom - rect.top; j++) { if (desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE) { // Fast path for EXT_read_format_bgra, given @@ -2821,17 +2854,17 @@ void Context::sync(bool block) // Keep polling, but allow other threads to do something useful first Sleep(0); } } while(block && result == S_FALSE); eventQuery->Release(); - if (result == D3DERR_DEVICELOST) + if (checkDeviceLost(result)) { error(GL_OUT_OF_MEMORY); } } void Context::drawClosingLine(unsigned int first, unsigned int last) { IDirect3DIndexBuffer9 *indexBuffer = NULL; @@ -2989,16 +3022,46 @@ GLenum Context::getError() mInvalidFramebufferOperation = false; return GL_INVALID_FRAMEBUFFER_OPERATION; } return GL_NO_ERROR; } +GLenum Context::getResetStatus() +{ + if (mResetStatus == GL_NO_ERROR) + { + bool lost = mDisplay->testDeviceLost(); + + if (lost) + { + mDisplay->notifyDeviceLost(); // Sets mResetStatus + } + } + + GLenum status = mResetStatus; + + if (mResetStatus != GL_NO_ERROR) + { + if (mDisplay->testDeviceResettable()) + { + mResetStatus = GL_NO_ERROR; + } + } + + return status; +} + +bool Context::isResetNotificationEnabled() +{ + return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); +} + bool Context::supportsShaderModel3() const { return mSupportsShaderModel3; } int Context::getMaximumVaryingVectors() const { return mSupportsShaderModel3 ? MAX_VARYING_VECTORS_SM3 : MAX_VARYING_VECTORS_SM2; @@ -3063,44 +3126,44 @@ bool Context::supportsDXT3Textures() con return mSupportsDXT3Textures; } bool Context::supportsDXT5Textures() const { return mSupportsDXT5Textures; } -bool Context::supportsFloatTextures() const +bool Context::supportsFloat32Textures() const { - return mSupportsFloatTextures; + return mSupportsFloat32Textures; } -bool Context::supportsFloatLinearFilter() const +bool Context::supportsFloat32LinearFilter() const { - return mSupportsFloatLinearFilter; + return mSupportsFloat32LinearFilter; } -bool Context::supportsFloatRenderableTextures() const +bool Context::supportsFloat32RenderableTextures() const { - return mSupportsFloatRenderableTextures; + return mSupportsFloat32RenderableTextures; } -bool Context::supportsHalfFloatTextures() const +bool Context::supportsFloat16Textures() const { - return mSupportsHalfFloatTextures; + return mSupportsFloat16Textures; } -bool Context::supportsHalfFloatLinearFilter() const +bool Context::supportsFloat16LinearFilter() const { - return mSupportsHalfFloatLinearFilter; + return mSupportsFloat16LinearFilter; } -bool Context::supportsHalfFloatRenderableTextures() const +bool Context::supportsFloat16RenderableTextures() const { - return mSupportsHalfFloatRenderableTextures; + return mSupportsFloat16RenderableTextures; } int Context::getMaximumRenderbufferDimension() const { return mMaxRenderbufferDimension; } int Context::getMaximumTextureDimension() const @@ -3339,63 +3402,67 @@ void Context::initExtensionString() { mExtensionString += "GL_OES_element_index_uint "; } mExtensionString += "GL_OES_packed_depth_stencil "; mExtensionString += "GL_OES_rgb8_rgba8 "; mExtensionString += "GL_OES_standard_derivatives "; - if (supportsHalfFloatTextures()) + if (supportsFloat16Textures()) { mExtensionString += "GL_OES_texture_half_float "; } - if (supportsHalfFloatLinearFilter()) + if (supportsFloat16LinearFilter()) { mExtensionString += "GL_OES_texture_half_float_linear "; } - if (supportsFloatTextures()) + if (supportsFloat32Textures()) { mExtensionString += "GL_OES_texture_float "; } - if (supportsFloatLinearFilter()) + if (supportsFloat32LinearFilter()) { mExtensionString += "GL_OES_texture_float_linear "; } if (supportsNonPower2Texture()) { mExtensionString += "GL_OES_texture_npot "; } // Multi-vendor (EXT) extensions mExtensionString += "GL_EXT_read_format_bgra "; + mExtensionString += "GL_EXT_robustness "; if (supportsDXT1Textures()) { mExtensionString += "GL_EXT_texture_compression_dxt1 "; } mExtensionString += "GL_EXT_texture_format_BGRA8888 "; + mExtensionString += "GL_EXT_texture_storage "; // ANGLE-specific extensions mExtensionString += "GL_ANGLE_framebuffer_blit "; if (getMaxSupportedSamples() != 0) { mExtensionString += "GL_ANGLE_framebuffer_multisample "; } if (supportsDXT3Textures()) { mExtensionString += "GL_ANGLE_texture_compression_dxt3 "; } if (supportsDXT5Textures()) { mExtensionString += "GL_ANGLE_texture_compression_dxt5 "; } + + mExtensionString += "GL_ANGLE_texture_usage "; mExtensionString += "GL_ANGLE_translated_shader_source "; // Other vendor-specific extensions if (supportsEventQueries()) { mExtensionString += "GL_NV_fence "; } @@ -3611,18 +3678,18 @@ void Context::blitFramebuffer(GLint srcX } blitRenderTarget = true; } if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) { - DepthStencilbuffer *readDSBuffer = NULL; - DepthStencilbuffer *drawDSBuffer = NULL; + 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) { if (readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer()) { @@ -3800,19 +3867,19 @@ void VertexDeclarationCache::markStateDi mLastSetVDecl = NULL; } } extern "C" { -gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext) +gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess) { - return new gl::Context(config, shareContext); + return new gl::Context(config, shareContext, notifyResets, robustAccess); } void glDestroyContext(gl::Context *context) { delete context; if (context == gl::getContext()) {
--- a/gfx/angle/src/libGLESv2/Context.h +++ b/gfx/angle/src/libGLESv2/Context.h @@ -253,24 +253,27 @@ class VertexDeclarationCache UINT lruCount; IDirect3DVertexDeclaration9 *vertexDeclaration; } mVertexDeclCache[NUM_VERTEX_DECL_CACHE_ENTRIES]; }; class Context { public: - Context(const egl::Config *config, const gl::Context *shareContext); + Context(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess); ~Context(); void makeCurrent(egl::Display *display, egl::Surface *surface); void markAllStateDirty(); + 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); @@ -412,33 +415,35 @@ class Context Framebuffer *getDrawFramebuffer(); bool getFloatv(GLenum pname, GLfloat *params); bool getIntegerv(GLenum pname, GLint *params); bool getBooleanv(GLenum pname, GLboolean *params); bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); - void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); + void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels); void clear(GLbitfield mask); void drawArrays(GLenum mode, GLint first, GLsizei count); void drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices); void sync(bool block); // flush/finish // Draw the last segment of a line loop void drawClosingLine(unsigned int first, unsigned int last); void drawClosingLine(GLsizei count, GLenum type, const void *indices); void recordInvalidEnum(); void recordInvalidValue(); void recordInvalidOperation(); void recordOutOfMemory(); void recordInvalidFramebufferOperation(); GLenum getError(); + GLenum getResetStatus(); + virtual bool isResetNotificationEnabled(); bool supportsShaderModel3() const; int getMaximumVaryingVectors() const; unsigned int getMaximumVertexTextureImageUnits() const; unsigned int getMaximumCombinedTextureImageUnits() const; int getMaximumFragmentUniformVectors() const; int getMaximumRenderbufferDimension() const; int getMaximumTextureDimension() const; @@ -447,22 +452,22 @@ class Context GLsizei getMaxSupportedSamples() const; int getNearestSupportedSamples(D3DFORMAT format, int requested) const; const char *getExtensionString() const; const char *getRendererString() const; bool supportsEventQueries() const; bool supportsDXT1Textures() const; bool supportsDXT3Textures() const; bool supportsDXT5Textures() const; - bool supportsFloatTextures() const; - bool supportsFloatLinearFilter() const; - bool supportsFloatRenderableTextures() const; - bool supportsHalfFloatTextures() const; - bool supportsHalfFloatLinearFilter() const; - bool supportsHalfFloatRenderableTextures() 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 supports32bitIndices() const; bool supportsNonPower2Texture() const; void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask); @@ -526,17 +531,22 @@ class Context // Recorded errors bool mInvalidEnum; bool mInvalidValue; bool mInvalidOperation; bool mOutOfMemory; bool mInvalidFramebufferOperation; + // Current/lost context flags bool mHasBeenCurrent; + bool mContextLost; + GLenum mResetStatus; + GLenum mResetStrategy; + bool mRobustAccess; unsigned int mAppliedTextureSerialPS[MAX_TEXTURE_IMAGE_UNITS]; unsigned int mAppliedTextureSerialVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF]; unsigned int mAppliedProgramSerial; unsigned int mAppliedRenderTargetSerial; unsigned int mAppliedDepthbufferSerial; unsigned int mAppliedStencilbufferSerial; unsigned int mAppliedIBSerial; @@ -557,22 +567,22 @@ class Context int mMaxCubeTextureDimension; int mMaxTextureLevel; std::map<D3DFORMAT, bool *> mMultiSampleSupport; GLsizei mMaxSupportedSamples; bool mSupportsEventQueries; bool mSupportsDXT1Textures; bool mSupportsDXT3Textures; bool mSupportsDXT5Textures; - bool mSupportsFloatTextures; - bool mSupportsFloatLinearFilter; - bool mSupportsFloatRenderableTextures; - bool mSupportsHalfFloatTextures; - bool mSupportsHalfFloatLinearFilter; - bool mSupportsHalfFloatRenderableTextures; + bool mSupportsFloat32Textures; + bool mSupportsFloat32LinearFilter; + bool mSupportsFloat32RenderableTextures; + bool mSupportsFloat16Textures; + bool mSupportsFloat16LinearFilter; + bool mSupportsFloat16RenderableTextures; bool mSupportsLuminanceTextures; bool mSupportsLuminanceAlphaTextures; bool mSupports32bitIndices; int mNumCompressedTextureFormats; // state caching flags bool mClearStateDirty; bool mCullStateDirty; @@ -595,17 +605,17 @@ class Context VertexDeclarationCache mVertexDeclarationCache; }; } extern "C" { // Exported functions for use by EGL -gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext); +gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess); void glDestroyContext(gl::Context *context); void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface); gl::Context *glGetCurrentContext(); __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname); -void __stdcall glBindTexImage(egl::Surface *surface); +bool __stdcall glBindTexImage(egl::Surface *surface); } #endif // INCLUDE_CONTEXT_H_
--- a/gfx/angle/src/libGLESv2/Fence.cpp +++ b/gfx/angle/src/libGLESv2/Fence.cpp @@ -60,17 +60,17 @@ GLboolean Fence::testFence() { if (mQuery == NULL) { return error(GL_INVALID_OPERATION, GL_TRUE); } HRESULT result = mQuery->GetData(NULL, 0, D3DGETDATA_FLUSH); - if (result == D3DERR_DEVICELOST) + if (checkDeviceLost(result)) { return error(GL_OUT_OF_MEMORY, GL_TRUE); } ASSERT(result == S_OK || result == S_FALSE); mStatus = result == S_OK; return mStatus; } @@ -105,17 +105,17 @@ void Fence::getFenceiv(GLenum pname, GLi if (mStatus) { params[0] = GL_TRUE; return; } HRESULT result = mQuery->GetData(NULL, 0, 0); - if (result == D3DERR_DEVICELOST) + if (checkDeviceLost(result)) { params[0] = GL_TRUE; return error(GL_OUT_OF_MEMORY); } ASSERT(result == S_OK || result == S_FALSE); mStatus = result == S_OK; params[0] = mStatus;
--- a/gfx/angle/src/libGLESv2/Framebuffer.cpp +++ b/gfx/angle/src/libGLESv2/Framebuffer.cpp @@ -176,56 +176,29 @@ unsigned int Framebuffer::getStencilbuff if (stencilbuffer) { return stencilbuffer->getSerial(); } return 0; } -Colorbuffer *Framebuffer::getColorbuffer() +Renderbuffer *Framebuffer::getColorbuffer() { - Renderbuffer *rb = mColorbufferPointer.get(); - - if (rb != NULL && rb->isColorbuffer()) - { - return static_cast<Colorbuffer*>(rb->getStorage()); - } - else - { - return NULL; - } + return mColorbufferPointer.get(); } -DepthStencilbuffer *Framebuffer::getDepthbuffer() +Renderbuffer *Framebuffer::getDepthbuffer() { - Renderbuffer *rb = mDepthbufferPointer.get(); - - if (rb != NULL && rb->isDepthbuffer()) - { - return static_cast<DepthStencilbuffer*>(rb->getStorage()); - } - else - { - return NULL; - } + return mDepthbufferPointer.get(); } -DepthStencilbuffer *Framebuffer::getStencilbuffer() +Renderbuffer *Framebuffer::getStencilbuffer() { - Renderbuffer *rb = mStencilbufferPointer.get(); - - if (rb != NULL && rb->isStencilbuffer()) - { - return static_cast<DepthStencilbuffer*>(rb->getStorage()); - } - else - { - return NULL; - } + return mStencilbufferPointer.get(); } GLenum Framebuffer::getColorbufferType() { return mColorbufferType; } GLenum Framebuffer::getDepthbufferType() @@ -252,17 +225,17 @@ GLuint Framebuffer::getStencilbufferHand { return mStencilbufferPointer.id(); } bool Framebuffer::hasStencil() { if (mStencilbufferType != GL_NONE) { - DepthStencilbuffer *stencilbufferObject = getStencilbuffer(); + Renderbuffer *stencilbufferObject = getStencilbuffer(); if (stencilbufferObject) { return stencilbufferObject->getStencilSize() > 0; } } return false; @@ -271,17 +244,17 @@ bool Framebuffer::hasStencil() GLenum Framebuffer::completeness() { int width = 0; int height = 0; int samples = -1; if (mColorbufferType != GL_NONE) { - Colorbuffer *colorbuffer = getColorbuffer(); + Renderbuffer *colorbuffer = getColorbuffer(); if (!colorbuffer) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) { @@ -297,18 +270,18 @@ GLenum Framebuffer::completeness() } else if (IsTextureTarget(mColorbufferType)) { if (IsCompressed(colorbuffer->getInternalFormat())) { return GL_FRAMEBUFFER_UNSUPPORTED; } - if ((colorbuffer->getType() == GL_FLOAT && !getContext()->supportsFloatRenderableTextures()) || - (colorbuffer->getType() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatRenderableTextures())) + if ((dx2es::IsFloat32Format(colorbuffer->getD3DFormat()) && !getContext()->supportsFloat32RenderableTextures()) || + (dx2es::IsFloat16Format(colorbuffer->getD3DFormat()) && !getContext()->supportsFloat16RenderableTextures())) { return GL_FRAMEBUFFER_UNSUPPORTED; } if (colorbuffer->getInternalFormat() == GL_LUMINANCE || colorbuffer->getInternalFormat() == GL_LUMINANCE_ALPHA) { return GL_FRAMEBUFFER_UNSUPPORTED; } @@ -319,18 +292,18 @@ GLenum Framebuffer::completeness() height = colorbuffer->getHeight(); samples = colorbuffer->getSamples(); } else { return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; } - DepthStencilbuffer *depthbuffer = NULL; - DepthStencilbuffer *stencilbuffer = NULL; + Renderbuffer *depthbuffer = NULL; + Renderbuffer *stencilbuffer = NULL; if (mDepthbufferType != GL_NONE) { if (mDepthbufferType != GL_RENDERBUFFER) { return GL_FRAMEBUFFER_UNSUPPORTED; // Requires GL_OES_depth_texture } @@ -413,27 +386,27 @@ GLenum Framebuffer::completeness() { return GL_FRAMEBUFFER_UNSUPPORTED; } } return GL_FRAMEBUFFER_COMPLETE; } -DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil) +DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil) { - mColorbufferType = GL_RENDERBUFFER; - mDepthbufferType = (depthStencil->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE; - mStencilbufferType = (depthStencil->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE; - - mColorbufferPointer.set(new Renderbuffer(0, color)); + mColorbufferPointer.set(new Renderbuffer(0, colorbuffer)); Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil); mDepthbufferPointer.set(depthStencilRenderbuffer); mStencilbufferPointer.set(depthStencilRenderbuffer); + + mColorbufferType = GL_RENDERBUFFER; + mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE; + mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE; } int Framebuffer::getSamples() { if (completeness() == GL_FRAMEBUFFER_COMPLETE) { return getColorbuffer()->getSamples(); }
--- a/gfx/angle/src/libGLESv2/Framebuffer.h +++ b/gfx/angle/src/libGLESv2/Framebuffer.h @@ -41,19 +41,19 @@ class Framebuffer IDirect3DSurface9 *getRenderTarget(); IDirect3DSurface9 *getDepthStencil(); unsigned int getRenderTargetSerial(); unsigned int getDepthbufferSerial(); unsigned int getStencilbufferSerial(); - Colorbuffer *getColorbuffer(); - DepthStencilbuffer *getDepthbuffer(); - DepthStencilbuffer *getStencilbuffer(); + Renderbuffer *getColorbuffer(); + Renderbuffer *getDepthbuffer(); + Renderbuffer *getStencilbuffer(); GLenum getColorbufferType(); GLenum getDepthbufferType(); GLenum getStencilbufferType(); GLuint getColorbufferHandle(); GLuint getDepthbufferHandle(); GLuint getStencilbufferHandle(); @@ -77,17 +77,17 @@ class Framebuffer DISALLOW_COPY_AND_ASSIGN(Framebuffer); Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle) const; }; class DefaultFramebuffer : public Framebuffer { public: - DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil); + DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil); virtual GLenum completeness(); private: DISALLOW_COPY_AND_ASSIGN(DefaultFramebuffer); }; }
--- a/gfx/angle/src/libGLESv2/Program.cpp +++ b/gfx/angle/src/libGLESv2/Program.cpp @@ -31,17 +31,17 @@ std::string str(int i) char buffer[20]; sprintf(buffer, "%d", i); return buffer; } Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize) : type(type), _name(_name), name(Program::undecorateUniform(_name)), arraySize(arraySize) { - int bytes = UniformTypeSize(type) * arraySize; + int bytes = UniformInternalSize(type) * arraySize; data = new unsigned char[bytes]; memset(data, 0, bytes); dirty = true; } Uniform::~Uniform() { delete[] data; @@ -555,33 +555,33 @@ void transposeMatrix(T *target, const GL { 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++) { - target[x * targetWidth + y] = value[y * srcWidth + x]; + target[x * targetWidth + y] = (T)value[y * srcWidth + x]; } } // clear unfilled right side for (int y = 0; y < copyHeight; y++) { for (int x = srcWidth; x < targetWidth; x++) { - target[y * targetWidth + x] = 0; + target[y * targetWidth + x] = (T)0; } } // clear unfilled bottom. for (int y = srcHeight; y < targetHeight; y++) { for (int x = 0; x < targetWidth; x++) { - target[y * targetWidth + x] = 0; + target[y * targetWidth + x] = (T)0; } } } bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) { if (location < 0 || location >= (int)mUniformIndex.size()) { @@ -906,39 +906,49 @@ bool Program::setUniform4iv(GLint locati else { return false; } return true; } -bool Program::getUniformfv(GLint location, GLfloat *params) +bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params) { if (location < 0 || location >= (int)mUniformIndex.size()) { return false; } Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + // sized queries -- ensure the provided buffer is large enough + if (bufSize) + { + int requiredBytes = UniformExternalSize(targetUniform->type); + if (*bufSize < requiredBytes) + { + return false; + } + } + switch (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: { - unsigned int count = UniformComponentCount(targetUniform->type); + unsigned int count = UniformExternalComponentCount(targetUniform->type); unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); switch (UniformComponentType(targetUniform->type)) { case GL_BOOL: { GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount; @@ -965,25 +975,35 @@ bool Program::getUniformfv(GLint locatio default: UNREACHABLE(); } } } return true; } -bool Program::getUniformiv(GLint location, GLint *params) +bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params) { if (location < 0 || location >= (int)mUniformIndex.size()) { return false; } Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + // sized queries -- ensure the provided buffer is large enough + if (bufSize) + { + int requiredBytes = UniformExternalSize(targetUniform->type); + if (*bufSize < requiredBytes) + { + return false; + } + } + 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: @@ -993,17 +1013,17 @@ bool Program::getUniformiv(GLint locatio break; case GL_FLOAT_MAT4: { transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); } break; default: { - unsigned int count = UniformComponentCount(targetUniform->type); + unsigned int count = UniformExternalComponentCount(targetUniform->type); unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); switch (UniformComponentType(targetUniform->type)) { case GL_BOOL: { GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount; @@ -1829,36 +1849,43 @@ bool Program::linkUniforms(ID3DXConstant } // Adds the description of a constant found in the binary shader to the list of uniforms // Returns true if succesful (uniform not already defined) bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name) { if (constantDescription.RegisterSet == D3DXRS_SAMPLER) { - for (unsigned int samplerIndex = constantDescription.RegisterIndex; samplerIndex < constantDescription.RegisterIndex + constantDescription.RegisterCount; samplerIndex++) + for (unsigned int i = 0; i < constantDescription.RegisterCount; i++) { - if (mConstantTablePS->GetConstantByName(NULL, constantDescription.Name) != NULL) + D3DXHANDLE psConstant = mConstantTablePS->GetConstantByName(NULL, constantDescription.Name); + D3DXHANDLE vsConstant = mConstantTableVS->GetConstantByName(NULL, constantDescription.Name); + + if (psConstant) { + unsigned int samplerIndex = mConstantTablePS->GetSamplerIndex(psConstant) + i; + if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) { mSamplersPS[samplerIndex].active = true; mSamplersPS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D; mSamplersPS[samplerIndex].logicalTextureUnit = 0; mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange); } else { appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS); return false; } } - if (mConstantTableVS->GetConstantByName(NULL, constantDescription.Name) != NULL) + if (vsConstant) { + unsigned int samplerIndex = mConstantTableVS->GetSamplerIndex(vsConstant) + i; + if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits()) { mSamplersVS[samplerIndex].active = true; mSamplersVS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D; mSamplersVS[samplerIndex].logicalTextureUnit = 0; mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange); } else
--- a/gfx/angle/src/libGLESv2/Program.h +++ b/gfx/angle/src/libGLESv2/Program.h @@ -93,18 +93,18 @@ class Program 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); - bool getUniformfv(GLint location, GLfloat *params); - bool getUniformiv(GLint location, GLint *params); + bool getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params); + bool getUniformiv(GLint location, GLsizei *bufSize, GLint *params); GLint getDxDepthRangeLocation() const; GLint getDxDepthLocation() const; GLint getDxViewportLocation() const; GLint getDxHalfPixelSizeLocation() const; GLint getDxFrontCCWLocation() const; GLint getDxPointsOrLinesLocation() const;
--- a/gfx/angle/src/libGLESv2/Renderbuffer.cpp +++ b/gfx/angle/src/libGLESv2/Renderbuffer.cpp @@ -13,143 +13,200 @@ #include "libGLESv2/main.h" #include "libGLESv2/Texture.h" #include "libGLESv2/utilities.h" namespace gl { unsigned int RenderbufferStorage::mCurrentSerial = 1; -Renderbuffer::Renderbuffer(GLuint id, RenderbufferStorage *storage) : RefCountObject(id) +RenderbufferInterface::RenderbufferInterface() +{ +} + +GLuint RenderbufferInterface::getRedSize() const +{ + return dx2es::GetRedSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getGreenSize() const +{ + return dx2es::GetGreenSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getBlueSize() const +{ + return dx2es::GetBlueSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getAlphaSize() const +{ + return dx2es::GetAlphaSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getDepthSize() const +{ + return dx2es::GetDepthSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getStencilSize() const +{ + return dx2es::GetStencilSize(getD3DFormat()); +} + +RenderbufferTexture::RenderbufferTexture(Texture *texture, GLenum target) : mTexture(texture), mTarget(target) +{ +} + +RenderbufferTexture::~RenderbufferTexture() { - ASSERT(storage != NULL); - mStorage = storage; +} + +IDirect3DSurface9 *RenderbufferTexture::getRenderTarget() +{ + return mTexture->getRenderTarget(mTarget); +} + +IDirect3DSurface9 *RenderbufferTexture::getDepthStencil() +{ + return NULL; +} + +GLsizei RenderbufferTexture::getWidth() const +{ + return mTexture->getWidth(); +} + +GLsizei RenderbufferTexture::getHeight() const +{ + return mTexture->getHeight(); +} + +GLenum RenderbufferTexture::getInternalFormat() const +{ + return mTexture->getInternalFormat(); +} + +D3DFORMAT RenderbufferTexture::getD3DFormat() const +{ + return mTexture->getD3DFormat(); +} + +GLsizei RenderbufferTexture::getSamples() const +{ + return 0; +} + +unsigned int RenderbufferTexture::getSerial() const +{ + return mTexture->getRenderTargetSerial(mTarget); +} + +Renderbuffer::Renderbuffer(GLuint id, RenderbufferInterface *instance) : RefCountObject(id) +{ + ASSERT(instance != NULL); + mInstance = instance; } Renderbuffer::~Renderbuffer() { - delete mStorage; -} - -bool Renderbuffer::isColorbuffer() const -{ - return mStorage->isColorbuffer(); -} - -bool Renderbuffer::isDepthbuffer() const -{ - return mStorage->isDepthbuffer(); -} - -bool Renderbuffer::isStencilbuffer() const -{ - return mStorage->isStencilbuffer(); + delete mInstance; } IDirect3DSurface9 *Renderbuffer::getRenderTarget() { - return mStorage->getRenderTarget(); + return mInstance->getRenderTarget(); } IDirect3DSurface9 *Renderbuffer::getDepthStencil() { - return mStorage->getDepthStencil(); + return mInstance->getDepthStencil(); } GLsizei Renderbuffer::getWidth() const { - return mStorage->getWidth(); + return mInstance->getWidth(); } GLsizei Renderbuffer::getHeight() const { - return mStorage->getHeight(); + return mInstance->getHeight(); } GLenum Renderbuffer::getInternalFormat() const { - return mStorage->getInternalFormat(); + return mInstance->getInternalFormat(); +} + +D3DFORMAT Renderbuffer::getD3DFormat() const +{ + return mInstance->getD3DFormat(); } GLuint Renderbuffer::getRedSize() const { - return mStorage->getRedSize(); + return mInstance->getRedSize(); } GLuint Renderbuffer::getGreenSize() const { - return mStorage->getGreenSize(); + return mInstance->getGreenSize(); } GLuint Renderbuffer::getBlueSize() const { - return mStorage->getBlueSize(); + return mInstance->getBlueSize(); } GLuint Renderbuffer::getAlphaSize() const { - return mStorage->getAlphaSize(); + return mInstance->getAlphaSize(); } GLuint Renderbuffer::getDepthSize() const { - return mStorage->getDepthSize(); + return mInstance->getDepthSize(); } GLuint Renderbuffer::getStencilSize() const { - return mStorage->getStencilSize(); + return mInstance->getStencilSize(); } GLsizei Renderbuffer::getSamples() const { - return mStorage->getSamples(); + return mInstance->getSamples(); } unsigned int Renderbuffer::getSerial() const { - return mStorage->getSerial(); + return mInstance->getSerial(); } void Renderbuffer::setStorage(RenderbufferStorage *newStorage) { ASSERT(newStorage != NULL); - delete mStorage; - mStorage = newStorage; + delete mInstance; + mInstance = newStorage; } RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerial()) { mWidth = 0; mHeight = 0; mInternalFormat = GL_RGBA4; mD3DFormat = D3DFMT_A8R8G8B8; mSamples = 0; } RenderbufferStorage::~RenderbufferStorage() { } -bool RenderbufferStorage::isColorbuffer() const -{ - return false; -} - -bool RenderbufferStorage::isDepthbuffer() const -{ - return false; -} - -bool RenderbufferStorage::isStencilbuffer() const -{ - return false; -} - IDirect3DSurface9 *RenderbufferStorage::getRenderTarget() { return NULL; } IDirect3DSurface9 *RenderbufferStorage::getDepthStencil() { return NULL; @@ -165,98 +222,61 @@ GLsizei RenderbufferStorage::getHeight() return mHeight; } GLenum RenderbufferStorage::getInternalFormat() const { return mInternalFormat; } -GLuint RenderbufferStorage::getRedSize() const -{ - return dx2es::GetRedSize(getD3DFormat()); -} - -GLuint RenderbufferStorage::getGreenSize() const -{ - return dx2es::GetGreenSize(getD3DFormat()); -} - -GLuint RenderbufferStorage::getBlueSize() const +D3DFORMAT RenderbufferStorage::getD3DFormat() const { - return dx2es::GetBlueSize(getD3DFormat()); -} - -GLuint RenderbufferStorage::getAlphaSize() const -{ - return dx2es::GetAlphaSize(getD3DFormat()); -} - -GLuint RenderbufferStorage::getDepthSize() const -{ - return dx2es::GetDepthSize(getD3DFormat()); -} - -GLuint RenderbufferStorage::getStencilSize() const -{ - return dx2es::GetStencilSize(getD3DFormat()); + return mD3DFormat; } GLsizei RenderbufferStorage::getSamples() const { return mSamples; } -D3DFORMAT RenderbufferStorage::getD3DFormat() const -{ - return mD3DFormat; -} - unsigned int RenderbufferStorage::getSerial() const { return mSerial; } unsigned int RenderbufferStorage::issueSerial() { return mCurrentSerial++; } -Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(renderTarget), mTexture(NULL) +unsigned int RenderbufferStorage::issueCubeSerials() +{ + unsigned int firstSerial = mCurrentSerial; + mCurrentSerial += 6; + return firstSerial; +} + +Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(renderTarget) { if (renderTarget) { renderTarget->AddRef(); D3DSURFACE_DESC description; renderTarget->GetDesc(&description); mWidth = description.Width; mHeight = description.Height; mInternalFormat = dx2es::ConvertBackBufferFormat(description.Format); mD3DFormat = description.Format; mSamples = dx2es::GetSamplesFromMultisampleType(description.MultiSampleType); } } -Colorbuffer::Colorbuffer(Texture *texture, GLenum target) : mRenderTarget(NULL), mTexture(texture), mTarget(target) -{ - if (texture) - { - mWidth = texture->getWidth(); - mHeight = texture->getHeight(); - mInternalFormat = texture->getInternalFormat(); - mD3DFormat = texture->getD3DFormat(); - mSamples = 0; - - mRenderTarget = texture->getRenderTarget(target); - } -} - -Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL), mTexture(NULL) +Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL) { IDirect3DDevice9 *device = getDevice(); D3DFORMAT requestedFormat = es2dx::ConvertRenderbufferFormat(format); int supportedSamples = getContext()->getNearestSupportedSamples(requestedFormat, samples); if (supportedSamples == -1) { @@ -290,81 +310,21 @@ Colorbuffer::Colorbuffer(int width, int Colorbuffer::~Colorbuffer() { if (mRenderTarget) { mRenderTarget->Release(); } } -GLsizei Colorbuffer::getWidth() const -{ - if (mTexture) - { - return mTexture->getWidth(); - } - - return mWidth; -} - -GLsizei Colorbuffer::getHeight() const -{ - if (mTexture) - { - return mTexture->getHeight(); - } - - return mHeight; -} - -GLenum Colorbuffer::getInternalFormat() const -{ - if (mTexture) - { - return mTexture->getInternalFormat(); - } - - return mInternalFormat; -} - -GLenum Colorbuffer::getType() const -{ - if (mTexture) - { - return mTexture->getType(); - } - - return GL_UNSIGNED_BYTE; -} - -D3DFORMAT Colorbuffer::getD3DFormat() const -{ - if (mTexture) - { - return mTexture->getD3DFormat(); - } - - return mD3DFormat; -} - -bool Colorbuffer::isColorbuffer() const -{ - return true; -} - IDirect3DSurface9 *Colorbuffer::getRenderTarget() { - if (mTexture) + if (mRenderTarget) { - if (mRenderTarget) - { - mRenderTarget->Release(); - } - - mRenderTarget = mTexture->getRenderTarget(mTarget); + mRenderTarget->AddRef(); } return mRenderTarget; } DepthStencilbuffer::DepthStencilbuffer(IDirect3DSurface9 *depthStencil) : mDepthStencil(depthStencil) { if (depthStencil) @@ -422,26 +382,16 @@ DepthStencilbuffer::DepthStencilbuffer(i DepthStencilbuffer::~DepthStencilbuffer() { if (mDepthStencil) { mDepthStencil->Release(); } } -bool DepthStencilbuffer::isDepthbuffer() const -{ - return true; -} - -bool DepthStencilbuffer::isStencilbuffer() const -{ - return true; -} - IDirect3DSurface9 *DepthStencilbuffer::getDepthStencil() { return mDepthStencil; } Depthbuffer::Depthbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(depthStencil) { if (depthStencil) @@ -449,64 +399,45 @@ Depthbuffer::Depthbuffer(IDirect3DSurfac mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function // will expect one of the valid renderbuffer formats for use in // glRenderbufferStorage } } Depthbuffer::Depthbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples) { - if (getDepthStencil()) + if (mDepthStencil) { mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function // will expect one of the valid renderbuffer formats for use in // glRenderbufferStorage } } Depthbuffer::~Depthbuffer() { } -bool Depthbuffer::isDepthbuffer() const -{ - return true; -} - -bool Depthbuffer::isStencilbuffer() const -{ - return false; -} - Stencilbuffer::Stencilbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(depthStencil) { if (depthStencil) { mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function // will expect one of the valid renderbuffer formats for use in // glRenderbufferStorage } } Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples) { - if (getDepthStencil()) + if (mDepthStencil) { mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function // will expect one of the valid renderbuffer formats for use in // glRenderbufferStorage } } Stencilbuffer::~Stencilbuffer() { } -bool Stencilbuffer::isDepthbuffer() const -{ - return false; } - -bool Stencilbuffer::isStencilbuffer() const -{ - return true; -} -}
--- a/gfx/angle/src/libGLESv2/Renderbuffer.h +++ b/gfx/angle/src/libGLESv2/Renderbuffer.h @@ -17,79 +17,121 @@ #include <d3d9.h> #include "common/angleutils.h" #include "libGLESv2/RefCountObject.h" namespace gl { class Texture; +class Colorbuffer; +class DepthStencilbuffer; + +class RenderbufferInterface +{ + public: + RenderbufferInterface(); + + virtual ~RenderbufferInterface() {}; + + virtual IDirect3DSurface9 *getRenderTarget() = 0; + virtual IDirect3DSurface9 *getDepthStencil() = 0; + + virtual GLsizei getWidth() const = 0; + virtual GLsizei getHeight() const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual D3DFORMAT getD3DFormat() const = 0; + virtual GLsizei getSamples() const = 0; + + GLuint getRedSize() const; + GLuint getGreenSize() const; + GLuint getBlueSize() const; + GLuint getAlphaSize() const; + GLuint getDepthSize() const; + GLuint getStencilSize() const; + + virtual unsigned int getSerial() const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferInterface); +}; + +class RenderbufferTexture : public RenderbufferInterface +{ + public: + RenderbufferTexture(Texture *texture, GLenum target); + + virtual ~RenderbufferTexture(); + + IDirect3DSurface9 *getRenderTarget(); + IDirect3DSurface9 *getDepthStencil(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual D3DFORMAT getD3DFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferTexture); + + Texture *mTexture; + GLenum mTarget; +}; // 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 +class RenderbufferStorage : public RenderbufferInterface { public: RenderbufferStorage(); virtual ~RenderbufferStorage() = 0; - virtual bool isColorbuffer() const; - virtual bool isDepthbuffer() const; - virtual bool isStencilbuffer() const; - virtual IDirect3DSurface9 *getRenderTarget(); virtual IDirect3DSurface9 *getDepthStencil(); virtual GLsizei getWidth() const; virtual GLsizei getHeight() const; virtual GLenum getInternalFormat() const; - GLuint getRedSize() const; - GLuint getGreenSize() const; - GLuint getBlueSize() const; - GLuint getAlphaSize() const; - GLuint getDepthSize() const; - GLuint getStencilSize() const; + virtual D3DFORMAT getD3DFormat() const; virtual GLsizei getSamples() const; - virtual D3DFORMAT getD3DFormat() const; + virtual unsigned int getSerial() const; - unsigned int getSerial() const; + static unsigned int issueSerial(); + static unsigned int issueCubeSerials(); protected: GLsizei mWidth; GLsizei mHeight; GLenum mInternalFormat; D3DFORMAT mD3DFormat; GLsizei mSamples; private: DISALLOW_COPY_AND_ASSIGN(RenderbufferStorage); - static unsigned int issueSerial(); - const unsigned int mSerial; static unsigned int mCurrentSerial; }; // Renderbuffer implements the GL renderbuffer object. -// It's only a proxy for a RenderbufferStorage instance; the internal 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(GLuint id, RenderbufferStorage *storage); - - ~Renderbuffer(); + Renderbuffer(GLuint id, RenderbufferInterface *storage); - bool isColorbuffer() const; - bool isDepthbuffer() const; - bool isStencilbuffer() const; + virtual ~Renderbuffer(); IDirect3DSurface9 *getRenderTarget(); IDirect3DSurface9 *getDepthStencil(); GLsizei getWidth() const; GLsizei getHeight() const; GLenum getInternalFormat() const; D3DFORMAT getD3DFormat() const; @@ -99,94 +141,74 @@ class Renderbuffer : public RefCountObje GLuint getAlphaSize() const; GLuint getDepthSize() const; GLuint getStencilSize() const; GLsizei getSamples() const; unsigned int getSerial() const; void setStorage(RenderbufferStorage *newStorage); - RenderbufferStorage *getStorage() { return mStorage; } private: DISALLOW_COPY_AND_ASSIGN(Renderbuffer); - RenderbufferStorage *mStorage; + RenderbufferInterface *mInstance; }; class Colorbuffer : public RenderbufferStorage { public: explicit Colorbuffer(IDirect3DSurface9 *renderTarget); - Colorbuffer(Texture *texture, GLenum target); Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples); virtual ~Colorbuffer(); - virtual bool isColorbuffer() const; - virtual IDirect3DSurface9 *getRenderTarget(); - virtual GLsizei getWidth() const; - virtual GLsizei getHeight() const; - virtual GLenum getInternalFormat() const; - virtual GLenum getType() const; - - virtual D3DFORMAT getD3DFormat() const; - private: DISALLOW_COPY_AND_ASSIGN(Colorbuffer); IDirect3DSurface9 *mRenderTarget; - Texture *mTexture; - GLenum mTarget; }; class DepthStencilbuffer : public RenderbufferStorage { public: explicit DepthStencilbuffer(IDirect3DSurface9 *depthStencil); DepthStencilbuffer(GLsizei width, GLsizei height, GLsizei samples); ~DepthStencilbuffer(); - virtual bool isDepthbuffer() const; - virtual bool isStencilbuffer() const; + virtual IDirect3DSurface9 *getDepthStencil(); - virtual IDirect3DSurface9 *getDepthStencil(); + protected: + IDirect3DSurface9 *mDepthStencil; private: DISALLOW_COPY_AND_ASSIGN(DepthStencilbuffer); - IDirect3DSurface9 *mDepthStencil; }; class Depthbuffer : public DepthStencilbuffer { public: explicit Depthbuffer(IDirect3DSurface9 *depthStencil); Depthbuffer(GLsizei width, GLsizei height, GLsizei samples); virtual ~Depthbuffer(); - virtual bool isDepthbuffer() const; - virtual bool isStencilbuffer() const; - private: DISALLOW_COPY_AND_ASSIGN(Depthbuffer); }; class Stencilbuffer : public DepthStencilbuffer { public: explicit Stencilbuffer(IDirect3DSurface9 *depthStencil); Stencilbuffer(GLsizei width, GLsizei height, GLsizei samples); virtual ~Stencilbuffer(); - virtual bool isDepthbuffer() const; - virtual bool isStencilbuffer() const; - private: DISALLOW_COPY_AND_ASSIGN(Stencilbuffer); }; } #endif // LIBGLESV2_RENDERBUFFER_H_
--- a/gfx/angle/src/libGLESv2/Texture.cpp +++ b/gfx/angle/src/libGLESv2/Texture.cpp @@ -28,32 +28,141 @@ #include "libGLESv2/main.h" #include "libGLESv2/mathutil.h" #include "libGLESv2/utilities.h" #include "libGLESv2/Blit.h" #include "libGLESv2/Framebuffer.h" namespace gl { -unsigned int Texture::mCurrentSerial = 1; - -Texture::Image::Image() - : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE), type(GL_UNSIGNED_BYTE) +unsigned int TextureStorage::mCurrentTextureSerial = 1; + +Image::Image() { + mWidth = 0; + mHeight = 0; + mFormat = GL_NONE; + mType = GL_UNSIGNED_BYTE; + + mSurface = NULL; + + mDirty = false; + mManaged = false; } -Texture::Image::~Image() +Image::~Image() { - if (surface) + if (mSurface) { - surface->Release(); + mSurface->Release(); } } -bool Texture::Image::isRenderable() const +bool Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRelease) +{ + if (mWidth != width || + mHeight != height || + mFormat != format || + mType != type || + forceRelease) + { + mWidth = width; + mHeight = height; + mFormat = format; + mType = type; + + if (mSurface) + { + mSurface->Release(); + mSurface = NULL; + } + + return true; + } + + return false; +} + +void Image::createSurface() +{ + if(mSurface) + { + return; + } + + IDirect3DTexture9 *newTexture = NULL; + IDirect3DSurface9 *newSurface = NULL; + + if (mWidth != 0 && mHeight != 0) + { + int levelToFetch = 0; + GLsizei requestWidth = mWidth; + GLsizei requestHeight = mHeight; + if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0)) + { + bool isMult4 = false; + int upsampleCount = 0; + while (!isMult4) + { + requestWidth <<= 1; + requestHeight <<= 1; + upsampleCount++; + if (requestWidth % 4 == 0 && requestHeight % 4 == 0) + { + isMult4 = true; + } + } + levelToFetch = upsampleCount; + } + + HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(), + D3DPOOL_SYSTEMMEM, &newTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + ERR("Creating image surface failed."); + return error(GL_OUT_OF_MEMORY); + } + + newTexture->GetSurfaceLevel(levelToFetch, &newSurface); + newTexture->Release(); + } + + mSurface = newSurface; + mDirty = false; +} + +HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect) +{ + createSurface(); + + HRESULT result = D3DERR_INVALIDCALL; + + if (mSurface) + { + result = mSurface->LockRect(lockedRect, rect, 0); + ASSERT(SUCCEEDED(result)); + + mDirty = true; + } + + return result; +} + +void Image::unlock() +{ + if (mSurface) + { + HRESULT result = mSurface->UnlockRect(); + ASSERT(SUCCEEDED(result)); + } +} + +bool Image::isRenderable() const { switch(getD3DFormat()) { case D3DFMT_L8: case D3DFMT_A8L8: case D3DFMT_DXT1: case D3DFMT_DXT3: case D3DFMT_DXT5: @@ -65,307 +174,219 @@ bool Texture::Image::isRenderable() cons return true; default: UNREACHABLE(); } return false; } -D3DFORMAT Texture::Image::getD3DFormat() const +D3DFORMAT Image::getD3DFormat() const { - if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || - format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) + if (mFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || + mFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) { return D3DFMT_DXT1; } - else if (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE) + else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE) { return D3DFMT_DXT3; } - else if (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE) + else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE) { return D3DFMT_DXT5; } - else if (type == GL_FLOAT) + else if (mType == GL_FLOAT) { return D3DFMT_A32B32G32R32F; } - else if (type == GL_HALF_FLOAT_OES) + else if (mType == GL_HALF_FLOAT_OES) { return D3DFMT_A16B16G16R16F; } - else if (type == GL_UNSIGNED_BYTE) + else if (mType == GL_UNSIGNED_BYTE) { - if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures()) + if (mFormat == GL_LUMINANCE && getContext()->supportsLuminanceTextures()) { return D3DFMT_L8; } - else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures()) + else if (mFormat == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures()) { return D3DFMT_A8L8; } - else if (format == GL_RGB) + else if (mFormat == GL_RGB) { return D3DFMT_X8R8G8B8; } return D3DFMT_A8R8G8B8; } return D3DFMT_A8R8G8B8; } -Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial()) +IDirect3DSurface9 *Image::getSurface() { - mMinFilter = GL_NEAREST_MIPMAP_LINEAR; - mMagFilter = GL_LINEAR; - mWrapS = GL_REPEAT; - mWrapT = GL_REPEAT; - mDirtyParameter = true; - - mDirtyImage = true; - - mIsRenderable = false; + createSurface(); + + return mSurface; } -Texture::~Texture() -{ -} - -Blit *Texture::getBlitter() +void Image::setManagedSurface(IDirect3DSurface9 *surface) { - Context *context = getContext(); - return context->getBlitter(); -} - -// Returns true on successful filter state update (valid enum parameter) -bool Texture::setMinFilter(GLenum filter) -{ - switch (filter) + if (mSurface) { - 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: - { - if (mMinFilter != filter) - { - mMinFilter = filter; - mDirtyParameter = true; - } - return true; - } - default: - return false; + D3DXLoadSurfaceFromSurface(surface, NULL, NULL, mSurface, NULL, NULL, D3DX_FILTER_BOX, 0); + mSurface->Release(); } + + mSurface = surface; + mManaged = true; } -// Returns true on successful filter state update (valid enum parameter) -bool Texture::setMagFilter(GLenum filter) +void Image::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { - switch (filter) + IDirect3DSurface9 *sourceSurface = getSurface(); + + if (sourceSurface != destSurface) { - case GL_NEAREST: - case GL_LINEAR: + RECT rect = transformPixelRect(xoffset, yoffset, width, height, mHeight); + + if (mManaged) { - if (mMagFilter != filter) - { - mMagFilter = filter; - mDirtyParameter = true; - } - return true; + HRESULT result = D3DXLoadSurfaceFromSurface(destSurface, NULL, &rect, sourceSurface, NULL, &rect, D3DX_FILTER_BOX, 0); + ASSERT(SUCCEEDED(result)); } - default: - return false; - } -} - -// Returns true on successful wrap state update (valid enum parameter) -bool Texture::setWrapS(GLenum wrap) -{ - switch (wrap) - { - case GL_REPEAT: - case GL_CLAMP_TO_EDGE: - case GL_MIRRORED_REPEAT: + else { - if (mWrapS != wrap) - { - mWrapS = wrap; - mDirtyParameter = true; - } - return true; + POINT point = {rect.left, rect.top}; + HRESULT result = getDevice()->UpdateSurface(sourceSurface, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); } - default: - return false; } } -// 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: - { - if (mWrapT != wrap) - { - mWrapT = wrap; - mDirtyParameter = true; - } - return true; - } - default: - return false; - } -} - -GLenum Texture::getMinFilter() const -{ - return mMinFilter; -} - -GLenum Texture::getMagFilter() const -{ - return mMagFilter; -} - -GLenum Texture::getWrapS() const -{ - return mWrapS; -} - -GLenum Texture::getWrapT() const -{ - return mWrapT; -} - // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input // into the target pixel rectangle at output with outputPitch bytes in between each line. -void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, - GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const +void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type, + GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const { - GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment); + GLsizei inputPitch = -ComputePitch(width, mFormat, type, unpackAlignment); input = ((char*)input) - inputPitch * (height - 1); switch (type) { case GL_UNSIGNED_BYTE: - switch (format) + switch (mFormat) { case GL_ALPHA: - loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE: - loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8); + loadLuminanceData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_L8); break; case GL_LUMINANCE_ALPHA: - loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8); + loadLuminanceAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_A8L8); break; case GL_RGB: - loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGBA: if (supportsSSE2()) { - loadRGBAUByteImageDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBAUByteDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); } else { - loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBAUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); } break; case GL_BGRA_EXT: - loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadBGRAData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_UNSIGNED_SHORT_5_6_5: - switch (format) + switch (mFormat) { case GL_RGB: - loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGB565Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_UNSIGNED_SHORT_4_4_4_4: - switch (format) + switch (mFormat) { case GL_RGBA: - loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBA4444Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_UNSIGNED_SHORT_5_5_5_1: - switch (format) + switch (mFormat) { case GL_RGBA: - loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBA5551Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_FLOAT: - switch (format) + switch (mFormat) { // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D case GL_ALPHA: - loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE: - loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE_ALPHA: - loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGB: - loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGBA: - loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBAFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_HALF_FLOAT_OES: - switch (format) + switch (mFormat) { // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D case GL_ALPHA: - loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE: - loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE_ALPHA: - loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGB: - loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGBA: - loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBAHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; default: UNREACHABLE(); } } -void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 4; @@ -374,18 +395,18 @@ void Texture::loadAlphaImageData(GLint x dest[4 * x + 0] = 0; dest[4 * x + 1] = 0; dest[4 * x + 2] = 0; dest[4 * x + 3] = source[x]; } } } -void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 16); @@ -394,18 +415,18 @@ void Texture::loadAlphaFloatImageData(GL dest[4 * x + 0] = 0; dest[4 * x + 1] = 0; dest[4 * x + 2] = 0; dest[4 * x + 3] = source[x]; } } } -void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 8); @@ -414,18 +435,18 @@ void Texture::loadAlphaHalfFloatImageDat dest[4 * x + 0] = 0; dest[4 * x + 1] = 0; dest[4 * x + 2] = 0; dest[4 * x + 3] = source[x]; } } } -void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const +void Image::loadLuminanceData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const { const int destBytesPerPixel = native? 1: 4; 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; @@ -443,18 +464,18 @@ void Texture::loadLuminanceImageData(GLi } else // L8 destination format { memcpy(dest, source, width); } } } -void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 16); @@ -463,18 +484,18 @@ void Texture::loadLuminanceFloatImageDat 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 Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 8); @@ -483,18 +504,18 @@ void Texture::loadLuminanceHalfFloatImag 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 Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const +void Image::loadLuminanceAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const { const int destBytesPerPixel = native? 2: 4; 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; @@ -512,18 +533,18 @@ void Texture::loadLuminanceAlphaImageDat } else { memcpy(dest, source, width * 2); } } } -void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 16); @@ -532,18 +553,18 @@ void Texture::loadLuminanceAlphaFloatIma 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 Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 8); @@ -552,18 +573,18 @@ void Texture::loadLuminanceAlphaHalfFloa 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 Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 4; @@ -572,18 +593,18 @@ void Texture::loadRGBUByteImageData(GLin 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 Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGB565Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 4; @@ -593,18 +614,18 @@ void Texture::loadRGB565ImageData(GLint 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 Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 16); @@ -613,18 +634,18 @@ void Texture::loadRGBFloatImageData(GLin 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 Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 8); @@ -633,18 +654,18 @@ void Texture::loadRGBHalfFloatImageData( 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 Texture::loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBAUByteDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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); @@ -675,36 +696,36 @@ void Texture::loadRGBAUByteImageDataSSE2 for (; x < width; x++) { unsigned int rgba = source[x]; dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); } } } -void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBAUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 4); for (int x = 0; x < width; x++) { unsigned int rgba = source[x]; dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); } } } -void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBA4444Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 4; @@ -714,18 +735,18 @@ void Texture::loadRGBA4444ImageData(GLin 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 Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBA5551Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 4; @@ -735,70 +756,70 @@ void Texture::loadRGBA5551ImageData(GLin 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 Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBAFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 16); memcpy(dest, source, width * 16); } } -void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBAHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 8; memcpy(dest, source, width * 8); } } -void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadBGRAData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { 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 + yoffset) * outputPitch + xoffset * 4; memcpy(dest, source, width*4); } } -void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const { +void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { switch (getD3DFormat()) { case D3DFMT_DXT1: - loadDXT1ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadDXT1Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case D3DFMT_DXT3: - loadDXT3ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadDXT3Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case D3DFMT_DXT5: - loadDXT5ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadDXT5Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; } } static void FlipCopyDXT1BlockFull(const unsigned int* source, unsigned int* dest) { // A DXT1 block layout is: // [0-1] color0. // [2-3] color1. @@ -903,18 +924,18 @@ static void FlipCopyDXT5BlockHalf(const destBytes[0] = sourceBytes[0]; destBytes[1] = sourceBytes[1]; destBytes[2] = line_1_0 & 0xff; destBytes[3] = (line_1_0 & 0xff00) >> 8; destBytes[4] = (line_1_0 & 0xff0000) >> 16; FlipCopyDXT1BlockHalf(source + 2, dest + 2); } -void Texture::loadDXT1ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadDXT1Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { ASSERT(xoffset % 4 == 0); ASSERT(yoffset % 4 == 0); ASSERT(width % 4 == 0 || width == 2 || width == 1); ASSERT(inputPitch % 8 == 0); ASSERT(outputPitch % 8 == 0); const unsigned int *source = reinterpret_cast<const unsigned int*>(input); @@ -951,18 +972,18 @@ void Texture::loadDXT1ImageData(GLint xo { FlipCopyDXT1BlockFull(source + x, dest + x); } } break; } } -void Texture::loadDXT3ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadDXT3Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { ASSERT(xoffset % 4 == 0); ASSERT(yoffset % 4 == 0); ASSERT(width % 4 == 0 || width == 2 || width == 1); ASSERT(inputPitch % 16 == 0); ASSERT(outputPitch % 16 == 0); const unsigned int *source = reinterpret_cast<const unsigned int*>(input); @@ -1001,18 +1022,18 @@ void Texture::loadDXT3ImageData(GLint xo { FlipCopyDXT3BlockFull(source + x, dest + x); } } break; } } -void Texture::loadDXT5ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadDXT5Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { ASSERT(xoffset % 4 == 0); ASSERT(yoffset % 4 == 0); ASSERT(width % 4 == 0 || width == 2 || width == 1); ASSERT(inputPitch % 16 == 0); ASSERT(outputPitch % 16 == 0); const unsigned int *source = reinterpret_cast<const unsigned int*>(input); @@ -1051,222 +1072,19 @@ void Texture::loadDXT5ImageData(GLint xo { FlipCopyDXT5BlockFull(source + x, dest + x); } } break; } } -void Texture::createSurface(Image *image) -{ - IDirect3DTexture9 *newTexture = NULL; - IDirect3DSurface9 *newSurface = NULL; - - if (image->width != 0 && image->height != 0) - { - int levelToFetch = 0; - GLsizei requestWidth = image->width; - GLsizei requestHeight = image->height; - if (IsCompressed(image->format) && (image->width % 4 != 0 || image->height % 4 != 0)) - { - bool isMult4 = false; - int upsampleCount = 0; - while (!isMult4) - { - requestWidth <<= 1; - requestHeight <<= 1; - upsampleCount++; - if (requestWidth % 4 == 0 && requestHeight % 4 == 0) - { - isMult4 = true; - } - } - levelToFetch = upsampleCount; - } - - HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, image->getD3DFormat(), - D3DPOOL_SYSTEMMEM, &newTexture, NULL); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY); - } - - newTexture->GetSurfaceLevel(levelToFetch, &newSurface); - newTexture->Release(); - } - - if (image->surface) - { - image->surface->Release(); - } - - image->surface = newSurface; -} - -void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image) -{ - createSurface(image); - - if (pixels != NULL && image->surface != NULL) - { - D3DSURFACE_DESC description; - image->surface->GetDesc(&description); - - D3DLOCKED_RECT locked; - HRESULT result = image->surface->LockRect(&locked, NULL, 0); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) - { - loadImageData(0, 0, image->width, image->height, image->format, image->type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description); - image->surface->UnlockRect(); - } - - image->dirty = true; - mDirtyImage = true; - } -} - -void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image) -{ - createSurface(image); - - if (pixels != NULL && image->surface != NULL) - { - D3DLOCKED_RECT locked; - HRESULT result = image->surface->LockRect(&locked, NULL, 0); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) - { - int inputPitch = ComputeCompressedPitch(image->width, image->format); - int inputSize = ComputeCompressedSize(image->width, image->height, image->format); - loadCompressedImageData(0, 0, image->width, image->height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits); - image->surface->UnlockRect(); - } - - image->dirty = true; - mDirtyImage = true; - } -} - -bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image) +// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures +void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget) { - if (width + xoffset > image->width || height + yoffset > image->height) - { - error(GL_INVALID_VALUE); - return false; - } - - if (IsCompressed(image->format)) - { - error(GL_INVALID_OPERATION); - return false; - } - - if (format != image->format) - { - error(GL_INVALID_OPERATION); - return false; - } - - if (!image->surface) - { - createSurface(image); - } - - if (pixels != NULL && image->surface != NULL) - { - D3DSURFACE_DESC description; - image->surface->GetDesc(&description); - - D3DLOCKED_RECT locked; - HRESULT result = image->surface->LockRect(&locked, NULL, 0); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) - { - loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description); - image->surface->UnlockRect(); - } - - image->dirty = true; - mDirtyImage = true; - } - - return true; -} - -bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image) -{ - if (width + xoffset > image->width || height + yoffset > image->height) - { - error(GL_INVALID_VALUE); - return false; - } - - if (format != getInternalFormat()) - { - error(GL_INVALID_OPERATION); - return false; - } - - if (!image->surface) - { - createSurface(image); - } - - if (pixels != NULL && image->surface != NULL) - { - RECT updateRegion; - updateRegion.left = xoffset; - updateRegion.right = xoffset + width; - updateRegion.bottom = yoffset + height; - updateRegion.top = yoffset; - - D3DLOCKED_RECT locked; - HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) - { - int inputPitch = ComputeCompressedPitch(width, format); - int inputSize = ComputeCompressedSize(width, height, format); - loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits); - image->surface->UnlockRect(); - } - - image->dirty = true; - mDirtyImage = true; - } - - return true; -} - -// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures -void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget) -{ - if (!image->surface) - { - createSurface(image); - - if (!image->surface) - { - ERR("Failed to create an image surface."); - return error(GL_OUT_OF_MEMORY); - } - } - IDirect3DDevice9 *device = getDevice(); IDirect3DSurface9 *renderTargetData = NULL; D3DSURFACE_DESC description; renderTarget->GetDesc(&description); HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL); if (FAILED(result)) @@ -1280,22 +1098,22 @@ void Texture::copyToImage(Image *image, if (FAILED(result)) { ERR("GetRenderTargetData unexpectedly failed."); renderTargetData->Release(); return error(GL_OUT_OF_MEMORY); } RECT sourceRect = transformPixelRect(x, y, width, height, description.Height); - int destYOffset = transformPixelYOffset(yoffset, height, image->height); + int destYOffset = transformPixelYOffset(yoffset, height, mHeight); RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height}; - if (image->isRenderable()) + if (isRenderable()) { - result = D3DXLoadSurfaceFromSurface(image->surface, NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0); + result = D3DXLoadSurfaceFromSurface(getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0); if (FAILED(result)) { ERR("Copying surfaces unexpectedly failed."); renderTargetData->Release(); return error(GL_OUT_OF_MEMORY); } } @@ -1307,17 +1125,17 @@ void Texture::copyToImage(Image *image, if (FAILED(result)) { ERR("Failed to lock the source surface (rectangle might be invalid)."); renderTargetData->Release(); return error(GL_OUT_OF_MEMORY); } D3DLOCKED_RECT destLock = {0}; - result = image->surface->LockRect(&destLock, &destRect, 0); + result = lock(&destLock, &destRect); if (FAILED(result)) { ERR("Failed to lock the destination surface (rectangle might be invalid)."); renderTargetData->UnlockRect(); renderTargetData->Release(); return error(GL_OUT_OF_MEMORY); } @@ -1326,17 +1144,17 @@ void Texture::copyToImage(Image *image, { unsigned char *source = (unsigned char*)sourceLock.pBits; unsigned char *dest = (unsigned char*)destLock.pBits; switch (description.Format) { case D3DFMT_X8R8G8B8: case D3DFMT_A8R8G8B8: - switch(image->getD3DFormat()) + switch(getD3DFormat()) { case D3DFMT_L8: for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { dest[x] = source[x * 4 + 2]; } @@ -1358,17 +1176,17 @@ void Texture::copyToImage(Image *image, dest += destLock.Pitch; } break; default: UNREACHABLE(); } break; case D3DFMT_R5G6B5: - switch(image->getD3DFormat()) + switch(getD3DFormat()) { case D3DFMT_L8: for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { unsigned char red = source[x * 2 + 1] & 0xF8; dest[x] = red | (red >> 5); @@ -1378,17 +1196,17 @@ void Texture::copyToImage(Image *image, dest += destLock.Pitch; } break; default: UNREACHABLE(); } break; case D3DFMT_A1R5G5B5: - switch(image->getD3DFormat()) + switch(getD3DFormat()) { case D3DFMT_L8: for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { unsigned char red = source[x * 2 + 1] & 0x7C; dest[x] = (red << 1) | (red >> 4); @@ -1416,270 +1234,612 @@ void Texture::copyToImage(Image *image, UNREACHABLE(); } break; default: UNREACHABLE(); } } - image->surface->UnlockRect(); + unlock(); renderTargetData->UnlockRect(); } renderTargetData->Release(); - image->dirty = true; - mDirtyImage = true; + mDirty = true; +} + +TextureStorage::TextureStorage(bool renderable) + : mRenderable(renderable), mManaged(getDisplay()->getBufferPool(renderable) == D3DPOOL_MANAGED), mTextureSerial(issueTextureSerial()) +{ +} + +TextureStorage::~TextureStorage() +{ +} + +bool TextureStorage::isRenderable() const +{ + return mRenderable; +} + +bool TextureStorage::isManaged() const +{ + return mManaged; +} + +unsigned int TextureStorage::getTextureSerial() const +{ + return mTextureSerial; +} + +unsigned int TextureStorage::issueTextureSerial() +{ + return mCurrentTextureSerial++; +} + +Texture::Texture(GLuint id) : RefCountObject(id) +{ + mMinFilter = GL_NEAREST_MIPMAP_LINEAR; + mMagFilter = GL_LINEAR; + mWrapS = GL_REPEAT; + mWrapT = GL_REPEAT; + mDirtyParameters = true; + 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: + { + if (mMinFilter != filter) + { + mMinFilter = filter; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// Returns true on successful filter state update (valid enum parameter) +bool Texture::setMagFilter(GLenum filter) +{ + switch (filter) + { + case GL_NEAREST: + case GL_LINEAR: + { + if (mMagFilter != filter) + { + mMagFilter = filter; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// Returns true on successful wrap state update (valid enum parameter) +bool Texture::setWrapS(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: + { + if (mWrapS != wrap) + { + mWrapS = wrap; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// 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: + { + if (mWrapT != wrap) + { + mWrapT = wrap; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// 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 mMinFilter; +} + +GLenum Texture::getMagFilter() const +{ + return mMagFilter; +} + +GLenum Texture::getWrapS() const +{ + return mWrapS; +} + +GLenum Texture::getWrapT() const +{ + return mWrapT; +} + +GLenum Texture::getUsage() const +{ + return mUsage; +} + +void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + D3DLOCKED_RECT locked; + HRESULT result = image->lock(&locked, NULL); + + if (SUCCEEDED(result)) + { + image->loadData(0, 0, image->getWidth(), image->getHeight(), image->getType(), unpackAlignment, pixels, locked.Pitch, locked.pBits); + image->unlock(); + } + + mDirtyImages = true; + } +} + +void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + D3DLOCKED_RECT locked; + HRESULT result = image->lock(&locked, NULL); + + if (SUCCEEDED(result)) + { + int inputPitch = ComputeCompressedPitch(image->getWidth(), image->getFormat()); + int inputSize = ComputeCompressedSize(image->getWidth(), image->getHeight(), image->getFormat()); + image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits); + image->unlock(); + } + + mDirtyImages = true; + } +} + +bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image) +{ + if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight()) + { + error(GL_INVALID_VALUE); + return false; + } + + if (IsCompressed(image->getFormat())) + { + error(GL_INVALID_OPERATION); + return false; + } + + if (format != image->getFormat()) + { + error(GL_INVALID_OPERATION); + return false; + } + + if (pixels != NULL) + { + D3DLOCKED_RECT locked; + HRESULT result = image->lock(&locked, NULL); + + if (SUCCEEDED(result)) + { + image->loadData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, type, unpackAlignment, pixels, locked.Pitch, locked.pBits); + image->unlock(); + } + + mDirtyImages = true; + } + + return true; +} + +bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image) +{ + if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight()) + { + error(GL_INVALID_VALUE); + return false; + } + + if (format != getInternalFormat()) + { + error(GL_INVALID_OPERATION); + return false; + } + + if (pixels != NULL) + { + RECT updateRegion; + updateRegion.left = xoffset; + updateRegion.right = xoffset + width; + updateRegion.bottom = yoffset + height; + updateRegion.top = yoffset; + + D3DLOCKED_RECT locked; + HRESULT result = image->lock(&locked, &updateRegion); + + if (SUCCEEDED(result)) + { + int inputPitch = ComputeCompressedPitch(width, format); + int inputSize = ComputeCompressedSize(width, height, format); + image->loadCompressedData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits); + image->unlock(); + } + + mDirtyImages = true; + } + + return true; } IDirect3DBaseTexture9 *Texture::getTexture() { - if (!isComplete()) + if (!isSamplerComplete()) { return NULL; } if (!getBaseTexture()) { createTexture(); } updateTexture(); return getBaseTexture(); } -bool Texture::isDirtyParameter() const +bool Texture::hasDirtyParameters() const { - return mDirtyParameter; + return mDirtyParameters; } -bool Texture::isDirtyImage() const +bool Texture::hasDirtyImages() const { - return mDirtyImage; + return mDirtyImages; } void Texture::resetDirty() { - mDirtyParameter = false; - mDirtyImage = false; + mDirtyParameters = false; + mDirtyImages = false; +} + +unsigned int Texture::getTextureSerial() const +{ + TextureStorage *texture = getStorage(); + return texture ? texture->getTextureSerial() : 0; } -unsigned int Texture::getSerial() const +unsigned int Texture::getRenderTargetSerial(GLenum target) const { - return mSerial; + TextureStorage *texture = getStorage(); + return texture ? texture->getRenderTargetSerial(target) : 0; } -GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const +bool Texture::isImmutable() const +{ + return mImmutable; +} + +GLint Texture::creationLevels(GLsizei width, GLsizei height) const { if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture()) { - return maxlevel; + return 0; // Maximum number of levels } else { // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. return 1; } } -GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const +GLint Texture::creationLevels(GLsizei size) const { - return creationLevels(size, size, maxlevel); + return creationLevels(size, size); } int Texture::levelCount() const { return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0; } -unsigned int Texture::issueSerial() +Blit *Texture::getBlitter() +{ + Context *context = getContext(); + return context->getBlitter(); +} + +bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) +{ + if (source && dest) + { + HRESULT result; + + if (fromManaged) + { + result = D3DXLoadSurfaceFromSurface(dest, NULL, NULL, source, NULL, NULL, D3DX_FILTER_BOX, 0); + } + else + { + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + + display->endScene(); + result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); + } + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return false; + } + } + + return true; +} + +TextureStorage2D::TextureStorage2D(IDirect3DTexture9 *surfaceTexture) : TextureStorage(true), mRenderTargetSerial(RenderbufferStorage::issueSerial()) { - return mCurrentSerial++; + mTexture = surfaceTexture; +} + +TextureStorage2D::TextureStorage2D(int levels, D3DFORMAT format, int width, int height, bool renderable) : TextureStorage(renderable), mRenderTargetSerial(RenderbufferStorage::issueSerial()) +{ + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + + mTexture = NULL; + HRESULT result = device->CreateTexture(width, height, levels, renderable ? D3DUSAGE_RENDERTARGET : 0, format, display->getTexturePool(renderable), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + error(GL_OUT_OF_MEMORY); + } +} + +TextureStorage2D::~TextureStorage2D() +{ + mTexture->Release(); +} + +IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level) +{ + IDirect3DSurface9 *surface = NULL; + + if (mTexture) + { + HRESULT result = mTexture->GetSurfaceLevel(level, &surface); + ASSERT(SUCCEEDED(result)); + } + + return surface; +} + +IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const +{ + return mTexture; +} + +unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const +{ + return mRenderTargetSerial; } Texture2D::Texture2D(GLuint id) : Texture(id) { mTexture = NULL; mSurface = NULL; } Texture2D::~Texture2D() { mColorbufferProxy.set(NULL); - if (mTexture) - { - mTexture->Release(); - mTexture = NULL; - } - + delete mTexture; + mTexture = NULL; + if (mSurface) { mSurface->setBoundTexture(NULL); mSurface = NULL; } } GLenum Texture2D::getTarget() const { return GL_TEXTURE_2D; } GLsizei Texture2D::getWidth() const { - return mImageArray[0].width; + return mImageArray[0].getWidth(); } GLsizei Texture2D::getHeight() const { - return mImageArray[0].height; + return mImageArray[0].getHeight(); } GLenum Texture2D::getInternalFormat() const { - return mImageArray[0].format; + return mImageArray[0].getFormat(); } GLenum Texture2D::getType() const { - return mImageArray[0].type; + return mImageArray[0].getType(); } D3DFORMAT Texture2D::getD3DFormat() const { return mImageArray[0].getD3DFormat(); } -void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine) +void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type) { - GLsizei textureWidth = mImageArray[0].width; - GLsizei textureHeight = mImageArray[0].height; - GLenum textureFormat = mImageArray[0].format; - GLenum textureType = mImageArray[0].type; - - mImageArray[level].width = width; - mImageArray[level].height = height; - mImageArray[level].format = format; - mImageArray[level].type = type; - - if (!mTexture) - { - return; - } - - bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1); - bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1); - bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type); - - if (!textureOkay || forceRedefine || mSurface) // Purge all the levels and the texture. + releaseTexImage(); + + bool redefined = mImageArray[level].redefine(format, width, height, type, false); + + if (mTexture && redefined) { for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - if (mImageArray[i].surface != NULL) - { - mImageArray[i].surface->Release(); - mImageArray[i].surface = NULL; - mImageArray[i].dirty = true; - } + mImageArray[i].markDirty(); } - if (mTexture != NULL) - { - mTexture->Release(); - mTexture = NULL; - mDirtyImage = true; - mIsRenderable = false; - } - - if (mSurface) - { - mSurface->setBoundTexture(NULL); - mSurface = NULL; - } - - mColorbufferProxy.set(NULL); + delete mTexture; + mTexture = NULL; + mDirtyImages = true; } } void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { - redefineTexture(level, format, width, height, type, false); + redefineImage(level, format, width, height, type); Texture::setImage(unpackAlignment, pixels, &mImageArray[level]); } void Texture2D::bindTexImage(egl::Surface *surface) { + releaseTexImage(); + GLenum format; switch(surface->getFormat()) { case D3DFMT_A8R8G8B8: format = GL_RGBA; break; case D3DFMT_X8R8G8B8: format = GL_RGB; break; default: UNIMPLEMENTED(); return; } - redefineTexture(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true); - - IDirect3DTexture9 *texture = surface->getOffscreenTexture(); - - mTexture = texture; - mDirtyImage = true; - mIsRenderable = true; + mImageArray[0].redefine(format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true); + + delete mTexture; + mTexture = new TextureStorage2D(surface->getOffscreenTexture()); + + mDirtyImages = true; mSurface = surface; mSurface->setBoundTexture(this); } void Texture2D::releaseTexImage() { - redefineTexture(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true); + if (mSurface) + { + mSurface->setBoundTexture(NULL); + mSurface = NULL; + + if (mTexture) + { + delete mTexture; + mTexture = NULL; + } + + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i].redefine(GL_RGBA, 0, 0, GL_UNSIGNED_BYTE, true); + } + } } void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) { - redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false); + redefineImage(level, format, width, height, GL_UNSIGNED_BYTE); Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]); } void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { - ASSERT(mImageArray[level].surface != NULL); + ASSERT(mImageArray[level].getSurface() != NULL); if (level < levelCount()) { - IDirect3DSurface9 *destLevel = NULL; - HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) + IDirect3DSurface9 *destLevel = mTexture->getSurfaceLevel(level); + + if (destLevel) { Image *image = &mImageArray[level]; - - RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);; - - POINT destPoint; - destPoint.x = sourceRect.left; - destPoint.y = sourceRect.top; - - result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint); - ASSERT(SUCCEEDED(result)); + image->updateSurface(destLevel, xoffset, yoffset, width, height); destLevel->Release(); - - image->dirty = false; + 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])) { @@ -1700,104 +1860,134 @@ void Texture2D::copyImage(GLint level, G IDirect3DSurface9 *renderTarget = source->getRenderTarget(); if (!renderTarget) { ERR("Failed to retrieve the render target."); return error(GL_OUT_OF_MEMORY); } - redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false); + redefineImage(level, format, width, height, GL_UNSIGNED_BYTE); if (!mImageArray[level].isRenderable()) { - copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget); + mImageArray[level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (!mTexture || !mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } - updateTexture(); + mImageArray[level].markClean(); if (width != 0 && height != 0 && level < levelCount()) { RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight()); sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth()); sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight()); sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); - GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].height); + GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].getHeight()); - IDirect3DSurface9 *dest; - HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); - - getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest); - dest->Release(); + IDirect3DSurface9 *dest = mTexture->getSurfaceLevel(level); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, format, 0, destYOffset, dest); + dest->Release(); + } } } + + renderTarget->Release(); } void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height) + if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight()) { return error(GL_INVALID_VALUE); } IDirect3DSurface9 *renderTarget = source->getRenderTarget(); if (!renderTarget) { ERR("Failed to retrieve the render target."); return error(GL_OUT_OF_MEMORY); } - redefineTexture(level, mImageArray[level].format, mImageArray[level].width, mImageArray[level].height, GL_UNSIGNED_BYTE, false); - - if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete())) + if (!mImageArray[level].isRenderable() || (!mTexture && !isSamplerComplete())) { - copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget); + mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (!mTexture || !mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } updateTexture(); if (level < levelCount()) { RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight()); sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth()); sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight()); sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); - GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height); - - IDirect3DSurface9 *dest; - HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); - - getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest); - dest->Release(); + GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].getHeight()); + + IDirect3DSurface9 *dest = mTexture->getSurfaceLevel(level); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, mImageArray[0].getFormat(), xoffset, destYOffset, dest); + dest->Release(); + } } } + + renderTarget->Release(); } -// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool Texture2D::isComplete() const +void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { - GLsizei width = mImageArray[0].width; - GLsizei height = mImageArray[0].height; + GLenum format = gl::ExtractFormat(internalformat); + GLenum type = gl::ExtractType(internalformat); + + delete mTexture; + mTexture = new TextureStorage2D(levels, mImageArray[0].getD3DFormat(), width, height, mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + mImmutable = true; + + for (int level = 0; level < levels; level++) + { + mImageArray[level].redefine(format, width, height, type, 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(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true); + } +} + +// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. +bool Texture2D::isSamplerComplete() const +{ + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); if (width <= 0 || height <= 0) { return false; } bool mipmapping = false; @@ -1808,374 +1998,372 @@ bool Texture2D::isComplete() const mipmapping = false; break; case GL_NEAREST_MIPMAP_NEAREST: case GL_LINEAR_MIPMAP_NEAREST: case GL_NEAREST_MIPMAP_LINEAR: case GL_LINEAR_MIPMAP_LINEAR: mipmapping = true; break; - default: UNREACHABLE(); + default: UNREACHABLE(); } - if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) || - (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter())) + if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) || + (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter())) { if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) { return false; } } - bool npot = getContext()->supportsNonPower2Texture(); - - if (!npot) + bool npotSupport = getContext()->supportsNonPower2Texture(); + + if (!npotSupport) { if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height))) { return false; } } if (mipmapping) { - if (!npot) + if (!npotSupport) { if (!isPow2(width) || !isPow2(height)) { return false; } } - int q = log2(std::max(width, height)); - - for (int level = 1; level <= q; level++) + if (!isMipmapComplete()) { - if (mImageArray[level].format != mImageArray[0].format) - { - return false; - } - - if (mImageArray[level].type != mImageArray[0].type) - { - return false; - } - - if (mImageArray[level].width != std::max(1, width >> level)) - { - return false; - } - - if (mImageArray[level].height != std::max(1, height >> level)) - { - return false; - } + 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].getFormat() != mImageArray[0].getFormat()) + { + return false; + } + + if (mImageArray[level].getType() != mImageArray[0].getType()) + { + 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; } bool Texture2D::isCompressed() const { return IsCompressed(getInternalFormat()); } IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const { - return mTexture; + return mTexture ? mTexture->getBaseTexture() : NULL; } // Constructs a Direct3D 9 texture resource from the texture images void Texture2D::createTexture() { - IDirect3DDevice9 *device = getDevice(); + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + GLint levels = creationLevels(width, height); D3DFORMAT format = mImageArray[0].getD3DFormat(); - GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0); - - IDirect3DTexture9 *texture = NULL; - HRESULT result = device->CreateTexture(mImageArray[0].width, mImageArray[0].height, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL); - - if (FAILED(result)) + bool renderable = (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + + delete mTexture; + mTexture = new TextureStorage2D(levels, format, width, height, renderable); + + if (mTexture->isManaged()) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY); + int levels = levelCount(); + + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexture->getSurfaceLevel(level); + mImageArray[level].setManagedSurface(surface); + } } - if (mTexture) - { - mTexture->Release(); - } - - mTexture = texture; - mDirtyImage = true; - mIsRenderable = false; + mDirtyImages = true; } void Texture2D::updateTexture() { - IDirect3DDevice9 *device = getDevice(); - int levels = levelCount(); for (int level = 0; level < levels; level++) { - if (mImageArray[level].surface && mImageArray[level].dirty) + Image *image = &mImageArray[level]; + + if (image->isDirty()) { - IDirect3DSurface9 *levelSurface = NULL; - HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) - { - result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL); - ASSERT(SUCCEEDED(result)); - - levelSurface->Release(); - - mImageArray[level].dirty = false; - } + commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight()); } } } void Texture2D::convertToRenderTarget() { - IDirect3DTexture9 *texture = NULL; - - if (mImageArray[0].width != 0 && mImageArray[0].height != 0) + TextureStorage2D *newTexture = NULL; + + if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0) { - egl::Display *display = getDisplay(); - IDirect3DDevice9 *device = getDevice(); + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + GLint levels = creationLevels(width, height); D3DFORMAT format = mImageArray[0].getD3DFormat(); - GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0); - - HRESULT result = device->CreateTexture(mImageArray[0].width, mImageArray[0].height, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY); - } + + newTexture = new TextureStorage2D(levels, format, width, height, true); if (mTexture != NULL) { int levels = levelCount(); for (int i = 0; i < levels; i++) { - IDirect3DSurface9 *source; - result = mTexture->GetSurfaceLevel(i, &source); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - - return error(GL_OUT_OF_MEMORY); + IDirect3DSurface9 *source = mTexture->getSurfaceLevel(i); + IDirect3DSurface9 *dest = newTexture->getSurfaceLevel(i); + + if (!copyToRenderTarget(dest, source, mTexture->isManaged())) + { + delete newTexture; + source->Release(); + dest->Release(); + return error(GL_OUT_OF_MEMORY); } - IDirect3DSurface9 *dest; - result = texture->GetSurfaceLevel(i, &dest); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - - return error(GL_OUT_OF_MEMORY); - } - - display->endScene(); - result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - dest->Release(); - - return error(GL_OUT_OF_MEMORY); - } - - source->Release(); - dest->Release(); + if (source) source->Release(); + if (dest) dest->Release(); } } } - if (mTexture != NULL) - { - mTexture->Release(); - } - - mTexture = texture; - mDirtyImage = true; - mIsRenderable = true; + delete mTexture; + mTexture = newTexture; + + mDirtyImages = true; } void Texture2D::generateMipmaps() { if (!getContext()->supportsNonPower2Texture()) { - if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height)) + if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight())) { return 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].width, mImageArray[0].height)); + unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight())); for (unsigned int i = 1; i <= q; i++) { - if (mImageArray[i].surface != NULL) - { - mImageArray[i].surface->Release(); - mImageArray[i].surface = NULL; - } - - mImageArray[i].width = std::max(mImageArray[0].width >> i, 1); - mImageArray[i].height = std::max(mImageArray[0].height >> i, 1); - mImageArray[i].format = mImageArray[0].format; - mImageArray[i].type = mImageArray[0].type; + redefineImage(i, mImageArray[0].getFormat(), + std::max(mImageArray[0].getWidth() >> i, 1), + std::max(mImageArray[0].getHeight() >> i, 1), + mImageArray[0].getType()); } - if (mIsRenderable) + if (mTexture && mTexture->isRenderable()) { - if (mTexture == NULL) - { - ERR(" failed because mTexture was null."); - return; - } - for (unsigned int i = 1; i <= q; i++) { - IDirect3DSurface9 *upper = NULL; - IDirect3DSurface9 *lower = NULL; - - mTexture->GetSurfaceLevel(i-1, &upper); - mTexture->GetSurfaceLevel(i, &lower); + IDirect3DSurface9 *upper = mTexture->getSurfaceLevel(i - 1); + IDirect3DSurface9 *lower = mTexture->getSurfaceLevel(i); if (upper != NULL && lower != NULL) { getBlitter()->boxFilter(upper, lower); } if (upper != NULL) upper->Release(); if (lower != NULL) lower->Release(); - mImageArray[i].dirty = false; + mImageArray[i].markClean(); } } else { for (unsigned int i = 1; i <= q; i++) { - createSurface(&mImageArray[i]); - - if (mImageArray[i].surface == NULL) + if (mImageArray[i].getSurface() == NULL) { return error(GL_OUT_OF_MEMORY); } - if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0))) + if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].getSurface(), NULL, NULL, mImageArray[i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0))) { ERR(" failed to load filter %d to %d.", i - 1, i); } - mImageArray[i].dirty = true; + mImageArray[i].markDirty(); } } } Renderbuffer *Texture2D::getRenderbuffer(GLenum target) { if (target != GL_TEXTURE_2D) { return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); } if (mColorbufferProxy.get() == NULL) { - mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target))); + mColorbufferProxy.set(new Renderbuffer(id(), new RenderbufferTexture(this, target))); } return mColorbufferProxy.get(); } IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target) { ASSERT(target == GL_TEXTURE_2D); - if (!mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } if (mTexture == NULL) { return NULL; } updateTexture(); - IDirect3DSurface9 *renderTarget = NULL; - mTexture->GetSurfaceLevel(0, &renderTarget); - - return renderTarget; + return mTexture->getSurfaceLevel(0); +} + +TextureStorage *Texture2D::getStorage() const +{ + return mTexture; +} + +TextureStorageCubeMap::TextureStorageCubeMap(int levels, D3DFORMAT format, int size, bool renderable) : TextureStorage(renderable), mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials()) +{ + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + + mTexture = NULL; + HRESULT result = device->CreateCubeTexture(size, levels, renderable ? D3DUSAGE_RENDERTARGET : 0, format, display->getTexturePool(renderable), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + error(GL_OUT_OF_MEMORY); + } +} + +TextureStorageCubeMap::~TextureStorageCubeMap() +{ + mTexture->Release(); +} + +IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level) +{ + IDirect3DSurface9 *surface = NULL; + + if (mTexture) + { + HRESULT result = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(faceTarget), level, &surface); + ASSERT(SUCCEEDED(result)); + } + + return surface; +} + +IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const +{ + return mTexture; +} + +unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const +{ + return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target); } TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id) { mTexture = NULL; } TextureCubeMap::~TextureCubeMap() { for (int i = 0; i < 6; i++) { mFaceProxies[i].set(NULL); } - if (mTexture) - { - mTexture->Release(); - mTexture = NULL; - } + delete mTexture; + mTexture = NULL; } GLenum TextureCubeMap::getTarget() const { return GL_TEXTURE_CUBE_MAP; } GLsizei TextureCubeMap::getWidth() const { - return mImageArray[0][0].width; + return mImageArray[0][0].getWidth(); } GLsizei TextureCubeMap::getHeight() const { - return mImageArray[0][0].height; + return mImageArray[0][0].getHeight(); } GLenum TextureCubeMap::getInternalFormat() const { - return mImageArray[0][0].format; + return mImageArray[0][0].getFormat(); } GLenum TextureCubeMap::getType() const { - return mImageArray[0][0].type; + return mImageArray[0][0].getType(); } D3DFORMAT TextureCubeMap::getD3DFormat() const { return mImageArray[0][0].getD3DFormat(); } void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) @@ -2205,76 +2393,61 @@ void TextureCubeMap::setImagePosZ(GLint void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { setImage(5, level, width, height, format, type, unpackAlignment, pixels); } void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) { - redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE); + redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE); Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]); } -void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { - int face = faceIndex(faceTarget); - ASSERT(mImageArray[face][level].surface != NULL); + ASSERT(mImageArray[face][level].getSurface() != NULL); if (level < levelCount()) { - IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level); + IDirect3DSurface9 *destLevel = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level); ASSERT(destLevel != NULL); if (destLevel != NULL) { Image *image = &mImageArray[face][level]; - - RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);; - - POINT destPoint; - destPoint.x = sourceRect.left; - destPoint.y = sourceRect.top; - - HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint); - ASSERT(SUCCEEDED(result)); + image->updateSurface(destLevel, xoffset, yoffset, width, height); destLevel->Release(); - - image->dirty = false; + image->markClean(); } } } void TextureCubeMap::subImage(GLenum target, 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[faceIndex(target)][level])) { - commitRect(target, level, xoffset, yoffset, width, height); + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); } } void TextureCubeMap::subImageCompressed(GLenum target, 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[faceIndex(target)][level])) { - commitRect(target, level, xoffset, yoffset, width, height); + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); } } -// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool TextureCubeMap::isComplete() const +// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86. +bool TextureCubeMap::isSamplerComplete() const { - int size = mImageArray[0][0].width; - - if (size <= 0) - { - return false; - } + int size = mImageArray[0][0].getWidth(); bool mipmapping; switch (mMinFilter) { case GL_NEAREST: case GL_LINEAR: mipmapping = false; @@ -2283,539 +2456,493 @@ bool TextureCubeMap::isComplete() const case GL_LINEAR_MIPMAP_NEAREST: case GL_NEAREST_MIPMAP_LINEAR: case GL_LINEAR_MIPMAP_LINEAR: mipmapping = true; break; default: UNREACHABLE(); } - for (int face = 0; face < 6; face++) - { - if (mImageArray[face][0].width != size || mImageArray[face][0].height != size) - { - return false; - } - } - - if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) || - (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter())) + if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) || + (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter())) { if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) { return false; } } - bool npot = getContext()->supportsNonPower2Texture(); - - if (!npot) + if (!isPow2(size) && !getContext()->supportsNonPower2Texture()) { - if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size)) + if (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE || mipmapping) + { + return false; + } + } + + if (!mipmapping) + { + if (!isCubeComplete()) + { + return false; + } + } + else + { + if (!isMipmapCubeComplete()) // Also tests for isCubeComplete() { return false; } } - if (mipmapping) + return true; +} + +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool TextureCubeMap::isCubeComplete() const +{ + if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth()) + { + return false; + } + + for (unsigned int face = 1; face < 6; face++) { - if (!npot) + if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() || + mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() || + mImageArray[face][0].getFormat() != mImageArray[0][0].getFormat() || + mImageArray[face][0].getType() != mImageArray[0][0].getType()) { - if (!isPow2(size)) + return false; + } + } + + return true; +} + +bool TextureCubeMap::isMipmapCubeComplete() const +{ + if (isImmutable()) + { + return true; + } + + if (!isCubeComplete()) + { + return false; + } + + GLsizei size = mImageArray[0][0].getWidth(); + + int q = log2(size); + + for (int face = 0; face < 6; face++) + { + for (int level = 1; level <= q; level++) + { + if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat()) { return false; } - } - - int q = log2(size); - - for (int face = 0; face < 6; face++) - { - for (int level = 1; level <= q; level++) + + if (mImageArray[face][level].getType() != mImageArray[0][0].getType()) { - if (mImageArray[face][level].format != mImageArray[0][0].format) - { - return false; - } - - if (mImageArray[face][level].type != mImageArray[0][0].type) - { - return false; - } - - if (mImageArray[face][level].width != std::max(1, size >> level)) - { - return false; - } - - ASSERT(mImageArray[face][level].height == mImageArray[face][level].width); + return false; + } + + if (mImageArray[face][level].getWidth() != std::max(1, size >> level)) + { + return false; } } } return true; } bool TextureCubeMap::isCompressed() const { return IsCompressed(getInternalFormat()); } IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const { - return mTexture; + return mTexture ? mTexture->getBaseTexture() : NULL; } // Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one void TextureCubeMap::createTexture() { - IDirect3DDevice9 *device = getDevice(); + GLsizei size = mImageArray[0][0].getWidth(); + GLint levels = creationLevels(size, 0); D3DFORMAT format = mImageArray[0][0].getD3DFormat(); - GLint levels = creationLevels(mImageArray[0][0].width, 0); - - IDirect3DCubeTexture9 *texture = NULL; - HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL); - - if (FAILED(result)) + bool renderable = (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + + delete mTexture; + mTexture = new TextureStorageCubeMap(levels, format, size, renderable); + + if (mTexture->isManaged()) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY); + int levels = levelCount(); + + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level); + mImageArray[face][level].setManagedSurface(surface); + } + } } - - if (mTexture) - { - mTexture->Release(); - } - - mTexture = texture; - mDirtyImage = true; - mIsRenderable = false; + + mDirtyImages = true; } void TextureCubeMap::updateTexture() { - IDirect3DDevice9 *device = getDevice(); - for (int face = 0; face < 6; face++) { int levels = levelCount(); for (int level = 0; level < levels; level++) { Image *image = &mImageArray[face][level]; - if (image->surface && image->dirty) + if (image->isDirty()) { - IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level); - ASSERT(levelSurface != NULL); - - if (levelSurface != NULL) - { - HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL); - ASSERT(SUCCEEDED(result)); - - levelSurface->Release(); - - image->dirty = false; - } + commitRect(face, level, 0, 0, image->getWidth(), image->getHeight()); } } } } void TextureCubeMap::convertToRenderTarget() { - IDirect3DCubeTexture9 *texture = NULL; - - if (mImageArray[0][0].width != 0) + TextureStorageCubeMap *newTexture = NULL; + + if (mImageArray[0][0].getWidth() != 0) { - egl::Display *display = getDisplay(); - IDirect3DDevice9 *device = getDevice(); + GLsizei size = mImageArray[0][0].getWidth(); + GLint levels = creationLevels(size, 0); D3DFORMAT format = mImageArray[0][0].getD3DFormat(); - GLint levels = creationLevels(mImageArray[0][0].width, 0); - - HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY); - } + + newTexture = new TextureStorageCubeMap(levels, format, size, true); if (mTexture != NULL) { + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + int levels = levelCount(); for (int f = 0; f < 6; f++) { for (int i = 0; i < levels; i++) { - IDirect3DSurface9 *source; - result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - - return error(GL_OUT_OF_MEMORY); - } - - IDirect3DSurface9 *dest; - result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest); - - if (FAILED(result)) + IDirect3DSurface9 *source = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i); + IDirect3DSurface9 *dest = newTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i); + + if (!copyToRenderTarget(dest, source, mTexture->isManaged())) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - - return error(GL_OUT_OF_MEMORY); + delete newTexture; + source->Release(); + dest->Release(); + return error(GL_OUT_OF_MEMORY); } - display->endScene(); - result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - dest->Release(); - - return error(GL_OUT_OF_MEMORY); - } - - source->Release(); - dest->Release(); + if (source) source->Release(); + if (dest) dest->Release(); } } } } - if (mTexture != NULL) - { - mTexture->Release(); - } - - mTexture = texture; - mDirtyImage = true; - mIsRenderable = true; + delete mTexture; + mTexture = newTexture; + + mDirtyImages = true; } void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { - redefineTexture(faceIndex, level, format, width, height, type); + redefineImage(faceIndex, level, format, width, height, type); Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]); } unsigned int TextureCubeMap::faceIndex(GLenum face) { 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 face - GL_TEXTURE_CUBE_MAP_POSITIVE_X; } -void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type) +void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type) { - GLsizei textureWidth = mImageArray[0][0].width; - GLsizei textureHeight = mImageArray[0][0].height; - GLenum textureFormat = mImageArray[0][0].format; - GLenum textureType = mImageArray[0][0].type; - - mImageArray[face][level].width = width; - mImageArray[face][level].height = height; - mImageArray[face][level].format = format; - mImageArray[face][level].type = type; - - if (!mTexture) - { - return; - } - - bool sizeOkay = (textureWidth >> level == width); - bool textureOkay = (sizeOkay && textureFormat == format && textureType == type); - - if (!textureOkay) // Purge all the levels and the texture. + bool redefined = mImageArray[face][level].redefine(format, width, height, type, false); + + if (mTexture && redefined) { for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { for (int f = 0; f < 6; f++) { - if (mImageArray[f][i].surface != NULL) - { - mImageArray[f][i].surface->Release(); - mImageArray[f][i].surface = NULL; - mImageArray[f][i].dirty = true; - } + mImageArray[f][i].markDirty(); } } - if (mTexture != NULL) - { - mTexture->Release(); - mTexture = NULL; - mDirtyImage = true; - mIsRenderable = false; - } + delete mTexture; + mTexture = NULL; + + mDirtyImages = true; } } void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { IDirect3DSurface9 *renderTarget = source->getRenderTarget(); if (!renderTarget) { ERR("Failed to retrieve the render target."); return error(GL_OUT_OF_MEMORY); } unsigned int faceindex = faceIndex(target); - redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE); + redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE); if (!mImageArray[faceindex][level].isRenderable()) { - copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget); + mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (!mTexture || !mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } - updateTexture(); + mImageArray[faceindex][level].markClean(); ASSERT(width == height); if (width > 0 && level < levelCount()) { RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight()); sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth()); sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight()); sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); - GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].width); - - IDirect3DSurface9 *dest = getCubeMapSurface(target, level); - - getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest); - dest->Release(); + GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].getWidth()); + + IDirect3DSurface9 *dest = mTexture->getCubeMapSurface(target, level); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, format, 0, destYOffset, dest); + dest->Release(); + } } } -} - -IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level) -{ - if (mTexture == NULL) - { - UNREACHABLE(); - return NULL; - } - - IDirect3DSurface9 *surface = NULL; - - HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface); - - return (SUCCEEDED(hr)) ? surface : NULL; + + renderTarget->Release(); } void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - GLsizei size = mImageArray[faceIndex(target)][level].width; + GLsizei size = mImageArray[faceIndex(target)][level].getWidth(); if (xoffset + width > size || yoffset + height > size) { return error(GL_INVALID_VALUE); } IDirect3DSurface9 *renderTarget = source->getRenderTarget(); if (!renderTarget) { ERR("Failed to retrieve the render target."); return error(GL_OUT_OF_MEMORY); } unsigned int faceindex = faceIndex(target); - redefineTexture(faceindex, level, mImageArray[faceindex][level].format, mImageArray[faceindex][level].width, mImageArray[faceindex][level].height, GL_UNSIGNED_BYTE); - - if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete())) + + if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isSamplerComplete())) { - copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget); + mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (!mTexture || !mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } updateTexture(); if (level < levelCount()) { RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight()); sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth()); sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight()); sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); - GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width); - - IDirect3DSurface9 *dest = getCubeMapSurface(target, level); - - getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest); - dest->Release(); + GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].getWidth()); + + IDirect3DSurface9 *dest = mTexture->getCubeMapSurface(target, level); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, mImageArray[0][0].getFormat(), xoffset, destYOffset, dest); + dest->Release(); + } } } + + renderTarget->Release(); } -bool TextureCubeMap::isCubeComplete() const +void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) { - if (mImageArray[0][0].width == 0) + GLenum format = gl::ExtractFormat(internalformat); + GLenum type = gl::ExtractType(internalformat); + + delete mTexture; + mTexture = new TextureStorageCubeMap(levels, mImageArray[0][0].getD3DFormat(), size, mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + mImmutable = true; + + for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { - return false; - } - - for (unsigned int f = 1; f < 6; f++) - { - if (mImageArray[f][0].width != mImageArray[0][0].width - || mImageArray[f][0].format != mImageArray[0][0].format) + for (int face = 0; face < 6; face++) { - return false; + mImageArray[face][level].redefine(format, size, size, type, true); + size = std::max(1, size >> 1); } } - return true; + for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + for (int face = 0; face < 6; face++) + { + mImageArray[face][level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true); + } + } } void TextureCubeMap::generateMipmaps() { if (!isCubeComplete()) { return error(GL_INVALID_OPERATION); } if (!getContext()->supportsNonPower2Texture()) { - if (!isPow2(mImageArray[0][0].width)) + if (!isPow2(mImageArray[0][0].getWidth())) { return error(GL_INVALID_OPERATION); } } // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - unsigned int q = log2(mImageArray[0][0].width); + unsigned int q = log2(mImageArray[0][0].getWidth()); for (unsigned int f = 0; f < 6; f++) { for (unsigned int i = 1; i <= q; i++) { - if (mImageArray[f][i].surface != NULL) - { - mImageArray[f][i].surface->Release(); - mImageArray[f][i].surface = NULL; - } - - mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1); - mImageArray[f][i].height = mImageArray[f][i].width; - mImageArray[f][i].format = mImageArray[f][0].format; - mImageArray[f][i].type = mImageArray[f][0].type; + redefineImage(f, i, mImageArray[f][0].getFormat(), + std::max(mImageArray[f][0].getWidth() >> i, 1), + std::max(mImageArray[f][0].getWidth() >> i, 1), + mImageArray[f][0].getType()); } } - if (mIsRenderable) + if (mTexture && mTexture->isRenderable()) { - if (mTexture == NULL) - { - return; - } - for (unsigned int f = 0; f < 6; f++) { for (unsigned int i = 1; i <= q; i++) { - IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1); - IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i); + IDirect3DSurface9 *upper = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1); + IDirect3DSurface9 *lower = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i); if (upper != NULL && lower != NULL) { getBlitter()->boxFilter(upper, lower); } if (upper != NULL) upper->Release(); if (lower != NULL) lower->Release(); - mImageArray[f][i].dirty = false; + mImageArray[f][i].markClean(); } } } else { for (unsigned int f = 0; f < 6; f++) { for (unsigned int i = 1; i <= q; i++) { - createSurface(&mImageArray[f][i]); - if (mImageArray[f][i].surface == NULL) + if (mImageArray[f][i].getSurface() == NULL) { return error(GL_OUT_OF_MEMORY); } - if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0))) + if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].getSurface(), NULL, NULL, mImageArray[f][i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0))) { ERR(" failed to load filter %d to %d.", i - 1, i); } - mImageArray[f][i].dirty = true; + mImageArray[f][i].markDirty(); } } } } Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target) { if (!IsCubemapTextureTarget(target)) { return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); } unsigned int face = faceIndex(target); if (mFaceProxies[face].get() == NULL) { - mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target))); + mFaceProxies[face].set(new Renderbuffer(id(), new RenderbufferTexture(this, target))); } return mFaceProxies[face].get(); } IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target) { ASSERT(IsCubemapTextureTarget(target)); - if (!mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } if (mTexture == NULL) { return NULL; } updateTexture(); - IDirect3DSurface9 *renderTarget = NULL; - mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget); - - return renderTarget; + return mTexture->getCubeMapSurface(target, 0); } +TextureStorage *TextureCubeMap::getStorage() const +{ + return mTexture; } + +} \ No newline at end of file
--- a/gfx/angle/src/libGLESv2/Texture.h +++ b/gfx/angle/src/libGLESv2/Texture.h @@ -38,170 +38,239 @@ enum // 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 Image +{ + public: + Image(); + ~Image(); + + bool redefine(GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRelease); + void markDirty() {mDirty = true;} + void markClean() {mDirty = false;} + + HRESULT lock(D3DLOCKED_RECT *lockedRect, const RECT *rect); + void unlock(); + + bool isRenderable() const; + D3DFORMAT getD3DFormat() const; + + GLsizei getWidth() const {return mWidth;} + GLsizei getHeight() const {return mHeight;} + GLenum getFormat() const {return mFormat;} + GLenum getType() const {return mType;} + bool isDirty() const {return mSurface && mDirty;} + IDirect3DSurface9 *getSurface(); + + void setManagedSurface(IDirect3DSurface9 *surface); + void updateSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + + void loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type, + GLint unpackAlignment, const void *input, std::size_t outputPitch, void *output) const; + + void loadAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; + void loadLuminanceFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; + void loadLuminanceAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGB565Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAUByteDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBA4444Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBA5551Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadBGRAData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadDXT1Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadDXT3Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadDXT5Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + + void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget); + + private: + DISALLOW_COPY_AND_ASSIGN(Image); + + void createSurface(); + + GLsizei mWidth; + GLsizei mHeight; + GLenum mFormat; + GLenum mType; + + bool mDirty; + bool mManaged; + + IDirect3DSurface9 *mSurface; +}; + +class TextureStorage +{ + public: + explicit TextureStorage(bool renderable); + + virtual ~TextureStorage(); + + bool isRenderable() const; + bool isManaged() const; + unsigned int getTextureSerial() const; + virtual unsigned int getRenderTargetSerial(GLenum target) const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage); + + const bool mRenderable; + const bool mManaged; + + const unsigned int mTextureSerial; + static unsigned int issueTextureSerial(); + + static unsigned int mCurrentTextureSerial; +}; + class Texture : public RefCountObject { public: explicit Texture(GLuint id); virtual ~Texture(); virtual GLenum getTarget() const = 0; bool setMinFilter(GLenum filter); bool setMagFilter(GLenum filter); bool setWrapS(GLenum wrap); bool setWrapT(GLenum wrap); + bool setUsage(GLenum usage); GLenum getMinFilter() const; GLenum getMagFilter() const; GLenum getWrapS() const; GLenum getWrapT() const; + GLenum getUsage() const; virtual GLsizei getWidth() const = 0; virtual GLsizei getHeight() const = 0; virtual GLenum getInternalFormat() const = 0; virtual GLenum getType() const = 0; virtual D3DFORMAT getD3DFormat() const = 0; - virtual bool isComplete() const = 0; + virtual bool isSamplerComplete() const = 0; virtual bool isCompressed() const = 0; IDirect3DBaseTexture9 *getTexture(); virtual Renderbuffer *getRenderbuffer(GLenum target) = 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; - bool isDirtyParameter() const; - bool isDirtyImage() const; + bool hasDirtyParameters() const; + bool hasDirtyImages() const; void resetDirty(); - unsigned int getSerial() const; + unsigned int getTextureSerial() const; + unsigned int getRenderTargetSerial(GLenum target) const; + + bool isImmutable() const; 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: - friend class Colorbuffer; - - // Helper structure representing a single image layer - struct Image - { - Image(); - ~Image(); - - bool isRenderable() const; - D3DFORMAT getD3DFormat() const; - - GLsizei width; - GLsizei height; - GLenum format; - GLenum type; - - bool dirty; - - IDirect3DSurface9 *surface; - }; + friend class RenderbufferTexture; void setImage(GLint unpackAlignment, const void *pixels, Image *image); bool subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image); void setCompressedImage(GLsizei imageSize, const void *pixels, Image *image); bool subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image); - void copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget); - GLint creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const; - GLint creationLevels(GLsizei size, GLint maxlevel) const; + GLint creationLevels(GLsizei width, GLsizei height) const; + GLint creationLevels(GLsizei size) const; virtual IDirect3DBaseTexture9 *getBaseTexture() const = 0; virtual void createTexture() = 0; virtual void updateTexture() = 0; virtual void convertToRenderTarget() = 0; virtual IDirect3DSurface9 *getRenderTarget(GLenum target) = 0; - void createSurface(Image *image); + int levelCount() const; - Blit *getBlitter(); - - int levelCount() const; + static Blit *getBlitter(); + static bool copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); GLenum mMinFilter; GLenum mMagFilter; GLenum mWrapS; GLenum mWrapT; - bool mDirtyParameter; + bool mDirtyParameters; + GLenum mUsage; - bool mDirtyImage; + bool mDirtyImages; - bool mIsRenderable; + bool mImmutable; private: DISALLOW_COPY_AND_ASSIGN(Texture); - void loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, - GLint unpackAlignment, const void *input, std::size_t outputPitch, void *output, D3DSURFACE_DESC *description) const; + virtual TextureStorage *getStorage() const = 0; +}; + +class TextureStorage2D : public TextureStorage +{ + public: + explicit TextureStorage2D(IDirect3DTexture9 *surfaceTexture); + TextureStorage2D(int levels, D3DFORMAT format, int width, int height, bool renderable); + + virtual ~TextureStorage2D(); - void loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; - void loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; - void loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadDXT1ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadDXT3ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadDXT5ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; + IDirect3DSurface9 *getSurfaceLevel(int level); + IDirect3DBaseTexture9 *getBaseTexture() const; + + virtual unsigned int getRenderTargetSerial(GLenum target) const; - static unsigned int issueSerial(); + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage2D); - const unsigned int mSerial; - - static unsigned int mCurrentSerial; + IDirect3DTexture9 *mTexture; + const unsigned int mRenderTargetSerial; }; class Texture2D : public Texture { public: explicit Texture2D(GLuint id); ~Texture2D(); @@ -214,47 +283,70 @@ class Texture2D : public Texture virtual GLenum getType() const; virtual D3DFORMAT getD3DFormat() const; void setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, 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 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); - 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 x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); - virtual bool isComplete() const; + virtual bool isSamplerComplete() const; virtual bool isCompressed() const; virtual void bindTexImage(egl::Surface *surface); virtual void releaseTexImage(); virtual void generateMipmaps(); virtual Renderbuffer *getRenderbuffer(GLenum target); private: DISALLOW_COPY_AND_ASSIGN(Texture2D); virtual IDirect3DBaseTexture9 *getBaseTexture() const; virtual void createTexture(); virtual void updateTexture(); virtual void convertToRenderTarget(); virtual IDirect3DSurface9 *getRenderTarget(GLenum target); + virtual TextureStorage *getStorage() const; - void redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool force); + bool isMipmapComplete() const; + + void redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type); void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); Image mImageArray[IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - IDirect3DTexture9 *mTexture; + TextureStorage2D *mTexture; egl::Surface *mSurface; BindingPointer<Renderbuffer> mColorbufferProxy; }; +class TextureStorageCubeMap : public TextureStorage +{ + public: + TextureStorageCubeMap(int levels, D3DFORMAT format, int size, bool renderable); + + virtual ~TextureStorageCubeMap(); + + IDirect3DSurface9 *getCubeMapSurface(GLenum faceTarget, int level); + IDirect3DBaseTexture9 *getBaseTexture() const; + + virtual unsigned int getRenderTargetSerial(GLenum target) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorageCubeMap); + + IDirect3DCubeTexture9 *mTexture; + const unsigned int mFirstRenderTargetSerial; +}; + class TextureCubeMap : public Texture { public: explicit TextureCubeMap(GLuint id); ~TextureCubeMap(); virtual GLenum getTarget() const; @@ -273,46 +365,45 @@ class TextureCubeMap : public Texture void setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); void setCompressedImage(GLenum face, 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 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); + void storage(GLsizei levels, GLenum internalformat, GLsizei size); - virtual bool isComplete() const; + virtual bool isSamplerComplete() const; virtual bool isCompressed() const; virtual void generateMipmaps(); virtual Renderbuffer *getRenderbuffer(GLenum target); + static unsigned int faceIndex(GLenum face); + private: DISALLOW_COPY_AND_ASSIGN(TextureCubeMap); virtual IDirect3DBaseTexture9 *getBaseTexture() const; virtual void createTexture(); virtual void updateTexture(); virtual void convertToRenderTarget(); virtual IDirect3DSurface9 *getRenderTarget(GLenum target); - - // face is one of the GL_TEXTURE_CUBE_MAP_* enumerants. - // Returns NULL if the call underlying Direct3D call fails. - IDirect3DSurface9 *getCubeMapSurface(GLenum face, unsigned int level); - - static unsigned int faceIndex(GLenum face); + virtual TextureStorage *getStorage() const; bool isCubeComplete() const; + bool isMipmapCubeComplete() const; void setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - void redefineTexture(int faceIndex, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type); + void commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + void redefineImage(int faceIndex, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type); Image mImageArray[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - IDirect3DCubeTexture9 *mTexture; + TextureStorageCubeMap *mTexture; BindingPointer<Renderbuffer> mFaceProxies[6]; }; } -#endif // LIBGLESV2_TEXTURE_H_ +#endif // LIBGLESV2_TEXTURE_H_ \ No newline at end of file
--- a/gfx/angle/src/libGLESv2/VertexDataManager.cpp +++ b/gfx/angle/src/libGLESv2/VertexDataManager.cpp @@ -24,16 +24,22 @@ namespace // This has to be at least 4k or else it fails on ATI cards. enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 }; } namespace gl { unsigned int VertexBuffer::mCurrentSerial = 1; +int elementsInBuffer(const VertexAttribute &attribute, int size) +{ + int stride = attribute.stride(); + return (size - attribute.mOffset % stride + (stride - attribute.typeSize())) / stride; +} + VertexDataManager::VertexDataManager(Context *context, IDirect3DDevice9 *device) : mContext(context), mDevice(device) { for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) { mDirtyCurrentValue[i] = true; mCurrentValueBuffer[i] = NULL; mCurrentValueOffsets[i] = 0; } @@ -132,17 +138,17 @@ GLenum VertexDataManager::prepareVertexD { Buffer *buffer = attribs[i].mBoundBuffer.get(); StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; if (staticBuffer) { if (staticBuffer->size() == 0) { - int totalCount = buffer->size() / attribs[i].stride(); + int totalCount = elementsInBuffer(attribs[i], buffer->size()); staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount)); } else if (staticBuffer->lookupAttribute(attribs[i]) == -1) { // This static buffer doesn't have matching attributes, so fall back to using the streaming buffer // Add the space of all previous attributes belonging to the invalidated static buffer to the streaming buffer for (int previous = 0; previous < i; previous++) { @@ -211,17 +217,17 @@ GLenum VertexDataManager::prepareVertexD if (staticBuffer) { streamOffset = staticBuffer->lookupAttribute(attribs[i]); if (streamOffset == -1) { // Convert the entire buffer - int totalCount = buffer->size() / attribs[i].stride(); + int totalCount = elementsInBuffer(attribs[i], buffer->size()); int startIndex = attribs[i].mOffset / attribs[i].stride(); streamOffset = writeAttributeData(staticBuffer, -startIndex, totalCount, attribs[i]); } if (streamOffset != -1) { streamOffset += (start + attribs[i].mOffset / attribs[i].stride()) * converter.outputElementSize;
--- a/gfx/angle/src/libGLESv2/libGLESv2.cpp +++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp @@ -48,26 +48,66 @@ bool validImageSize(GLint level, GLsizei if (gl::isPow2(width) && gl::isPow2(height)) { return true; } return false; } +// 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; + case gl::IMPLEMENTATION_COLOR_READ_FORMAT: + switch (type) + { + case gl::IMPLEMENTATION_COLOR_READ_TYPE: + break; + default: + return false; + } + break; + default: + return false; + } + return true; +} + extern "C" { void __stdcall glActiveTexture(GLenum texture) { EVENT("(GLenum texture = 0x%X)", texture); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getMaximumCombinedTextureImageUnits() - 1) { return error(GL_INVALID_ENUM); } @@ -81,17 +121,17 @@ void __stdcall glActiveTexture(GLenum te } void __stdcall glAttachShader(GLuint program, GLuint shader) { EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Program *programObject = context->getProgram(program); gl::Shader *shaderObject = context->getShader(shader); if (!programObject) { @@ -135,17 +175,17 @@ void __stdcall glBindAttribLocation(GLui try { if (index >= gl::MAX_VERTEX_ATTRIBS) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Program *programObject = context->getProgram(program); if (!programObject) { if (context->getShader(program)) @@ -173,17 +213,17 @@ void __stdcall glBindAttribLocation(GLui } void __stdcall glBindBuffer(GLenum target, GLuint buffer) { EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { switch (target) { case GL_ARRAY_BUFFER: context->bindArrayBuffer(buffer); return; @@ -207,17 +247,17 @@ void __stdcall glBindFramebuffer(GLenum try { if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) { return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) { context->bindReadFramebuffer(framebuffer); } @@ -239,17 +279,17 @@ void __stdcall glBindRenderbuffer(GLenum try { if (target != GL_RENDERBUFFER) { return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->bindRenderbuffer(renderbuffer); } } catch(std::bad_alloc&) { @@ -258,17 +298,17 @@ void __stdcall glBindRenderbuffer(GLenum } void __stdcall glBindTexture(GLenum target, GLuint texture) { EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Texture *textureObject = context->getTexture(texture); if (textureObject && textureObject->getTarget() != target && texture != 0) { return error(GL_INVALID_OPERATION); @@ -295,17 +335,17 @@ void __stdcall glBindTexture(GLenum targ void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", red, green, blue, alpha); try { - gl::Context* context = gl::getContext(); + 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&) { @@ -339,17 +379,17 @@ void __stdcall glBlendEquationSeparate(G case GL_FUNC_ADD: case GL_FUNC_SUBTRACT: case GL_FUNC_REVERSE_SUBTRACT: break; default: return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setBlendEquation(modeRGB, modeAlpha); } } catch(std::bad_alloc&) { @@ -462,17 +502,17 @@ void __stdcall glBlendFuncSeparate(GLenu dstRGB == GL_CONSTANT_ALPHA || dstRGB == GL_ONE_MINUS_CONSTANT_ALPHA); 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 error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha); } } catch(std::bad_alloc&) { @@ -497,17 +537,17 @@ void __stdcall glBufferData(GLenum targe case GL_STREAM_DRAW: case GL_STATIC_DRAW: case GL_DYNAMIC_DRAW: break; default: return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Buffer *buffer; switch (target) { case GL_ARRAY_BUFFER: @@ -546,17 +586,17 @@ void __stdcall glBufferSubData(GLenum ta return error(GL_INVALID_VALUE); } if (data == NULL) { return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Buffer *buffer; switch (target) { case GL_ARRAY_BUFFER: @@ -594,17 +634,17 @@ GLenum __stdcall glCheckFramebufferStatu try { if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) { return error(GL_INVALID_ENUM, 0); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Framebuffer *framebuffer = NULL; if (target == GL_READ_FRAMEBUFFER_ANGLE) { framebuffer = context->getReadFramebuffer(); } @@ -625,17 +665,17 @@ GLenum __stdcall glCheckFramebufferStatu } void __stdcall glClear(GLbitfield mask) { EVENT("(GLbitfield mask = %X)", mask); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->clear(mask); } } catch(std::bad_alloc&) { @@ -645,17 +685,17 @@ void __stdcall glClear(GLbitfield mask) void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", red, green, blue, alpha); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setClearColor(red, green, blue, alpha); } } catch(std::bad_alloc&) { @@ -664,17 +704,17 @@ void __stdcall glClearColor(GLclampf red } void __stdcall glClearDepthf(GLclampf depth) { EVENT("(GLclampf depth = %f)", depth); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setClearDepth(depth); } } catch(std::bad_alloc&) { @@ -683,17 +723,17 @@ void __stdcall glClearDepthf(GLclampf de } void __stdcall glClearStencil(GLint s) { EVENT("(GLint s = %d)", s); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setClearStencil(s); } } catch(std::bad_alloc&) { @@ -703,17 +743,17 @@ void __stdcall glClearStencil(GLint 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)", red, green, blue, alpha); try { - gl::Context *context = gl::getContext(); + 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&) { @@ -722,17 +762,17 @@ void __stdcall glColorMask(GLboolean red } void __stdcall glCompileShader(GLuint shader) { EVENT("(GLuint shader = %d)", shader); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Shader *shaderObject = context->getShader(shader); if (!shaderObject) { if (context->getProgram(shader)) @@ -779,17 +819,17 @@ void __stdcall glCompressedTexImage2D(GL return error(GL_INVALID_ENUM); } if (border != 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { if (level > context->getMaximumTextureLevel()) { return error(GL_INVALID_VALUE); } @@ -855,27 +895,37 @@ void __stdcall glCompressedTexImage2D(GL { gl::Texture2D *texture = context->getTexture2D(); if (!texture) { return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + texture->setCompressedImage(level, internalformat, width, height, imageSize, data); } else { gl::TextureCubeMap *texture = context->getTextureCubeMap(); if (!texture) { return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return 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: @@ -924,17 +974,17 @@ void __stdcall glCompressedTexSubImage2D return error(GL_INVALID_ENUM); } if (width == 0 || height == 0 || data == NULL) { return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { if (level > context->getMaximumTextureLevel()) { return error(GL_INVALID_VALUE); } @@ -1041,20 +1091,25 @@ void __stdcall glCopyTexImage2D(GLenum t return error(GL_INVALID_VALUE); } if (border != 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + switch (target) { case GL_TEXTURE_2D: if (width > (context->getMaximumTextureDimension() >> level) || height > (context->getMaximumTextureDimension() >> level)) { return error(GL_INVALID_VALUE); } @@ -1087,17 +1142,17 @@ void __stdcall glCopyTexImage2D(GLenum t return error(GL_INVALID_FRAMEBUFFER_OPERATION); } if (context->getReadFramebufferHandle() != 0 && framebuffer->getColorbuffer()->getSamples() != 0) { return error(GL_INVALID_OPERATION); } - gl::Colorbuffer *source = framebuffer->getColorbuffer(); + gl::Renderbuffer *source = framebuffer->getColorbuffer(); GLenum colorbufferFormat = source->getInternalFormat(); // [OpenGL ES 2.0.24] table 3.9 switch (internalformat) { case GL_ALPHA: if (colorbufferFormat != GL_ALPHA && colorbufferFormat != GL_RGBA && @@ -1170,27 +1225,37 @@ void __stdcall glCopyTexImage2D(GLenum t { gl::Texture2D *texture = context->getTexture2D(); if (!texture) { return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + texture->copyImage(level, internalformat, x, y, width, height, framebuffer); } else if (gl::IsCubemapTextureTarget(target)) { gl::TextureCubeMap *texture = context->getTextureCubeMap(); if (!texture) { return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer); } else UNREACHABLE(); } } catch(std::bad_alloc&) { return error(GL_OUT_OF_MEMORY); @@ -1220,17 +1285,17 @@ void __stdcall glCopyTexSubImage2D(GLenu return error(GL_INVALID_VALUE); } if (width == 0 || height == 0) { return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { if (level > context->getMaximumTextureLevel()) { return error(GL_INVALID_VALUE); } @@ -1241,17 +1306,17 @@ void __stdcall glCopyTexSubImage2D(GLenu return error(GL_INVALID_FRAMEBUFFER_OPERATION); } if (context->getReadFramebufferHandle() != 0 && framebuffer->getColorbuffer()->getSamples() != 0) { return error(GL_INVALID_OPERATION); } - gl::Colorbuffer *source = framebuffer->getColorbuffer(); + gl::Renderbuffer *source = framebuffer->getColorbuffer(); GLenum colorbufferFormat = source->getInternalFormat(); gl::Texture *texture = NULL; if (target == GL_TEXTURE_2D) { texture = context->getTexture2D(); } else if (gl::IsCubemapTextureTarget(target)) @@ -1323,17 +1388,17 @@ void __stdcall glCopyTexSubImage2D(GLenu } GLuint __stdcall glCreateProgram(void) { EVENT("()"); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { return context->createProgram(); } } catch(std::bad_alloc&) { @@ -1344,17 +1409,17 @@ GLuint __stdcall glCreateProgram(void) } GLuint __stdcall glCreateShader(GLenum type) { EVENT("(GLenum type = 0x%X)", type); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { switch (type) { case GL_FRAGMENT_SHADER: case GL_VERTEX_SHADER: return context->createShader(type); @@ -1378,17 +1443,17 @@ void __stdcall glCullFace(GLenum mode) try { switch (mode) { case GL_FRONT: case GL_BACK: case GL_FRONT_AND_BACK: { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setCullMode(mode); } } break; default: @@ -1407,17 +1472,17 @@ void __stdcall glDeleteBuffers(GLsizei n try { if (n < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { for (int i = 0; i < n; i++) { context->deleteBuffer(buffers[i]); } } @@ -1434,17 +1499,17 @@ void __stdcall glDeleteFencesNV(GLsizei try { if (n < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { for (int i = 0; i < n; i++) { context->deleteFence(fences[i]); } } @@ -1461,17 +1526,17 @@ void __stdcall glDeleteFramebuffers(GLsi try { if (n < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { for (int i = 0; i < n; i++) { if (framebuffers[i] != 0) { context->deleteFramebuffer(framebuffers[i]); @@ -1491,17 +1556,17 @@ void __stdcall glDeleteProgram(GLuint pr try { if (program == 0) { return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { if (!context->getProgram(program)) { if(context->getShader(program)) { return error(GL_INVALID_OPERATION); @@ -1527,17 +1592,17 @@ void __stdcall glDeleteRenderbuffers(GLs try { if (n < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { for (int i = 0; i < n; i++) { context->deleteRenderbuffer(renderbuffers[i]); } } @@ -1554,17 +1619,17 @@ void __stdcall glDeleteShader(GLuint sha try { if (shader == 0) { return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { if (!context->getShader(shader)) { if(context->getProgram(shader)) { return error(GL_INVALID_OPERATION); @@ -1590,17 +1655,17 @@ void __stdcall glDeleteTextures(GLsizei try { if (n < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { for (int i = 0; i < n; i++) { if (textures[i] != 0) { context->deleteTexture(textures[i]); @@ -1630,17 +1695,17 @@ void __stdcall glDepthFunc(GLenum func) case GL_GREATER: case GL_GEQUAL: case GL_NOTEQUAL: break; default: return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setDepthFunc(func); } } catch(std::bad_alloc&) { @@ -1649,17 +1714,17 @@ void __stdcall glDepthFunc(GLenum func) } void __stdcall glDepthMask(GLboolean flag) { EVENT("(GLboolean flag = %d)", flag); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setDepthMask(flag != GL_FALSE); } } catch(std::bad_alloc&) { @@ -1668,17 +1733,17 @@ void __stdcall glDepthMask(GLboolean fla } void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar) { EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setDepthRange(zNear, zFar); } } catch(std::bad_alloc&) { @@ -1687,17 +1752,17 @@ void __stdcall glDepthRangef(GLclampf zN } void __stdcall glDetachShader(GLuint program, GLuint shader) { EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Program *programObject = context->getProgram(program); gl::Shader *shaderObject = context->getShader(shader); if (!programObject) @@ -1740,17 +1805,17 @@ void __stdcall glDetachShader(GLuint pro } void __stdcall glDisable(GLenum cap) { EVENT("(GLenum cap = 0x%X)", cap); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { 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; @@ -1777,17 +1842,17 @@ void __stdcall glDisableVertexAttribArra try { if (index >= gl::MAX_VERTEX_ATTRIBS) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setEnableVertexAttribArray(index, false); } } catch(std::bad_alloc&) { @@ -1801,17 +1866,17 @@ void __stdcall glDrawArrays(GLenum mode, try { if (count < 0 || first < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->drawArrays(mode, first, count); } } catch(std::bad_alloc&) { @@ -1826,17 +1891,17 @@ void __stdcall glDrawElements(GLenum mod try { if (count < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { switch (type) { case GL_UNSIGNED_BYTE: case GL_UNSIGNED_SHORT: break; @@ -1860,17 +1925,17 @@ void __stdcall glDrawElements(GLenum mod } void __stdcall glEnable(GLenum cap) { EVENT("(GLenum cap = 0x%X)", cap); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { 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; @@ -1897,17 +1962,17 @@ void __stdcall glEnableVertexAttribArray try { if (index >= gl::MAX_VERTEX_ATTRIBS) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setEnableVertexAttribArray(index, true); } } catch(std::bad_alloc&) { @@ -1916,17 +1981,17 @@ void __stdcall glEnableVertexAttribArray } void __stdcall glFinishFenceNV(GLuint fence) { EVENT("(GLuint fence = %d)", fence); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Fence* fenceObject = context->getFence(fence); if (fenceObject == NULL) { return error(GL_INVALID_OPERATION); @@ -1942,17 +2007,17 @@ void __stdcall glFinishFenceNV(GLuint fe } void __stdcall glFinish(void) { EVENT("()"); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->sync(true); } } catch(std::bad_alloc&) { @@ -1961,17 +2026,17 @@ void __stdcall glFinish(void) } void __stdcall glFlush(void) { EVENT("()"); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->sync(false); } } catch(std::bad_alloc&) { @@ -1987,17 +2052,17 @@ void __stdcall glFramebufferRenderbuffer try { if ((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0)) { return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Framebuffer *framebuffer = NULL; GLuint framebufferHandle = 0; if (target == GL_READ_FRAMEBUFFER_ANGLE) { framebuffer = context->getReadFramebuffer(); @@ -2053,17 +2118,17 @@ void __stdcall glFramebufferTexture2D(GL case GL_COLOR_ATTACHMENT0: case GL_DEPTH_ATTACHMENT: case GL_STENCIL_ATTACHMENT: break; default: return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { if (texture == 0) { textarget = GL_NONE; } else @@ -2149,17 +2214,17 @@ void __stdcall glFrontFace(GLenum mode) try { switch (mode) { case GL_CW: case GL_CCW: { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { context->setFrontFace(mode); } } break; default: @@ -2178,17 +2243,17 @@ void __stdcall glGenBuffers(GLsizei n, G try { if (n < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { for (int i = 0; i < n; i++) { buffers[i] = context->createBuffer(); } } @@ -2200,17 +2265,17 @@ void __stdcall glGenBuffers(GLsizei n, G } void __stdcall glGenerateMipmap(GLenum target) { EVENT("(GLenum target = 0x%X)", target); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Texture *texture; switch (target) { case GL_TEXTURE_2D: @@ -2245,17 +2310,17 @@ void __stdcall glGenFencesNV(GLsizei n, try { if (n < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { for (int i = 0; i < n; i++) { fences[i] = context->createFence(); } } @@ -2272,17 +2337,17 @@ void __stdcall glGenFramebuffers(GLsizei try { if (n < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { for (int i = 0; i < n; i++) { framebuffers[i] = context->createFramebuffer(); } } @@ -2299,17 +2364,17 @@ void __stdcall glGenRenderbuffers(GLsize try { if (n < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { for (int i = 0; i < n; i++) { renderbuffers[i] = context->createRenderbuffer(); } } @@ -2326,17 +2391,17 @@ void __stdcall glGenTextures(GLsizei n, try { if (n < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { for (int i = 0; i < n; i++) { textures[i] = context->createTexture(); } } @@ -2355,17 +2420,17 @@ void __stdcall glGetActiveAttrib(GLuint try { if (bufsize < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Program *programObject = context->getProgram(program); if (!programObject) { if (context->getShader(program)) @@ -2400,17 +2465,17 @@ void __stdcall glGetActiveUniform(GLuint try { if (bufsize < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Program *programObject = context->getProgram(program); if (!programObject) { if (context->getShader(program)) @@ -2444,17 +2509,17 @@ void __stdcall glGetAttachedShaders(GLui try { if (maxcount < 0) { return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Program *programObject = context->getProgram(program); if (!programObject) { if (context->getShader(program)) @@ -2477,17 +2542,17 @@ void __stdcall glGetAttachedShaders(GLui } int __stdcall glGetAttribLocation(GLuint program, const GLchar* name) { EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Program *programObject = context->getProgram(program); if (!programObject) { @@ -2518,17 +2583,17 @@ int __stdcall glGetAttribLocation(GLuint } void __stdcall glGetBooleanv(GLenum pname, GLboolean* params) { EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { if (!(context->getBooleanv(pname, params))) { GLenum nativeType; unsigned int numParams = 0; if (!context->getQueryParameterInfo(pname, &nativeType, &numParams)) @@ -2581,17 +2646,17 @@ void __stdcall glGetBooleanv(GLenum pnam } 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::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Buffer *buffer; switch (target) { case GL_ARRAY_BUFFER: @@ -2630,30 +2695,33 @@ void __stdcall glGetBufferParameteriv(GL GLenum __stdcall glGetError(void) { EVENT("()"); gl::Context *context = gl::getContext(); if (context) { - return context->getError(); + if (context->isContextLost()) + return GL_OUT_OF_MEMORY; + else + return context->getError(); } return GL_NO_ERROR; } 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::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Fence *fenceObject = context->getFence(fence); if (fenceObject == NULL) { return error(GL_INVALID_OPERATION); @@ -2669,17 +2737,17 @@ void __stdcall glGetFenceivNV(GLuint fen }