// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved. #pragma once #if GRAPHICS_API_OPENGL #include "Engine/Graphics/Config.h" #include "Engine/Graphics/GPULimits.h" #include "Engine/Graphics/RenderTools.h" #include "GPUDeviceOGL.h" #if BUILD_DEBUG #include "Engine/Core/Types/StringBuilder.h" #endif struct TextureFormatOGL { public: GLenum InternalFormat; GLenum Format; GLenum Type; bool IsCompressed; public: TextureFormatOGL() { InternalFormat = GL_NONE; Format = GL_NONE; Type = GL_NONE; IsCompressed = false; } TextureFormatOGL(GLenum internalFormat, GLenum format, GLenum type, bool isCompressed = false, bool isBGRA = false) { InternalFormat = internalFormat; Format = format; Type = type; IsCompressed = isCompressed; } }; /// /// Implementation of GPU Limits for OpenGL /// /// class GPULimitsOGL : public GPULimits { protected: GPUDeviceOGL * _device; public: /// /// Initializes a new instance of the class. /// /// The device. GPULimitsOGL(GPUDeviceOGL* device) : _device(device) { } public: bool SupportsTessellation; bool SupportsGPUMemoryInfo; bool SupportsComputeShaders; bool SupportsVertexAttribBinding; bool SupportsTextureView; bool SupportsVolumeTextureRendering; bool SupportsASTC; bool SupportsCopyImage; bool SupportsSeamlessCubemap; bool SupportsTextureFilterAnisotropic; bool SupportsDrawBuffersBlend; bool SupportsSeparateShaderObjects; bool SupportsClipControl; uint64 VideoMemorySize; int32 MaxTextureMipCount; int32 MaxTextureSize; int32 MaxCubeTextureSize; int32 MaxVolumeTextureSize; int32 MaxTextureArraySize; int32 MaxOpenGLDrawBuffers; int32 MaxTextureImageUnits; int32 MaxCombinedTextureImageUnits; int32 MaxVertexTextureImageUnits; int32 MaxGeometryTextureImageUnits; int32 MaxHullTextureImageUnits; int32 MaxDomainTextureImageUnits; int32 MaxVaryingVectors; int32 MaxVertexUniformComponents; int32 MaxPixelUniformComponents; int32 MaxGeometryUniformComponents; int32 MaxHullUniformComponents; int32 MaxDomainUniformComponents; int32 MaxComputeTextureImageUnits; int32 MaxComputeUniformComponents; TextureFormatOGL TextureFormats[static_cast(PixelFormat::Maximum)]; public: GLenum GetInternalTextureFormat(PixelFormat format) { return TextureFormats[(int32)format].InternalFormat; } GLenum GetInternalTextureFormat(PixelFormat format, GPUTextureFlags flags) { GLenum f = TextureFormats[(int32)format].InternalFormat; // Correct GL texure format if (flags & GPUTextureFlags::DepthStencil) { if (f == GL_R32F) f = GL_DEPTH_COMPONENT32F; else if (f == GL_R16) f = GL_DEPTH_COMPONENT16; } return f; } private: void InitFormats() { // References: // http://www.opengl.org/wiki/Image_Format // http://www.g-truc.net/post-0335.html // http://renderingpipeline.com/2012/07/texture-compression/ TextureFormats[(int32)PixelFormat::Unknown] = TextureFormatOGL(); TextureFormats[(int32)PixelFormat::R32G32B32A32_Typeless] = TextureFormatOGL(GL_RGBA32F, GL_RGBA, GL_FLOAT); TextureFormats[(int32)PixelFormat::R32G32B32A32_Float] = TextureFormatOGL(GL_RGBA32F, GL_RGBA, GL_FLOAT); TextureFormats[(int32)PixelFormat::R32G32B32A32_UInt] = TextureFormatOGL(GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT); TextureFormats[(int32)PixelFormat::R32G32B32A32_SInt] = TextureFormatOGL(GL_RGBA32I, GL_RGBA_INTEGER, GL_INT); TextureFormats[(int32)PixelFormat::R32G32B32_Typeless] = TextureFormatOGL(GL_RGB32F, GL_RGB, GL_FLOAT); TextureFormats[(int32)PixelFormat::R32G32B32_Float] = TextureFormatOGL(GL_RGB32F, GL_RGB, GL_FLOAT); TextureFormats[(int32)PixelFormat::R32G32B32_UInt] = TextureFormatOGL(GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT); TextureFormats[(int32)PixelFormat::R32G32B32_SInt] = TextureFormatOGL(GL_RGB32I, GL_RGB_INTEGER, GL_INT); TextureFormats[(int32)PixelFormat::R16G16B16A16_Typeless] = TextureFormatOGL(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); TextureFormats[(int32)PixelFormat::R16G16B16A16_Float] = TextureFormatOGL(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); TextureFormats[(int32)PixelFormat::R16G16B16A16_UNorm] = TextureFormatOGL(GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT); TextureFormats[(int32)PixelFormat::R16G16B16A16_UInt] = TextureFormatOGL(GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT); TextureFormats[(int32)PixelFormat::R16G16B16A16_SNorm] = TextureFormatOGL(GL_RGBA16_SNORM, GL_RGBA, GL_SHORT); TextureFormats[(int32)PixelFormat::R16G16B16A16_SInt] = TextureFormatOGL(GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT); TextureFormats[(int32)PixelFormat::R32G32_Typeless] = TextureFormatOGL(GL_RG32F, GL_RG, GL_FLOAT); TextureFormats[(int32)PixelFormat::R32G32_Float] = TextureFormatOGL(GL_RG32F, GL_RG, GL_FLOAT); TextureFormats[(int32)PixelFormat::R32G32_UInt] = TextureFormatOGL(GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT); TextureFormats[(int32)PixelFormat::R32G32_SInt] = TextureFormatOGL(GL_RG32I, GL_RG_INTEGER, GL_INT); TextureFormats[(int32)PixelFormat::R32G8X24_Typeless] = TextureFormatOGL(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV); TextureFormats[(int32)PixelFormat::D32_Float_S8X24_UInt] = TextureFormatOGL(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV); TextureFormats[(int32)PixelFormat::R32_Float_X8X24_Typeless] = TextureFormatOGL(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV); TextureFormats[(int32)PixelFormat::X32_Typeless_G8X24_UInt] = TextureFormatOGL(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV); TextureFormats[(int32)PixelFormat::R10G10B10A2_Typeless] = TextureFormatOGL(GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV); TextureFormats[(int32)PixelFormat::R10G10B10A2_UNorm] = TextureFormatOGL(GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV); TextureFormats[(int32)PixelFormat::R10G10B10A2_UInt] = TextureFormatOGL(GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV); TextureFormats[(int32)PixelFormat::R11G11B10_Float] = TextureFormatOGL(GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV); TextureFormats[(int32)PixelFormat::R8G8B8A8_Typeless] = TextureFormatOGL(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); TextureFormats[(int32)PixelFormat::R8G8B8A8_UNorm] = TextureFormatOGL(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); TextureFormats[(int32)PixelFormat::R8G8B8A8_UNorm_sRGB] = TextureFormatOGL(GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE); TextureFormats[(int32)PixelFormat::R8G8B8A8_UInt] = TextureFormatOGL(GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE); TextureFormats[(int32)PixelFormat::R8G8B8A8_SNorm] = TextureFormatOGL(GL_RGBA8_SNORM, GL_RGBA, GL_BYTE); TextureFormats[(int32)PixelFormat::R8G8B8A8_SInt] = TextureFormatOGL(GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE); TextureFormats[(int32)PixelFormat::R16G16_Typeless] = TextureFormatOGL(GL_RG16F, GL_RG, GL_HALF_FLOAT); TextureFormats[(int32)PixelFormat::R16G16_Float] = TextureFormatOGL(GL_RG16F, GL_RG, GL_HALF_FLOAT); TextureFormats[(int32)PixelFormat::R16G16_UNorm] = TextureFormatOGL(GL_RG16, GL_RG, GL_UNSIGNED_SHORT); TextureFormats[(int32)PixelFormat::R16G16_UInt] = TextureFormatOGL(GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT); TextureFormats[(int32)PixelFormat::R16G16_SNorm] = TextureFormatOGL(GL_RG16_SNORM, GL_RG, GL_SHORT); TextureFormats[(int32)PixelFormat::R16G16_SInt] = TextureFormatOGL(GL_RG16I, GL_RG_INTEGER, GL_SHORT); TextureFormats[(int32)PixelFormat::R32_Typeless] = TextureFormatOGL(GL_R32F, GL_RED, GL_FLOAT); TextureFormats[(int32)PixelFormat::D32_Float] = TextureFormatOGL(GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT); TextureFormats[(int32)PixelFormat::R32_Float] = TextureFormatOGL(GL_R32F, GL_RED, GL_FLOAT); TextureFormats[(int32)PixelFormat::R32_UInt] = TextureFormatOGL(GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT); TextureFormats[(int32)PixelFormat::R32_SInt] = TextureFormatOGL(GL_R32I, GL_RED_INTEGER, GL_INT); TextureFormats[(int32)PixelFormat::R24G8_Typeless] = TextureFormatOGL(GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8); TextureFormats[(int32)PixelFormat::D24_UNorm_S8_UInt] = TextureFormatOGL(GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8); TextureFormats[(int32)PixelFormat::R24_UNorm_X8_Typeless] = TextureFormatOGL(GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8); TextureFormats[(int32)PixelFormat::X24_Typeless_G8_UInt] = TextureFormatOGL(GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8); TextureFormats[(int32)PixelFormat::R8G8_Typeless] = TextureFormatOGL(GL_RG8, GL_RG, GL_UNSIGNED_BYTE); TextureFormats[(int32)PixelFormat::R8G8_UNorm] = TextureFormatOGL(GL_RG8, GL_RG, GL_UNSIGNED_BYTE); TextureFormats[(int32)PixelFormat::R8G8_UInt] = TextureFormatOGL(GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE); TextureFormats[(int32)PixelFormat::R8G8_SNorm] = TextureFormatOGL(GL_RG8_SNORM, GL_RG, GL_BYTE); TextureFormats[(int32)PixelFormat::R8G8_SInt] = TextureFormatOGL(GL_RG8I, GL_RG_INTEGER, GL_BYTE); TextureFormats[(int32)PixelFormat::R16_Typeless] = TextureFormatOGL(GL_R16F, GL_RED, GL_HALF_FLOAT); TextureFormats[(int32)PixelFormat::R16_Float] = TextureFormatOGL(GL_R16F, GL_RED, GL_HALF_FLOAT); TextureFormats[(int32)PixelFormat::D16_UNorm] = TextureFormatOGL(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT); TextureFormats[(int32)PixelFormat::R16_UNorm] = TextureFormatOGL(GL_R16, GL_RED, GL_UNSIGNED_SHORT); TextureFormats[(int32)PixelFormat::R16_UInt] = TextureFormatOGL(GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT); TextureFormats[(int32)PixelFormat::R16_SNorm] = TextureFormatOGL(GL_R16_SNORM, GL_RED, GL_SHORT); TextureFormats[(int32)PixelFormat::R16_SInt] = TextureFormatOGL(GL_R16I, GL_RED_INTEGER, GL_SHORT); TextureFormats[(int32)PixelFormat::R8_Typeless] = TextureFormatOGL(GL_R8, GL_RED, GL_UNSIGNED_BYTE); TextureFormats[(int32)PixelFormat::R8_UNorm] = TextureFormatOGL(GL_R8, GL_RED, GL_UNSIGNED_BYTE); TextureFormats[(int32)PixelFormat::R8_UInt] = TextureFormatOGL(GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE); TextureFormats[(int32)PixelFormat::R8_SNorm] = TextureFormatOGL(GL_R8_SNORM, GL_RED, GL_BYTE); TextureFormats[(int32)PixelFormat::R8_SInt] = TextureFormatOGL(GL_R8I, GL_RED_INTEGER, GL_BYTE); TextureFormats[(int32)PixelFormat::A8_UNorm] = TextureFormatOGL(); TextureFormats[(int32)PixelFormat::R1_UNorm] = TextureFormatOGL(); TextureFormats[(int32)PixelFormat::R9G9B9E5_SharedExp] = TextureFormatOGL(GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV); TextureFormats[(int32)PixelFormat::R8G8_B8G8_UNorm] = TextureFormatOGL(); TextureFormats[(int32)PixelFormat::G8R8_G8B8_UNorm] = TextureFormatOGL(); TextureFormats[(int32)PixelFormat::BC1_Typeless] = TextureFormatOGL(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC1_UNorm] = TextureFormatOGL(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC1_UNorm_sRGB] = TextureFormatOGL(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC2_Typeless] = TextureFormatOGL(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC2_UNorm] = TextureFormatOGL(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC2_UNorm_sRGB] = TextureFormatOGL(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC3_Typeless] = TextureFormatOGL(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC3_UNorm] = TextureFormatOGL(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC3_UNorm_sRGB] = TextureFormatOGL(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC4_Typeless] = TextureFormatOGL(GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC4_UNorm] = TextureFormatOGL(GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC4_SNorm] = TextureFormatOGL(GL_COMPRESSED_SIGNED_RED_RGTC1, GL_RED, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC5_Typeless] = TextureFormatOGL(GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC5_UNorm] = TextureFormatOGL(GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC5_SNorm] = TextureFormatOGL(GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::B5G6R5_UNorm] = TextureFormatOGL(GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV); TextureFormats[(int32)PixelFormat::B5G5R5A1_UNorm] = TextureFormatOGL(GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV); TextureFormats[(int32)PixelFormat::B8G8R8A8_UNorm] = TextureFormatOGL(); TextureFormats[(int32)PixelFormat::B8G8R8X8_UNorm] = TextureFormatOGL(); TextureFormats[(int32)PixelFormat::R10G10B10_Xr_Bias_A2_UNorm] = TextureFormatOGL(); TextureFormats[(int32)PixelFormat::B8G8R8A8_Typeless] = TextureFormatOGL(GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV); TextureFormats[(int32)PixelFormat::B8G8R8A8_UNorm_sRGB] = TextureFormatOGL(GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV); TextureFormats[(int32)PixelFormat::B8G8R8X8_Typeless] = TextureFormatOGL(GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV); TextureFormats[(int32)PixelFormat::B8G8R8X8_UNorm_sRGB] = TextureFormatOGL(GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV); TextureFormats[(int32)PixelFormat::BC6H_Typeless] = TextureFormatOGL(GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC6H_Uf16] = TextureFormatOGL(GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC6H_Sf16] = TextureFormatOGL(GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC7_Typeless] = TextureFormatOGL(GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGB, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC7_UNorm] = TextureFormatOGL(GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGB, GL_UNSIGNED_BYTE, true); TextureFormats[(int32)PixelFormat::BC7_UNorm_sRGB] = TextureFormatOGL(GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGB, GL_UNSIGNED_BYTE, true); // Check features for each PixelFormat for (int32 i = 0; i < static_cast(PixelFormat::Maximum); i++) { // TODO: try to detect MSAA or some feature levels like on D3D11 auto format = static_cast(i); auto& info = TextureFormats[i]; FormatSupport support = FormatSupport::None; if (info.Format != 0) { support = FormatSupport::Texture1D | FormatSupport::Texture2D | FormatSupport::Texture3D | FormatSupport::DepthStencil | FormatSupport::Buffer; } _featuresPerFormat[i] = FeaturesPerFormat(format, MSAALevel::None, support); } } #if BUILD_DEBUG void PrintStats() { #define PRINT_STAT(name) sb.AppendFormat(TEXT("{0} = {1}\n"), TEXT(#name), name) StringBuilder sb; sb.AppendLine(); sb.AppendLine(); auto adapter = (AdapterOGL*)_device->GetAdapter(); sb.AppendFormat(TEXT("OpenGL {0}.{1}\n"), adapter->VersionMajor, adapter->VersionMinor); sb.AppendLine(); PRINT_STAT(SupportsTessellation); PRINT_STAT(SupportsGPUMemoryInfo); PRINT_STAT(SupportsComputeShaders); PRINT_STAT(SupportsVertexAttribBinding); PRINT_STAT(SupportsTextureView); PRINT_STAT(SupportsVolumeTextureRendering); PRINT_STAT(SupportsASTC); PRINT_STAT(SupportsCopyImage); PRINT_STAT(SupportsSeamlessCubemap); PRINT_STAT(SupportsTextureFilterAnisotropic); PRINT_STAT(SupportsDrawBuffersBlend); PRINT_STAT(SupportsSeparateShaderObjects); PRINT_STAT(SupportsClipControl); sb.AppendLine(); PRINT_STAT(VideoMemorySize); PRINT_STAT(MaxTextureMipCount); PRINT_STAT(MaxTextureSize); PRINT_STAT(MaxCubeTextureSize); PRINT_STAT(MaxVolumeTextureSize); PRINT_STAT(MaxTextureArraySize); PRINT_STAT(MaxOpenGLDrawBuffers); PRINT_STAT(MaxTextureImageUnits); PRINT_STAT(MaxCombinedTextureImageUnits); PRINT_STAT(MaxVertexTextureImageUnits); PRINT_STAT(MaxGeometryTextureImageUnits); PRINT_STAT(MaxHullTextureImageUnits); PRINT_STAT(MaxDomainTextureImageUnits); PRINT_STAT(MaxVaryingVectors); PRINT_STAT(MaxVertexUniformComponents); PRINT_STAT(MaxPixelUniformComponents); PRINT_STAT(MaxGeometryUniformComponents); PRINT_STAT(MaxHullUniformComponents); PRINT_STAT(MaxDomainUniformComponents); PRINT_STAT(MaxComputeTextureImageUnits); PRINT_STAT(MaxComputeUniformComponents); sb.AppendLine(); LOG_STR(Info, sb.ToString()); #undef PRINT_STAT } #endif public: // [GPULimits] bool Init() override { auto adapter = (AdapterOGL*)_device->GetAdapter(); auto VersionMajor = adapter->VersionMajor; auto VersionMinor = adapter->VersionMinor; // Test graphics pipeline features support SupportsTessellation = (VersionMajor >= 4) || adapter->HasExtension("GL_ARB_tessellation_shader"); SupportsGPUMemoryInfo = adapter->HasExtension("GL_NVX_gpu_memory_info"); SupportsComputeShaders = (VersionMajor == 4 && VersionMinor >= 3) || (VersionMajor > 4) || adapter->HasExtension("GL_ARB_compute_shader"); SupportsVertexAttribBinding = (VersionMajor == 4 && VersionMinor >= 3) || (VersionMajor > 4) || adapter->HasExtension("GL_ARB_vertex_attrib_binding"); SupportsTextureView = (VersionMajor == 4 && VersionMinor >= 3) || (VersionMajor > 4) || adapter->HasExtension("GL_ARB_texture_view"); SupportsASTC = adapter->HasExtension("GL_KHR_texture_compression_astc_ldr"); SupportsCopyImage = adapter->HasExtension("GL_ARB_copy_image"); SupportsSeamlessCubemap = adapter->HasExtension("GL_ARB_seamless_cube_map"); SupportsTextureFilterAnisotropic = adapter->HasExtension("GL_EXT_texture_filter_anisotropic"); SupportsDrawBuffersBlend = adapter->HasExtension("GL_ARB_draw_buffers_blend"); SupportsClipControl = adapter->HasExtension("GL_ARB_clip_control"); #if GRAPHICS_API_OPENGL_ES SupportsSeparateShaderObjects = false; #else SupportsSeparateShaderObjects = (VersionMajor == 4 && VersionMinor >= 4) || adapter->HasExtension("GL_ARB_separate_shader_objects"); #endif // Get video memory size (in bytes) VideoMemorySize = 0; if (SupportsGPUMemoryInfo) { GLint VMSizeKB = 0; glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &VMSizeKB); VideoMemorySize = VMSizeKB * 1024ll; } // Test whether the GPU can support volume-texture rendering. // There is no API to query this - you just have to test whether a 3D texture is framebuffer-complete. { GLuint frameBuffer; glGenFramebuffers(1, &frameBuffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer); GLuint volumeTexture; glGenTextures(1, &volumeTexture); glBindTexture(GL_TEXTURE_3D, volumeTexture); glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 256, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, volumeTexture, 0); SupportsVolumeTextureRendering = (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); glDeleteTextures(1, &volumeTexture); glDeleteFramebuffers(1, &frameBuffer); } // Get the device limits with OpenGL API #define LOG_AND_GET_GL_INT_TEMP(IntEnum, Default) GLint Value_##IntEnum = Default; if (IntEnum) {glGetIntegerv(IntEnum, &Value_##IntEnum); glGetError();} else {Value_##IntEnum = Default;} LOG_AND_GET_GL_INT_TEMP(GL_MAX_TEXTURE_SIZE, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_CUBE_MAP_TEXTURE_SIZE, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_ARRAY_TEXTURE_LAYERS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_3D_TEXTURE_SIZE, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_RENDERBUFFER_SIZE, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_TEXTURE_IMAGE_UNITS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_DRAW_BUFFERS, 1); LOG_AND_GET_GL_INT_TEMP(GL_MAX_COLOR_ATTACHMENTS, 1); LOG_AND_GET_GL_INT_TEMP(GL_MAX_SAMPLES, 1); LOG_AND_GET_GL_INT_TEMP(GL_MAX_COLOR_TEXTURE_SAMPLES, 1); LOG_AND_GET_GL_INT_TEMP(GL_MAX_DEPTH_TEXTURE_SAMPLES, 1); LOG_AND_GET_GL_INT_TEMP(GL_MAX_INTEGER_SAMPLES, 1); LOG_AND_GET_GL_INT_TEMP(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_VERTEX_ATTRIBS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_VERTEX_UNIFORM_COMPONENTS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_VARYING_VECTORS, 0); // Setup the actual limits MaxTextureSize = Value_GL_MAX_TEXTURE_SIZE; MaxTextureMipCount = Math::Min(GPU_MAX_TEXTURE_MIP_LEVELS, MipLevelsCount(MaxTextureSize)); MaxCubeTextureSize = Value_GL_MAX_CUBE_MAP_TEXTURE_SIZE; MaxTextureArraySize = Value_GL_MAX_ARRAY_TEXTURE_LAYERS; MaxVolumeTextureSize = MaxCubeTextureSize; MaxOpenGLDrawBuffers = Value_GL_MAX_DRAW_BUFFERS; MaxTextureImageUnits = Value_GL_MAX_TEXTURE_IMAGE_UNITS; MaxCombinedTextureImageUnits = Value_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS; MaxVertexTextureImageUnits = Value_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS; MaxGeometryTextureImageUnits = Value_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS; MaxHullTextureImageUnits = Value_GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS; MaxDomainTextureImageUnits = Value_GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS; MaxVaryingVectors = Value_GL_MAX_VARYING_VECTORS; MaxVertexUniformComponents = Value_GL_MAX_VERTEX_UNIFORM_COMPONENTS; MaxPixelUniformComponents = Value_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS; MaxGeometryUniformComponents = Value_GL_MAX_GEOMETRY_UNIFORM_COMPONENTS; if (SupportsTessellation) { LOG_AND_GET_GL_INT_TEMP(GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS, 0); MaxHullUniformComponents = Value_GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS; MaxDomainUniformComponents = Value_GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS; } else { MaxHullUniformComponents = 0; MaxDomainUniformComponents = 0; } if (SupportsComputeShaders) { LOG_AND_GET_GL_INT_TEMP(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, 0); LOG_AND_GET_GL_INT_TEMP(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, 0); MaxComputeTextureImageUnits = Value_GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS; MaxComputeUniformComponents = Value_GL_MAX_COMPUTE_UNIFORM_COMPONENTS; } else { MaxComputeTextureImageUnits = 0; MaxComputeUniformComponents = 0; } // For now, just allocate additional units if available and advertise no tessellation units for HW that can't handle more if (MaxCombinedTextureImageUnits < 48) { // To work around AMD driver limitation of 32 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, // Going to hard code this for now (16 units in PS, 8 units in VS, 8 units in GS). // This is going to be a problem for tessellation. MaxTextureImageUnits = MaxTextureImageUnits > 16 ? 16 : MaxTextureImageUnits; MaxVertexTextureImageUnits = MaxVertexTextureImageUnits > 8 ? 8 : MaxVertexTextureImageUnits; MaxGeometryTextureImageUnits = MaxGeometryTextureImageUnits > 8 ? 8 : MaxGeometryTextureImageUnits; MaxHullTextureImageUnits = 0; MaxDomainTextureImageUnits = 0; MaxCombinedTextureImageUnits = MaxCombinedTextureImageUnits > 32 ? 32 : MaxCombinedTextureImageUnits; } else { // Clamp things to the levels that the other path is going, but allow additional units for tessellation MaxTextureImageUnits = MaxTextureImageUnits > 16 ? 16 : MaxTextureImageUnits; MaxVertexTextureImageUnits = MaxVertexTextureImageUnits > 8 ? 8 : MaxVertexTextureImageUnits; MaxGeometryTextureImageUnits = MaxGeometryTextureImageUnits > 8 ? 8 : MaxGeometryTextureImageUnits; MaxHullTextureImageUnits = MaxHullTextureImageUnits > 8 ? 8 : MaxHullTextureImageUnits; MaxDomainTextureImageUnits = MaxDomainTextureImageUnits > 8 ? 8 : MaxDomainTextureImageUnits; MaxCombinedTextureImageUnits = MaxCombinedTextureImageUnits > 48 ? 48 : MaxCombinedTextureImageUnits; } InitFormats(); #if BUILD_DEBUG PrintStats(); #endif // Validate minimum specs for the engine to start if (!SupportsTextureView) { LOG(Error, "The GPU does not meet minimal requirements."); return true; } return false; } bool HasCompute() const override { return SupportsComputeShaders; } bool HasTessellation() const override { return SupportsTessellation; } bool HasGeometryShaders() const override { #if GRAPHICS_API_OPENGLES return false; #else return true; #endif } bool HasVolumeTextureRendering() const override { return SupportsVolumeTextureRendering; } bool HasDrawIndirect() const override { return false; } bool HasAppendConsumeBuffers() const override { return false; } bool HasSeparateRenderTargetBlendState() const override { return false; } bool HasDepthAsSRV() const override { return true; } bool HasMultisampleDepthAsSRV() const override { return true; } int32 MaximumMipLevelsCount() const override { return MaxTextureMipCount; } int32 MaximumTexture1DSize() const override { return MaxTextureSize; } int32 MaximumTexture1DArraySize() const override { return MaxTextureArraySize; } int32 MaximumTexture2DSize() const override { return MaxTextureSize; } int32 MaximumTexture2DArraySize() const override { return MaxTextureArraySize; } int32 MaximumTexture3DSize() const override { return MaxVolumeTextureSize; } int32 MaximumTextureCubeSize() const override { return MaxCubeTextureSize; } }; #endif