diff --git a/bindings/bf/bgfx.bf b/bindings/bf/bgfx.bf
index 5902503d8..163c4b47e 100644
--- a/bindings/bf/bgfx.bf
+++ b/bindings/bf/bgfx.bf
@@ -1288,6 +1288,11 @@ public static class bgfx
/// Microsoft adapter.
///
Microsoft = 0x1414,
+
+ ///
+ /// ARM adapter.
+ ///
+ Arm = 0x13b5,
}
[AllowDuplicates]
diff --git a/bindings/cs/bgfx.cs b/bindings/cs/bgfx.cs
index 7ee7bebb7..23ad28423 100644
--- a/bindings/cs/bgfx.cs
+++ b/bindings/cs/bgfx.cs
@@ -1287,6 +1287,11 @@ public static partial class bgfx
/// Microsoft adapter.
///
Microsoft = 0x1414,
+
+ ///
+ /// ARM adapter.
+ ///
+ Arm = 0x13b5,
}
[Flags]
diff --git a/bindings/d/types.d b/bindings/d/types.d
index 2f7a26dc6..fa9b32aa0 100644
--- a/bindings/d/types.d
+++ b/bindings/d/types.d
@@ -438,6 +438,7 @@ enum ushort BGFX_PCI_ID_APPLE = 0x106b; /// Apple adapter.
enum ushort BGFX_PCI_ID_INTEL = 0x8086; /// Intel adapter.
enum ushort BGFX_PCI_ID_NVIDIA = 0x10de; /// nVidia adapter.
enum ushort BGFX_PCI_ID_MICROSOFT = 0x1414; /// Microsoft adapter.
+enum ushort BGFX_PCI_ID_ARM = 0x13b5; /// ARM adapter.
enum ubyte BGFX_CUBE_MAP_POSITIVE_X = 0x00; /// Cubemap +x.
enum ubyte BGFX_CUBE_MAP_NEGATIVE_X = 0x01; /// Cubemap -x.
diff --git a/bindings/zig/bgfx.zig b/bindings/zig/bgfx.zig
index 0244a56be..1cfdfe0bf 100644
--- a/bindings/zig/bgfx.zig
+++ b/bindings/zig/bgfx.zig
@@ -789,6 +789,9 @@ pub const PciIdFlags_Nvidia: PciIdFlags = 0x10de;
/// Microsoft adapter.
pub const PciIdFlags_Microsoft: PciIdFlags = 0x1414;
+/// ARM adapter.
+pub const PciIdFlags_Arm: PciIdFlags = 0x13b5;
+
pub const CubeMapFlags = u32;
/// Cubemap +x.
pub const CubeMapFlags_PositiveX: CubeMapFlags = 0x00000000;
diff --git a/include/bgfx/defines.h b/include/bgfx/defines.h
index 3d7dcc165..9e30eeb4b 100644
--- a/include/bgfx/defines.h
+++ b/include/bgfx/defines.h
@@ -524,6 +524,7 @@
#define BGFX_PCI_ID_INTEL UINT16_C(0x8086) //!< Intel adapter.
#define BGFX_PCI_ID_NVIDIA UINT16_C(0x10de) //!< nVidia adapter.
#define BGFX_PCI_ID_MICROSOFT UINT16_C(0x1414) //!< Microsoft adapter.
+#define BGFX_PCI_ID_ARM UINT16_C(0x13b5) //!< ARM adapter.
#define BGFX_CUBE_MAP_POSITIVE_X UINT8_C(0x00) //!< Cubemap +x.
#define BGFX_CUBE_MAP_NEGATIVE_X UINT8_C(0x01) //!< Cubemap -x.
diff --git a/scripts/bgfx.idl b/scripts/bgfx.idl
index 572f1a6ef..dd27df0e7 100644
--- a/scripts/bgfx.idl
+++ b/scripts/bgfx.idl
@@ -429,6 +429,7 @@ flag.PciId { bits = 16 , const }
.Intel (0x8086) --- Intel adapter.
.Nvidia (0x10de) --- nVidia adapter.
.Microsoft (0x1414) --- Microsoft adapter.
+ .Arm (0x13b5) --- ARM adapter.
()
flag.CubeMap { bits = 8, const }
diff --git a/src/glimports.h b/src/glimports.h
index 8cc8854e4..502a2b311 100644
--- a/src/glimports.h
+++ b/src/glimports.h
@@ -228,6 +228,7 @@ typedef void (GL_APIENTRYP PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC)(GL
typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMGPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
#endif // GL_IMPORT_TYPEDEFS
#if BGFX_USE_GL_DYNAMIC_LIB
@@ -495,6 +496,7 @@ GL_IMPORT______(true, PFNGLGETINTERNALFORMATI64VPROC, glGetInternal
#endif // BGFX_USE_GL_DYNAMIC_LIB
GL_IMPORT______(true, PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC, glGetTranslatedShaderSourceANGLE);
+GL_IMPORT______(true, PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMGPROC, glFramebufferTexture2DMultisampleEXT);
#if !BGFX_CONFIG_RENDERER_OPENGL
GL_IMPORT______(true, PFNGLPOINTSIZEPROC, glPointSize);
diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp
index ca14f089c..22fffcb22 100644
--- a/src/renderer_gl.cpp
+++ b/src/renderer_gl.cpp
@@ -2143,6 +2143,7 @@ namespace bgfx { namespace gl
{ "Advanced Micro Devices, Inc.", BGFX_PCI_ID_AMD },
{ "Intel", BGFX_PCI_ID_INTEL },
{ "ATI Technologies Inc.", BGFX_PCI_ID_AMD },
+ { "ARM", BGFX_PCI_ID_ARM },
};
struct Workaround
@@ -2185,6 +2186,7 @@ namespace bgfx { namespace gl
, m_hash( (BX_PLATFORM_WINDOWS<<1) | BX_ARCH_64BIT)
, m_backBufferFbo(0)
, m_msaaBackBufferFbo(0)
+ , m_msaaBlitProgram(0)
, m_clearQuadColor(BGFX_INVALID_HANDLE)
, m_clearQuadDepth(BGFX_INVALID_HANDLE)
{
@@ -3801,34 +3803,122 @@ namespace bgfx { namespace gl
void createMsaaFbo(uint32_t _width, uint32_t _height, uint32_t _msaa)
{
if (0 == m_msaaBackBufferFbo // iOS
- && 1 < _msaa)
+ && 1 < _msaa)
{
GLenum storageFormat = (m_resolution.reset & BGFX_RESET_SRGB_BACKBUFFER)
- ? GL_SRGB8_ALPHA8
- : GL_RGBA8
- ;
+ ? GL_SRGB8_ALPHA8
+ : GL_RGBA8
+ ;
+ GLenum attachment = BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) || m_gles3
+ ? GL_DEPTH_STENCIL_ATTACHMENT
+ : GL_DEPTH_ATTACHMENT;
GL_CHECK(glGenFramebuffers(1, &m_msaaBackBufferFbo) );
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaBackBufferFbo) );
- GL_CHECK(glGenRenderbuffers(BX_COUNTOF(m_msaaBackBufferRbos), m_msaaBackBufferRbos) );
- GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_msaaBackBufferRbos[0]) );
- GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER, _msaa, storageFormat, _width, _height) );
- GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_msaaBackBufferRbos[1]) );
- GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER, _msaa, GL_DEPTH24_STENCIL8, _width, _height) );
- GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_msaaBackBufferRbos[0]) );
+ if (g_caps.vendorId == BGFX_PCI_ID_ARM && m_gles3) {
+ GL_CHECK(glGenTextures(BX_COUNTOF(m_msaaBackBufferTextures), m_msaaBackBufferTextures));
+ GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_msaaBackBufferTextures[0]));
+ GL_CHECK(glTexStorage2D(GL_TEXTURE_2D, 1, storageFormat, _width, _height));
+ GL_CHECK(glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ m_msaaBackBufferTextures[0], 0,
+ _msaa));
+ GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaBackBufferFbo));
- GLenum attachment = BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) || m_gles3
- ? GL_DEPTH_STENCIL_ATTACHMENT
- : GL_DEPTH_ATTACHMENT
- ;
- GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, m_msaaBackBufferRbos[1]) );
+ GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_msaaBackBufferTextures[1]));
+ GL_CHECK(glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, _width, _height));
+ GL_CHECK(glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER,
+ attachment,
+ GL_TEXTURE_2D,
+ m_msaaBackBufferTextures[1], 0,
+ _msaa));
+ GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
- BX_ASSERT(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER)
+ BX_ASSERT(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER),
+ "glCheckFramebufferStatus failed 0x%08x",
+ glCheckFramebufferStatus(GL_FRAMEBUFFER)
+ );
+
+ if (0 == m_msaaBlitProgram) {
+ static const char msaa_blit_vs[]{R"(#version 300 es
+ precision highp float;
+ out vec2 UV;
+ void main() {
+ float x = -1.0 + float((gl_VertexID & 1) << 2);
+ float y = -1.0 + float((gl_VertexID & 2) << 1);
+ gl_Position = vec4(x, y, 0, 1);
+ UV = vec2(gl_Position.x + 1.0, gl_Position.y + 1.0) * 0.5;
+ }
+ )"};
+
+ static const char msaa_blit_fs[]{R"(#version 300 es
+ precision mediump float;
+ in vec2 UV;
+ uniform sampler2D msaaTexture;
+ out vec4 oFragColor;
+ void main() {
+ oFragColor = texture(msaaTexture, UV);
+ }
+ )"};
+
+ const GLchar *const vs = msaa_blit_vs;
+ const GLchar *const fs = msaa_blit_fs;
+ GLuint shader_vs = glCreateShader(GL_VERTEX_SHADER);
+ BX_WARN(0 != shader_vs, "Failed to create msaa Blit Vertex shader.");
+ GL_CHECK(glShaderSource(shader_vs, 1, &vs, nullptr));
+ GL_CHECK(glCompileShader(shader_vs));
+ GLint compiled = 0;
+ GL_CHECK(glGetShaderiv(shader_vs, GL_COMPILE_STATUS, &compiled));
+ BX_WARN(0 == shader_vs, "Unable to compile msaa Blit Vertex shader.");
+
+ GLuint shader_fs = glCreateShader(GL_FRAGMENT_SHADER);
+ BX_WARN(0 != shader_fs, "Failed to create msaa Blit Fragment shader.");
+ GL_CHECK(glShaderSource(shader_fs, 1, &fs, nullptr));
+ GL_CHECK(glCompileShader(shader_fs));
+ compiled = 0;
+ GL_CHECK(glGetShaderiv(shader_fs, GL_COMPILE_STATUS, &compiled));
+ BX_WARN(0 == shader_vs, "Unable to compile msaa Blit Fragment shader.");
+
+ m_msaaBlitProgram = glCreateProgram();
+ if (m_msaaBlitProgram)
+ {
+ GL_CHECK(glAttachShader(m_msaaBlitProgram, shader_vs));
+ GL_CHECK(glAttachShader(m_msaaBlitProgram, shader_fs));
+
+ GL_CHECK(glLinkProgram(m_msaaBlitProgram));
+ GLint linked = 0;
+ glGetProgramiv(m_msaaBlitProgram, GL_LINK_STATUS, &linked);
+ if (0 == linked) {
+ char log[1024];
+ GL_CHECK(glGetProgramInfoLog(m_msaaBlitProgram, sizeof(log), NULL,
+ log));
+ BX_TRACE("%d: %s", linked, log);
+ }
+
+ GL_CHECK(glDetachShader(m_msaaBlitProgram, shader_vs));
+ GL_CHECK(glDeleteShader(shader_vs));
+ GL_CHECK(glDetachShader(m_msaaBlitProgram, shader_fs));
+ GL_CHECK(glDeleteShader(shader_fs));
+ }
+ }
+ }
+ else
+ {
+ GL_CHECK(glGenRenderbuffers(BX_COUNTOF(m_msaaBackBufferRbos), m_msaaBackBufferRbos));
+ GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_msaaBackBufferRbos[0]) );
+ GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER, _msaa, storageFormat, _width, _height) );
+ GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_msaaBackBufferRbos[1]) );
+ GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER, _msaa, GL_DEPTH24_STENCIL8, _width, _height) );
+ GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_msaaBackBufferRbos[0]) );
+
+ GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, m_msaaBackBufferRbos[1]) );
+
+ BX_ASSERT(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER)
, "glCheckFramebufferStatus failed 0x%08x"
, glCheckFramebufferStatus(GL_FRAMEBUFFER)
);
-
- GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaBackBufferFbo) );
+ }
}
}
@@ -3840,11 +3930,28 @@ namespace bgfx { namespace gl
GL_CHECK(glDeleteFramebuffers(1, &m_msaaBackBufferFbo) );
m_msaaBackBufferFbo = 0;
- if (0 != m_msaaBackBufferRbos[0])
+ if (g_caps.vendorId == BGFX_PCI_ID_ARM && m_gles3)
{
- GL_CHECK(glDeleteRenderbuffers(BX_COUNTOF(m_msaaBackBufferRbos), m_msaaBackBufferRbos) );
- m_msaaBackBufferRbos[0] = 0;
- m_msaaBackBufferRbos[1] = 0;
+ if (0 != m_msaaBackBufferTextures[0])
+ {
+ GL_CHECK(glDeleteTextures(BX_COUNTOF(m_msaaBackBufferTextures), m_msaaBackBufferTextures));
+ m_msaaBackBufferTextures[0] = 0;
+ m_msaaBackBufferTextures[1] = 0;
+ }
+ if (0 != m_msaaBlitProgram)
+ {
+ GL_CHECK(glDeleteProgram(m_msaaBlitProgram) );
+ m_msaaBlitProgram = 0;
+ }
+ }
+ else
+ {
+ if (0 != m_msaaBackBufferRbos[0])
+ {
+ GL_CHECK(glDeleteRenderbuffers(BX_COUNTOF(m_msaaBackBufferRbos), m_msaaBackBufferRbos));
+ m_msaaBackBufferRbos[0] = 0;
+ m_msaaBackBufferRbos[1] = 0;
+ }
}
}
}
@@ -3861,20 +3968,31 @@ namespace bgfx { namespace gl
uint32_t width = m_resolution.width;
uint32_t height = m_resolution.height;
GLenum filter = BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) || !m_gles3
- ? GL_NEAREST
- : GL_LINEAR
- ;
- GL_CHECK(glBlitFramebuffer(0
- , 0
- , width
- , height
- , 0
- , 0
- , width
- , height
- , GL_COLOR_BUFFER_BIT
- , filter
- ) );
+ ? GL_NEAREST
+ : GL_LINEAR
+ ;
+ if (g_caps.vendorId == BGFX_PCI_ID_ARM && m_gles3)
+ {
+ GL_CHECK(glUseProgram(m_msaaBlitProgram));
+ GL_CHECK(glActiveTexture(GL_TEXTURE0));
+ GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_msaaBackBufferTextures[0]));
+ GL_CHECK(glDrawArrays(GL_TRIANGLES, 0, 3));
+ }
+ else
+ {
+ GL_CHECK(glBlitFramebuffer(0
+ , 0
+ , width
+ , height
+ , 0
+ , 0
+ , width
+ , height
+ , GL_COLOR_BUFFER_BIT
+ , filter
+ ));
+ }
+
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_backBufferFbo) );
}
}
@@ -4541,7 +4659,11 @@ namespace bgfx { namespace gl
GLenum m_readPixelsFmt;
GLuint m_backBufferFbo;
GLuint m_msaaBackBufferFbo;
- GLuint m_msaaBackBufferRbos[2];
+ union {
+ GLuint m_msaaBackBufferRbos[2];
+ GLuint m_msaaBackBufferTextures[2];
+ };
+ GLuint m_msaaBlitProgram;
GlContext m_glctx;
bool m_needPresent;