diff --git a/include/LLGL/LLGL.h b/include/LLGL/LLGL.h index d46313d14c..7399abc757 100644 --- a/include/LLGL/LLGL.h +++ b/include/LLGL/LLGL.h @@ -36,7 +36,7 @@ * Overview * -------- * - * - **Version**: 0.03 Beta + * - **Version**: 0.04 Beta * - **License**: [3-Clause BSD License](https://github.com/LukasBanana/LLGL/blob/master/LICENSE.txt) * * diff --git a/include/LLGL/RenderSystem.h b/include/LLGL/RenderSystem.h index 3e96e0fe36..a979636272 100644 --- a/include/LLGL/RenderSystem.h +++ b/include/LLGL/RenderSystem.h @@ -166,7 +166,6 @@ class LLGL_EXPORT RenderSystem : public Interface } LLGL::RenderSystemPtr myRenderSystem = LLGL::RenderSystem::Load(myRendererDesc); \endcode - \throws std::runtime_error If loading the render system from the specified module failed. \see RenderSystemDescriptor::moduleName */ static RenderSystemPtr Load(const RenderSystemDescriptor& renderSystemDesc, Report* report = nullptr); @@ -411,7 +410,7 @@ class LLGL_EXPORT RenderSystem : public Interface /** \brief Creates a new Sampler object. - \throws std::runtime_error If the renderer does not support Sampler objects (e.g. if OpenGL 3.1 or lower is used). + \remarks Samplers (aka. sampler states) define how to sample texture resources in shaders. \see GetRenderingCaps */ virtual Sampler* CreateSampler(const SamplerDescriptor& samplerDesc) = 0; @@ -475,7 +474,7 @@ class LLGL_EXPORT RenderSystem : public Interface /** \brief Creates a new RenderTarget object. - \throws std::runtime_error If the renderer does not support RenderTarget objects (e.g. if OpenGL 2.1 or lower is used). + \remarks Use render targets to render into a texture instead of a swap-chain (i.e. the screen). */ virtual RenderTarget* CreateRenderTarget(const RenderTargetDescriptor& renderTargetDesc) = 0; diff --git a/sources/Core/Exception.cpp b/sources/Core/Exception.cpp index b7e5d95481..234a915919 100644 --- a/sources/Core/Exception.cpp +++ b/sources/Core/Exception.cpp @@ -14,6 +14,11 @@ #include #include +#include +#ifdef LLGL_OS_ANDROID +# include +#endif + namespace LLGL { @@ -43,7 +48,7 @@ LLGL_EXPORT void Trap(const char* origin, const char* format, ...) /* Throw exception with report and optional origin */ throw std::runtime_error(report); - #else + #else // LLGL_ENABLE_EXCEPTIONS # ifdef LLGL_DEBUG @@ -55,17 +60,26 @@ LLGL_EXPORT void Trap(const char* origin, const char* format, ...) /* Break execution if there's a debugger attached */ LLGL_DEBUG_BREAK(); - # else + # else // LLGL_DEBUG + + # ifdef LLGL_OS_ANDROID + + /* Print report to Android specific error log */ + (void)__android_log_print(ANDROID_LOG_ERROR, "LLGL", "%s\n", report.c_str()); + + # else /* Print report to standard error output */ ::fprintf(stderr, "%s\n", report.c_str()); - # endif + # endif + + # endif // /LLGL_DEBUG /* Abort execution as LLGL is trapped in an unrecoverable state */ ::abort(); - #endif + #endif // /LLGL_ENABLE_EXCEPTIONS } [[noreturn]] diff --git a/sources/Core/Exception.h b/sources/Core/Exception.h index 5b9ec7d55a..de07a50570 100644 --- a/sources/Core/Exception.h +++ b/sources/Core/Exception.h @@ -39,43 +39,43 @@ class Report; [[noreturn]] LLGL_EXPORT void Trap(const char* origin, const char* format, ...); -// Throws an std::runtime_error exception with the message, that the specified assertion that failed. +// Traps program execution with the message that the specified assertion that failed. [[noreturn]] LLGL_EXPORT void TrapAssertionFailed(const char* origin, const char* expr, const char* details = nullptr, ...); -// Throws an std::runtime_error exception with the message, that the specified feature is not supported. +// Traps program execution with the message that the specified feature is not supported. [[noreturn]] LLGL_EXPORT void TrapFeatureNotSupported(const char* origin, const char* featureName); -// Throws an std::runtime_error exception with the message, that the specified rendering feature is not supported by the renderer (see RenderingFeatures). +// Traps program execution with the message that the specified rendering feature is not supported by the renderer (see RenderingFeatures). [[noreturn]] LLGL_EXPORT void TrapRenderingFeatureNotSupported(const char* origin, const char* featureName); -// Throws an std::runtime_error exception with the message, that the specified OpenGL extension is not supported. +// Traps program execution with the message that the specified OpenGL extension is not supported. [[noreturn]] LLGL_EXPORT void TrapGLExtensionNotSupported(const char* origin, const char* extensionName, const char* useCase = nullptr); -// Throws an std::runtime_error exception with the message, that the specified Vulkan extension is not supported. +// Traps program execution with the message that the specified Vulkan extension is not supported. [[noreturn]] LLGL_EXPORT void TrapVKExtensionNotSupported(const char* origin, const char* extensionName, const char* useCase = nullptr); -// Throws an std::runtime_error exception with the message, that the specified interface function is not implemented yet. +// Traps program execution with the message that the specified interface function is not implemented yet. [[noreturn]] LLGL_EXPORT void TrapNotImplemented(const char* origin, const char* useCase = nullptr); -// Throws an std::runtime_error exception with the message, that a null pointer was passed. +// Traps program execution with the message that a null pointer was passed. [[noreturn]] LLGL_EXPORT void TrapNullPointer(const char* origin, const char* expr); -// Throws an std::runtime_error exception with the message, that a value has exceeded an upper bound, i.e. is not in the half-open range [0, upperBound). +// Traps program execution with the message that a value has exceeded an upper bound, i.e. is not in the half-open range [0, upperBound). [[noreturn]] LLGL_EXPORT void TrapParamExceededUpperBound(const char* origin, const char* paramName, int value, int upperBound); -// Throws an std::runtime_error exception with the message, that a value has exceeded its maximum, i.e. is not in the closed range [0, maximum]. +// Traps program execution with the message that a value has exceeded its maximum, i.e. is not in the closed range [0, maximum]. [[noreturn]] LLGL_EXPORT void TrapParamExceededMaximum(const char* origin, const char* paramName, int value, int maximum); -// THrows an std::runtime_error exception with the message from the specified report, cutting off any trailing new-line characters. +// Traps program execution with the message from the specified report, cutting off any trailing new-line characters. [[noreturn]] LLGL_EXPORT void TrapReport(const char* origin, const Report& report); diff --git a/sources/Renderer/CheckedCast.h b/sources/Renderer/CheckedCast.h index a48d24eb0a..f01f357c34 100644 --- a/sources/Renderer/CheckedCast.h +++ b/sources/Renderer/CheckedCast.h @@ -11,8 +11,13 @@ #include "../Platform/Debug.h" -#ifdef LLGL_ENABLE_CHECKED_CAST -# include +#if LLGL_ENABLE_CHECKED_CAST +# if LLGL_ENABLE_EXCEPTIONS +# include +# else +# include +# include "../Core/Assertion.h" +# endif #endif @@ -20,11 +25,13 @@ namespace LLGL { -#ifdef LLGL_ENABLE_CHECKED_CAST +#if LLGL_ENABLE_CHECKED_CAST template inline TDst& ObjectCast(TSrc& obj) { + #if LLGL_ENABLE_EXCEPTIONS + try { return dynamic_cast(obj); @@ -34,6 +41,12 @@ inline TDst& ObjectCast(TSrc& obj) LLGL_DEBUG_BREAK(); throw; } + + #else // LLGL_ENABLE_EXCEPTIONS + + return dynamic_cast(obj); + + #endif } template @@ -41,6 +54,9 @@ inline TDst ObjectCast(TSrc* obj) { if (obj == nullptr) return nullptr; + + #if LLGL_ENABLE_EXCEPTIONS + try { TDst objInstance = dynamic_cast(obj); @@ -53,9 +69,17 @@ inline TDst ObjectCast(TSrc* obj) LLGL_DEBUG_BREAK(); throw; } + + #else // LLGL_ENABLE_EXCEPTIONS + + TDst objInstance = dynamic_cast(obj); + LLGL_ASSERT(objInstance != nullptr); + return objInstance; + + #endif // /LLGL_ENABLE_EXCEPTIONS } -#else +#else // LLGL_ENABLE_CHECKED_CAST template inline TDst ObjectCast(TSrc&& obj) @@ -63,9 +87,10 @@ inline TDst ObjectCast(TSrc&& obj) return static_cast(obj); } -#endif +#endif // /LLGL_ENABLE_CHECKED_CAST -#define LLGL_CAST(TYPE, OBJ) ObjectCast(OBJ) +#define LLGL_CAST(TYPE, OBJ) \ + ObjectCast(OBJ) } // /namespace LLGL diff --git a/sources/Renderer/Direct3D11/RenderState/D3D11ResourceHeap.cpp b/sources/Renderer/Direct3D11/RenderState/D3D11ResourceHeap.cpp index d07eb7ae3f..b9fdde100b 100644 --- a/sources/Renderer/Direct3D11/RenderState/D3D11ResourceHeap.cpp +++ b/sources/Renderer/Direct3D11/RenderState/D3D11ResourceHeap.cpp @@ -21,6 +21,7 @@ #include "../../BufferUtils.h" #include "../../StaticAssertions.h" #include "../../../Core/CoreUtils.h" +#include "../../../Core/Assertion.h" #include #include #include @@ -118,7 +119,7 @@ D3D11ResourceHeap::D3D11ResourceHeap( /* Get pipeline layout object */ auto* pipelineLayoutD3D = LLGL_CAST(D3D11PipelineLayout*, desc.pipelineLayout); if (!pipelineLayoutD3D) - throw std::invalid_argument("failed to create resource heap due to missing pipeline layout"); + LLGL_TRAP("failed to create resource heap due to missing pipeline layout"); /* Get and validate number of bindings and resource views */ const auto& bindings = pipelineLayoutD3D->GetHeapBindings(); @@ -1058,8 +1059,7 @@ static UINT GetFormatBufferStride(const Format format) /* Get buffer stride by format */ const FormatAttributes& formatAttribs = GetFormatAttribs(format); const UINT stride = (formatAttribs.bitSize / formatAttribs.blockWidth / formatAttribs.blockHeight / 8); - if (stride == 0) - throw std::runtime_error("cannot create buffer subresource with format stride of 0"); + LLGL_ASSERT(stride > 0, "cannot create buffer subresource with format stride of 0"); return stride; } diff --git a/sources/Renderer/Direct3D11/Shader/D3D11Shader.cpp b/sources/Renderer/Direct3D11/Shader/D3D11Shader.cpp index 5c80eab001..1b0f354ddb 100644 --- a/sources/Renderer/Direct3D11/Shader/D3D11Shader.cpp +++ b/sources/Renderer/Direct3D11/Shader/D3D11Shader.cpp @@ -13,10 +13,10 @@ #include "../../../Core/CoreUtils.h" #include "../../../Core/StringUtils.h" #include "../../../Core/ReportUtils.h" +#include "../../../Core/Assertion.h" #include #include #include -#include #include @@ -89,24 +89,12 @@ bool D3D11Shader::BuildShader(ID3D11Device* device, const ShaderDescriptor& shad return LoadBinary(device, shaderDesc); } -static DXGI_FORMAT GetInputElementFormat(const VertexAttribute& attrib) -{ - try - { - return DXTypes::ToDXGIFormat(attrib.format); - } - catch (const std::exception& e) - { - throw std::invalid_argument(std::string(e.what()) + " for vertex attribute: " + std::string(attrib.name.c_str())); - } -} - // Converts a vertex attribute to a D3D input element descriptor static void ConvertInputElementDesc(D3D11_INPUT_ELEMENT_DESC& dst, const VertexAttribute& src) { dst.SemanticName = src.name.c_str(); dst.SemanticIndex = src.semanticIndex; - dst.Format = GetInputElementFormat(src); + dst.Format = DXTypes::ToDXGIFormat(src.format); dst.InputSlot = src.slot; dst.AlignedByteOffset = src.offset; dst.InputSlotClass = (src.instanceDivisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA); @@ -130,8 +118,7 @@ void D3D11Shader::BuildInputLayout(ID3D11Device* device, UINT numVertexAttribs, return; /* Check if input layout is allowed */ - if (GetType() != ShaderType::Vertex) - throw std::runtime_error("cannot build input layout for shader unless it is a vertex shader"); + LLGL_ASSERT(GetType() == ShaderType::Vertex, "cannot build input layout for non-vertex-shader"); /* Setup input element descriptors */ std::vector inputElements; diff --git a/sources/Renderer/Direct3D12/RenderState/D3D12ComputePSO.cpp b/sources/Renderer/Direct3D12/RenderState/D3D12ComputePSO.cpp index 15ed90eca8..35d8c3f0c3 100644 --- a/sources/Renderer/Direct3D12/RenderState/D3D12ComputePSO.cpp +++ b/sources/Renderer/Direct3D12/RenderState/D3D12ComputePSO.cpp @@ -14,7 +14,6 @@ #include "../../DXCommon/DXCore.h" #include "../../CheckedCast.h" #include "../../PipelineStateUtils.h" -#include "../../../Core/Assertion.h" #include @@ -32,7 +31,10 @@ D3D12ComputePSO::D3D12ComputePSO( { auto* computeShaderD3D = LLGL_CAST(const D3D12Shader*, desc.computeShader); if (computeShaderD3D == nullptr) - throw std::runtime_error("cannot create D3D compute pipeline without compute shader"); + { + ResetReport("cannot create D3D compute PSO without compute shader", true); + return; + } /* Create native compute PSO */ if (pipelineCache != nullptr) diff --git a/sources/Renderer/OpenGL/GLCore.h b/sources/Renderer/OpenGL/GLCore.h index efcec5cfc9..3699c56203 100644 --- a/sources/Renderer/OpenGL/GLCore.h +++ b/sources/Renderer/OpenGL/GLCore.h @@ -17,7 +17,7 @@ namespace LLGL { -// Throws an std::runtime_error exception if 'status' is not equal to 'statusRequired'. +// Traps program execution if 'status' is not equal to 'statusRequired'. void GLThrowIfFailed(const GLenum status, const GLenum statusRequired, const char* info = nullptr); // Converts the GL debug source into a string. @@ -38,7 +38,7 @@ bool GLParseVersionString(const GLubyte* s, GLint& major, GLint& minor); // Returns the GL profile version as a single number, e.g. 450 for OpenGL 4.5. int GLGetVersion(); -// Throws an std::runtime_error exception reporting a call to an unsupported OpenGL procedure. +// Traps program execution reporting a call to an unsupported OpenGL procedure. [[noreturn]] void ErrUnsupportedGLProc(const char* name); diff --git a/sources/Renderer/OpenGL/RenderState/GLQueryHeap.cpp b/sources/Renderer/OpenGL/RenderState/GLQueryHeap.cpp index 7c5f9207a1..83c658297c 100644 --- a/sources/Renderer/OpenGL/RenderState/GLQueryHeap.cpp +++ b/sources/Renderer/OpenGL/RenderState/GLQueryHeap.cpp @@ -69,7 +69,7 @@ GLQueryHeap::GLQueryHeap(const QueryHeapDescriptor& desc) : #ifdef GL_ARB_pipeline_statistics_query if (desc.type == QueryType::PipelineStatistics) { - /* Allocate IDs for all pipeline statistics queries or throw error on failure */ + /* Allocate IDs for all pipeline statistics queries or trap program execution on failure */ LLGL_ASSERT_GL_EXT(ARB_pipeline_statistics_query); groupSize_ = static_cast(sizeof(QueryPipelineStatistics) / sizeof(std::uint64_t)); } diff --git a/sources/Renderer/OpenGL/RenderState/GLRasterizerState.cpp b/sources/Renderer/OpenGL/RenderState/GLRasterizerState.cpp index a14e23eaaf..f9a9594ae4 100644 --- a/sources/Renderer/OpenGL/RenderState/GLRasterizerState.cpp +++ b/sources/Renderer/OpenGL/RenderState/GLRasterizerState.cpp @@ -11,6 +11,7 @@ #include "../GLCore.h" #include "../GLTypes.h" #include "../../../Core/MacroUtils.h" +#include "../../../Core/Exception.h" #include "GLStateManager.h" #include @@ -32,7 +33,7 @@ static GLState ToPolygonOffsetState(const PolygonMode mode) case PolygonMode::Points: break; #endif } - throw std::invalid_argument("failed to map 'PolygonMode' to polygon offset mode (GL_POLYGON_OFFSET_FILL, GL_POLYGON_OFFSET_LINE, or GL_POLYGON_OFFSET_POINT)"); + LLGL_TRAP("failed to map LLGL::PolygonMode(%d) to polygon offset mode (GL_POLYGON_OFFSET_FILL, GL_POLYGON_OFFSET_LINE, or GL_POLYGON_OFFSET_POINT)", static_cast(mode)); } static bool IsPolygonOffsetEnabled(const DepthBiasDescriptor& desc) diff --git a/sources/Renderer/OpenGL/Texture/GLTexImage.cpp b/sources/Renderer/OpenGL/Texture/GLTexImage.cpp index d46f0b0c15..237d0b7028 100644 --- a/sources/Renderer/OpenGL/Texture/GLTexImage.cpp +++ b/sources/Renderer/OpenGL/Texture/GLTexImage.cpp @@ -10,6 +10,7 @@ #include "../Profile/GLProfile.h" #include "../Ext/GLExtensions.h" #include "../Ext/GLExtensionRegistry.h" +#include "../../../Core/Exception.h" #include #include #include @@ -74,7 +75,7 @@ static GLenum GetDefaultInitialGLImageFormat(Format format) [[noreturn]] static void ErrIllegalUseOfDepthFormat() { - throw std::runtime_error("illegal use of depth-stencil format for texture"); + LLGL_TRAP("illegal use of depth-stencil format for texture"); } // Converts the internal format if necessary diff --git a/sources/Renderer/SPIRV/SpirvReflect.cpp b/sources/Renderer/SPIRV/SpirvReflect.cpp index 29d79c6d54..5725ddc0e6 100644 --- a/sources/Renderer/SPIRV/SpirvReflect.cpp +++ b/sources/Renderer/SPIRV/SpirvReflect.cpp @@ -8,6 +8,7 @@ #include "SpirvReflect.h" #include "SpirvModule.h" #include "../../Core/CoreUtils.h" +#include "../../Core/Assertion.h" #include @@ -640,16 +641,14 @@ void SpirvReflect::OpTypeFunction(const Instr& instr, SpvType& type) const SpirvReflect::SpvType* SpirvReflect::FindType(spv::Id id) const { auto it = types_.find(id); - if (it == types_.end()) - throw std::runtime_error("cannot find SPIR-V OpType* instruction with result ID %" + std::to_string(id)); + LLGL_ASSERT(it != types_.end(), "cannot find SPIR-V OpType* instruction with result ID %%%u", id); return &(it->second); } const SpirvReflect::SpvConstant* SpirvReflect::FindConstant(spv::Id id) const { auto it = constants_.find(id); - if (it == constants_.end()) - throw std::runtime_error("cannot find SPIR-V OpConstant instruction with with result ID %" + std::to_string(id)); + LLGL_ASSERT(it != constants_.end(), "cannot find SPIR-V OpConstant instruction with with result ID %%%u", id); return &(it->second); } diff --git a/sources/Renderer/Vulkan/Buffer/VKDeviceBuffer.cpp b/sources/Renderer/Vulkan/Buffer/VKDeviceBuffer.cpp index 6f95123399..4a3fe290a8 100644 --- a/sources/Renderer/Vulkan/Buffer/VKDeviceBuffer.cpp +++ b/sources/Renderer/Vulkan/Buffer/VKDeviceBuffer.cpp @@ -8,6 +8,8 @@ #include "VKDeviceBuffer.h" #include "../Memory/VKDeviceMemoryManager.h" #include "../VKCore.h" +#include "../../../Core/PrintfUtils.h" +#include "../../../Core/Assertion.h" #include @@ -75,7 +77,7 @@ void VKDeviceBuffer::CreateVkBufferAndMemoryRegion( /* Create Vulkan bnuffer object */ CreateVkBuffer(device, createInfo); - if (auto memoryRegion = deviceMemoryMngr.Allocate(requirements_, memoryProperties)) + if (VKDeviceMemoryRegion* memoryRegion = deviceMemoryMngr.Allocate(requirements_, memoryProperties)) { /* Bind allocated memory region to buffer */ BindMemoryRegion(device, memoryRegion); @@ -83,10 +85,7 @@ void VKDeviceBuffer::CreateVkBufferAndMemoryRegion( else { /* Failed to allocate device memory */ - throw std::runtime_error( - "failed to allocate " + std::to_string(requirements_.size) + - " byte(s) of device memory for Vulkan buffer" - ); + LLGL_TRAP("failed to allocate %" PRIu64 " byte(s) of device memory for Vulkan buffer", requirements_.size); } } diff --git a/sources/Renderer/Vulkan/Texture/VKDepthStencilBuffer.cpp b/sources/Renderer/Vulkan/Texture/VKDepthStencilBuffer.cpp index c8cdbcc4c9..8c0017f341 100644 --- a/sources/Renderer/Vulkan/Texture/VKDepthStencilBuffer.cpp +++ b/sources/Renderer/Vulkan/Texture/VKDepthStencilBuffer.cpp @@ -42,8 +42,7 @@ void VKDepthStencilBuffer::Create( { /* Determine image aspect */ const VkImageAspectFlags aspectFlags = GetVkImageAspectByFormat(format); - if (!aspectFlags) - throw std::invalid_argument("invalid format for Vulkan depth-stencil buffer"); + LLGL_ASSERT(aspectFlags != 0, "invalid format (%d) for Vulkan depth-stencil buffer", static_cast(format)); /* Create depth-stencil image */ VKRenderBuffer::Create( diff --git a/sources/Renderer/Vulkan/VKCore.h b/sources/Renderer/Vulkan/VKCore.h index 9060af9a85..bcf4de0499 100644 --- a/sources/Renderer/Vulkan/VKCore.h +++ b/sources/Renderer/Vulkan/VKCore.h @@ -60,10 +60,10 @@ struct SurfaceSupportDetails /* ----- Basic Functions ----- */ -// Throws an std::runtime_error exception if 'result' is not VK_SUCCESS. +// Traps program execution if 'result' is not VK_SUCCESS. void VKThrowIfFailed(const VkResult result, const char* details); -// Throws an std::runtime_error exception if 'result' is not VK_SUCCESS, with an info about the failed interface creation. +// Traps program execution if 'result' is not VK_SUCCESS, with an info about the failed interface creation. void VKThrowIfCreateFailed(const VkResult result, const char* interfaceName, const char* contextInfo = nullptr); // Converts the specified Vulkan API version into a string (e.g. "1.0.100"). @@ -86,7 +86,7 @@ SurfaceSupportDetails VKQuerySurfaceSupport(VkPhysicalDevice device, VkSurfaceKH QueueFamilyIndices VKFindQueueFamilies(VkPhysicalDevice device, const VkQueueFlags flags, VkSurfaceKHR* surface = nullptr); VkFormat VKFindSupportedImageFormat(VkPhysicalDevice device, const VkFormat* candidates, std::size_t numCandidates, VkImageTiling tiling, VkFormatFeatureFlags features); -// Returns the memory type index that supports the specified type bits and properties, or throws an std::runtime_error exception on failure. +// Returns the memory type index that supports the specified type bits and properties, or traps program execution on failure. std::uint32_t VKFindMemoryType(const VkPhysicalDeviceMemoryProperties& memoryProperties, std::uint32_t memoryTypeBits, VkMemoryPropertyFlags properties);