aboutsummaryrefslogtreecommitdiff
path: root/shared/OpenglCodecCommon
diff options
context:
space:
mode:
authorLingfeng Yang <lfy@google.com>2016-09-16 08:54:03 -0700
committerLingfeng Yang <lfy@google.com>2016-09-16 12:18:05 -0700
commite00ec9ddda30f6be5c027ccffd39e98a84e9acc9 (patch)
treedd013ff0e49608f1a9a32a36291b93ac71ce04f1 /shared/OpenglCodecCommon
parentbc7edb2c2306aa8dbdc36e903c4fce4a3efd831d (diff)
downloadgoldfish-opengl-e00ec9ddda30f6be5c027ccffd39e98a84e9acc9.tar.gz
[AMD] Fix segfault in glCopyTexImage + cube map luminance
bug: 31523568 In particular, the test dEQP.functional.texture.specification.basic_copyteximage2d.cube_luminance segfaults the emulator on some AMD GPUs. When we define cube maps using glCopyTexImage2D and are using the GL_LUMINANCE internal format, if the negative components of the cube map are defined first, the host AMD driver may segfault (tested in Mobility Radeon and RX 480). The workaround is to detect this particular API call, cube map target, and internal format, and define the positive component first using the same arguments, if the positive component has not been defined already. Change-Id: I26ed25bf3b7358ed7121a52f89d541c325beb6e4
Diffstat (limited to 'shared/OpenglCodecCommon')
-rw-r--r--shared/OpenglCodecCommon/GLClientState.cpp66
-rw-r--r--shared/OpenglCodecCommon/GLClientState.h39
2 files changed, 105 insertions, 0 deletions
diff --git a/shared/OpenglCodecCommon/GLClientState.cpp b/shared/OpenglCodecCommon/GLClientState.cpp
index 4fb081b2..ac97fcf7 100644
--- a/shared/OpenglCodecCommon/GLClientState.cpp
+++ b/shared/OpenglCodecCommon/GLClientState.cpp
@@ -433,6 +433,72 @@ GLuint GLClientState::getBoundTexture(GLenum target) const
}
}
+// BEGIN driver workarounds-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
+// (>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')>
+
+static bool unreliableInternalFormat(GLenum internalformat) {
+ switch (internalformat) {
+ case GL_LUMINANCE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void GLClientState::writeCopyTexImageState
+ (GLenum target, GLint level, GLenum internalformat) {
+ if (unreliableInternalFormat(internalformat)) {
+ CubeMapDef entry;
+ entry.id = getBoundTexture(GL_TEXTURE_2D);
+ entry.target = target;
+ entry.level = level;
+ entry.internalformat = internalformat;
+ m_cubeMapDefs.insert(entry);
+ }
+}
+
+static GLenum identifyPositiveCubeMapComponent(GLenum target) {
+ switch (target) {
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
+ default:
+ return 0;
+ }
+}
+
+GLenum GLClientState::copyTexImageNeededTarget
+ (GLenum target, GLint level, GLenum internalformat) {
+ if (unreliableInternalFormat(internalformat)) {
+ GLenum positiveComponent =
+ identifyPositiveCubeMapComponent(target);
+ if (positiveComponent) {
+ CubeMapDef query;
+ query.id = getBoundTexture(GL_TEXTURE_2D);
+ query.target = positiveComponent;
+ query.level = level;
+ query.internalformat = internalformat;
+ if (m_cubeMapDefs.find(query) ==
+ m_cubeMapDefs.end()) {
+ return positiveComponent;
+ }
+ }
+ }
+ return 0;
+}
+
+GLenum GLClientState::copyTexImageLuminanceCubeMapAMDWorkaround
+ (GLenum target, GLint level, GLenum internalformat) {
+ writeCopyTexImageState(target, level, internalformat);
+ return copyTexImageNeededTarget(target, level, internalformat);
+}
+
+// (>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')>
+// END driver workarounds-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
+
void GLClientState::deleteTextures(GLsizei n, const GLuint* textures)
{
// Updating the textures array could be made more efficient when deleting
diff --git a/shared/OpenglCodecCommon/GLClientState.h b/shared/OpenglCodecCommon/GLClientState.h
index 020d9e06..8c876cb9 100644
--- a/shared/OpenglCodecCommon/GLClientState.h
+++ b/shared/OpenglCodecCommon/GLClientState.h
@@ -33,6 +33,7 @@
#include "codec_defs.h"
#include <vector>
+#include <set>
// Tracking framebuffer objects:
// which framebuffer is bound,
@@ -233,6 +234,18 @@ public:
// Return the texture currently bound to GL_TEXTURE_(2D|EXTERNAL_OES).
GLuint getBoundTexture(GLenum target) const;
+ // For AMD GPUs, it is easy for the emulator to segfault
+ // (esp. in dEQP) when a cube map is defined using glCopyTexImage2D
+ // and uses GL_LUMINANCE as internal format.
+ // In particular, the segfault happens when negative components of
+ // cube maps are defined before positive ones,
+ // This procedure checks internal state to see if we have defined
+ // the positive component of a cube map already. If not, it returns
+ // which positive component needs to be defined first.
+ // If there is no need for the extra definition, 0 is returned.
+ GLenum copyTexImageLuminanceCubeMapAMDWorkaround(GLenum target, GLint level,
+ GLenum internalformat);
+
// Tracks the format of the currently bound texture.
// This is to pass dEQP tests for fbo completeness.
void setBoundTextureInternalFormat(GLenum target, GLint format);
@@ -319,6 +332,32 @@ private:
};
TextureState m_tex;
+ // State tracking of cube map definitions.
+ // Currently used only for driver workarounds
+ // when using GL_LUMINANCE and defining cube maps with
+ // glCopyTexImage2D.
+ struct CubeMapDef {
+ GLuint id;
+ GLenum target;
+ GLint level;
+ GLenum internalformat;
+ };
+ struct CubeMapDefCompare {
+ bool operator() (const CubeMapDef& a,
+ const CubeMapDef& b) const {
+ if (a.id != b.id) return a.id < b.id;
+ if (a.target != b.target) return a.target < b.target;
+ if (a.level != b.level) return a.level < b.level;
+ if (a.internalformat != b.internalformat)
+ return a.internalformat < b.internalformat;
+ return false;
+ }
+ };
+ std::set<CubeMapDef, CubeMapDefCompare> m_cubeMapDefs;
+ void writeCopyTexImageState(GLenum target, GLint level,
+ GLenum internalformat);
+ GLenum copyTexImageNeededTarget(GLenum target, GLint level,
+ GLenum internalformat);
struct RboState {
GLuint boundRenderbuffer;