@@ -109,7 +109,103 @@ static bool MeetsRequirements(const FunctionsGL *functions,
109109 }
110110}
111111
112+ static bool CheckSizedInternalFormatTextureRenderability (const FunctionsGL *functions,
113+ const WorkaroundsGL &workarounds,
114+ GLenum internalFormat)
115+ {
116+ const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo (internalFormat);
117+ ASSERT (formatInfo.sized );
118+
119+ // Query the current texture so it can be rebound afterwards
120+ GLint oldTextureBinding = 0 ;
121+ functions->getIntegerv (GL_TEXTURE_BINDING_2D, &oldTextureBinding);
122+
123+ // Create a small texture with the same format and type that gl::Texture would use
124+ GLuint texture = 0 ;
125+ functions->genTextures (1 , &texture);
126+ functions->bindTexture (GL_TEXTURE_2D, texture);
127+
128+ // Nearest filter needed for framebuffer completeness on some drivers.
129+ functions->texParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
130+
131+ nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat (
132+ functions, workarounds, formatInfo.internalFormat , formatInfo.format , formatInfo.type );
133+ constexpr GLsizei kTextureSize = 16 ;
134+ functions->texImage2D (GL_TEXTURE_2D, 0 , texImageFormat.internalFormat , kTextureSize ,
135+ kTextureSize , 0 , texImageFormat.format , texImageFormat.type , nullptr );
136+
137+ // Query the current framebuffer so it can be rebound afterwards
138+ GLint oldFramebufferBinding = 0 ;
139+ functions->getIntegerv (GL_FRAMEBUFFER_BINDING, &oldFramebufferBinding);
140+
141+ // Bind the texture to the framebuffer and check renderability
142+ GLuint fbo = 0 ;
143+ functions->genFramebuffers (1 , &fbo);
144+ functions->bindFramebuffer (GL_FRAMEBUFFER, fbo);
145+ functions->framebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,
146+ 0 );
147+
148+ bool supported = functions->checkFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
149+
150+ // Delete the framebuffer and restore the previous binding
151+ functions->deleteFramebuffers (1 , &fbo);
152+ functions->bindFramebuffer (GL_FRAMEBUFFER, static_cast <GLuint>(oldFramebufferBinding));
153+
154+ // Delete the texture and restore the previous binding
155+ functions->deleteTextures (1 , &texture);
156+ functions->bindTexture (GL_TEXTURE_2D, static_cast <GLuint>(oldTextureBinding));
157+
158+ return supported;
159+ }
160+
161+ static bool CheckInternalFormatRenderbufferRenderability (const FunctionsGL *functions,
162+ const WorkaroundsGL &workarounds,
163+ GLenum internalFormat)
164+ {
165+ const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo (internalFormat);
166+ ASSERT (formatInfo.sized );
167+
168+ // Query the current renderbuffer so it can be rebound afterwards
169+ GLint oldRenderbufferBinding = 0 ;
170+ functions->getIntegerv (GL_RENDERBUFFER_BINDING, &oldRenderbufferBinding);
171+
172+ // Create a small renderbuffer with the same format and type that gl::Renderbuffer would use
173+ GLuint renderbuffer = 0 ;
174+ functions->genRenderbuffers (1 , &renderbuffer);
175+ functions->bindRenderbuffer (GL_RENDERBUFFER, renderbuffer);
176+
177+ nativegl::RenderbufferFormat renderbufferFormat =
178+ nativegl::GetRenderbufferFormat (functions, workarounds, formatInfo.internalFormat );
179+ constexpr GLsizei kRenderbufferSize = 16 ;
180+ functions->renderbufferStorage (GL_RENDERBUFFER, renderbufferFormat.internalFormat ,
181+ kRenderbufferSize , kRenderbufferSize );
182+
183+ // Query the current framebuffer so it can be rebound afterwards
184+ GLint oldFramebufferBinding = 0 ;
185+ functions->getIntegerv (GL_FRAMEBUFFER_BINDING, &oldFramebufferBinding);
186+
187+ // Bind the texture to the framebuffer and check renderability
188+ GLuint fbo = 0 ;
189+ functions->genFramebuffers (1 , &fbo);
190+ functions->bindFramebuffer (GL_FRAMEBUFFER, fbo);
191+ functions->framebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
192+ renderbuffer);
193+
194+ bool supported = functions->checkFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
195+
196+ // Delete the framebuffer and restore the previous binding
197+ functions->deleteFramebuffers (1 , &fbo);
198+ functions->bindFramebuffer (GL_FRAMEBUFFER, static_cast <GLuint>(oldFramebufferBinding));
199+
200+ // Delete the renderbuffer and restore the previous binding
201+ functions->deleteRenderbuffers (1 , &renderbuffer);
202+ functions->bindRenderbuffer (GL_RENDERBUFFER, static_cast <GLuint>(oldRenderbufferBinding));
203+
204+ return supported;
205+ }
206+
112207static gl::TextureCaps GenerateTextureFormatCaps (const FunctionsGL *functions,
208+ const WorkaroundsGL &workarounds,
113209 GLenum internalFormat)
114210{
115211 ASSERT (functions->getError () == GL_NO_ERROR);
@@ -124,6 +220,23 @@ static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions,
124220 textureCaps.textureAttachment = MeetsRequirements (functions, formatInfo.textureAttachment );
125221 textureCaps.renderbuffer = MeetsRequirements (functions, formatInfo.renderbuffer );
126222
223+ // Do extra renderability validation for some formats.
224+ // We require GL_RGBA16F is renderable to expose EXT_color_buffer_half_float but we can't know
225+ // if the format is supported unless we try to create a framebuffer.
226+ if (internalFormat == GL_RGBA16F)
227+ {
228+ if (textureCaps.textureAttachment )
229+ {
230+ textureCaps.textureAttachment = CheckSizedInternalFormatTextureRenderability (
231+ functions, workarounds, internalFormat);
232+ }
233+ if (textureCaps.renderbuffer )
234+ {
235+ textureCaps.renderbuffer = CheckInternalFormatRenderbufferRenderability (
236+ functions, workarounds, internalFormat);
237+ }
238+ }
239+
127240 // glGetInternalformativ is not available until version 4.2 but may be available through the 3.0
128241 // extension GL_ARB_internalformat_query
129242 if (textureCaps.renderbuffer && functions->getInternalformativ )
@@ -281,7 +394,8 @@ void GenerateCaps(const FunctionsGL *functions,
281394 const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats ();
282395 for (GLenum internalFormat : allFormats)
283396 {
284- gl::TextureCaps textureCaps = GenerateTextureFormatCaps (functions, internalFormat);
397+ gl::TextureCaps textureCaps =
398+ GenerateTextureFormatCaps (functions, workarounds, internalFormat);
285399 textureCapsMap->insert (internalFormat, textureCaps);
286400
287401 if (gl::GetSizedInternalFormatInfo (internalFormat).compressed )
0 commit comments