mirror of https://github.com/mosra/magnum.git
Browse Source
Took me a while (several years?) to figure out a way to benchmark this without basically duplicating the testing effort and without new variants being too hard to add.pull/518/head
10 changed files with 827 additions and 7 deletions
Binary file not shown.
@ -0,0 +1,800 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||
2020, 2021 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
#include <Corrade/PluginManager/Manager.h> |
||||
#include <Corrade/Utility/Directory.h> |
||||
#include <Corrade/Utility/FormatStl.h> |
||||
|
||||
#include "Magnum/Image.h" |
||||
#include "Magnum/ImageView.h" |
||||
#include "Magnum/PixelFormat.h" |
||||
#include "Magnum/DebugTools/CompareImage.h" |
||||
#include "Magnum/GL/Extensions.h" |
||||
#include "Magnum/GL/Framebuffer.h" |
||||
#include "Magnum/GL/Mesh.h" |
||||
#include "Magnum/GL/OpenGLTester.h" |
||||
#include "Magnum/GL/Renderbuffer.h" |
||||
#include "Magnum/GL/RenderbufferFormat.h" |
||||
#include "Magnum/GL/Texture.h" |
||||
#include "Magnum/GL/TextureFormat.h" |
||||
#include "Magnum/Math/Color.h" |
||||
#include "Magnum/Math/Matrix4.h" |
||||
#include "Magnum/MeshTools/Compile.h" |
||||
#include "Magnum/MeshTools/Duplicate.h" |
||||
#include "Magnum/MeshTools/Interleave.h" |
||||
#include "Magnum/Primitives/Grid.h" |
||||
#include "Magnum/Shaders/DistanceFieldVectorGL.h" |
||||
#include "Magnum/Shaders/FlatGL.h" |
||||
#include "Magnum/Shaders/MeshVisualizerGL.h" |
||||
#include "Magnum/Shaders/PhongGL.h" |
||||
#include "Magnum/Shaders/VertexColorGL.h" |
||||
#include "Magnum/Shaders/VectorGL.h" |
||||
#include "Magnum/Trade/AbstractImporter.h" |
||||
#include "Magnum/Trade/MeshData.h" |
||||
|
||||
#include "configure.h" |
||||
|
||||
namespace Magnum { namespace Shaders { namespace Test { namespace { |
||||
|
||||
/*
|
||||
The goal of this is to not duplicate all testing work here, but instead |
||||
have a set of simple-to-setup benchmarks with trivial output that allow for |
||||
measuring cost of particular shader features or seeing performance |
||||
differences between different implementations of the same (e.g., using the |
||||
VertexColor shader vs Flat with vertex colors enabled). Thus: |
||||
|
||||
- all shaders render the same mesh, 2D shaders only ignore the Z |
||||
coordinate (so it should be possible to compare the perf between 2D and |
||||
3D) |
||||
- the mesh contains all attributes the shader might ever need including |
||||
instanced ones, to avoid differences caused by different memory access |
||||
patterns |
||||
- transformation and projection is identity |
||||
- textures are always single-pixel to measure the sampler overhead, not |
||||
memory access overhead |
||||
- if texture transformation is enabled, it's identity |
||||
- if instancing features are enabled, there's exactly one instance |
||||
- if alpha mask is enabled, it's 0.0 |
||||
- uniforms / binding overhead is not included in the benchmark |
||||
*/ |
||||
|
||||
struct ShadersGLBenchmark: GL::OpenGLTester { |
||||
explicit ShadersGLBenchmark(); |
||||
|
||||
void renderSetup(); |
||||
void renderTeardown(); |
||||
|
||||
template<UnsignedInt dimensions> void flat(); |
||||
void phong(); |
||||
template<UnsignedInt dimensions> void vertexColor(); |
||||
template<UnsignedInt dimensions> void vector(); |
||||
template<UnsignedInt dimensions> void distanceFieldVector(); |
||||
void meshVisualizer2D(); |
||||
void meshVisualizer3D(); |
||||
/** @todo mesh visualizer TBN, how to verify output? */ |
||||
|
||||
private: |
||||
PluginManager::Manager<Trade::AbstractImporter> _manager{"nonexistent"}; |
||||
|
||||
GL::Renderbuffer _color; |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
GL::Renderbuffer _objectId{NoCreate}; |
||||
#endif |
||||
GL::Framebuffer _framebuffer; |
||||
|
||||
GL::Buffer _indices, _vertices; |
||||
GL::Mesh _mesh, _meshInstanced, _meshDuplicated; |
||||
|
||||
GL::Texture2D _textureWhite, _textureBlue; |
||||
}; |
||||
|
||||
using namespace Math::Literals; |
||||
|
||||
constexpr Vector2i GridSubdivisions{64, 64}; |
||||
constexpr Vector2i RenderSize{512, 512}; |
||||
constexpr std::size_t WarmupIterations{100}; |
||||
constexpr std::size_t BenchmarkIterations{1000}; |
||||
constexpr std::size_t BenchmarkRepeats{4}; |
||||
|
||||
const struct { |
||||
const char* name; |
||||
FlatGL2D::Flags flags; |
||||
} FlatData[] { |
||||
{"", {}}, |
||||
{"vertex color", FlatGL2D::Flag::VertexColor}, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
{"object ID", FlatGL2D::Flag::ObjectId}, |
||||
#endif |
||||
{"textured", FlatGL2D::Flag::Textured}, |
||||
{"textured + alpha mask", FlatGL2D::Flag::Textured|FlatGL2D::Flag::AlphaMask}, |
||||
{"texture transformation", FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation}, |
||||
{"instanced transformation", FlatGL2D::Flag::InstancedTransformation}, |
||||
{"instanced transformation + color", FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::VertexColor}, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
{"instanced transformation + object ID", FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::InstancedObjectId}, |
||||
#endif |
||||
{"instanced transformation + texture offset", FlatGL2D::Flag::Textured|FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::InstancedTextureOffset}, |
||||
}; |
||||
|
||||
const struct { |
||||
const char* name; |
||||
PhongGL::Flags flags; |
||||
UnsignedInt lights; |
||||
} PhongData[] { |
||||
{"", {}, 1}, |
||||
{"zero lights", {}, 0}, |
||||
{"five lights", {}, 5}, |
||||
{"vertex color", PhongGL::Flag::VertexColor, 1}, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
{"object ID", PhongGL::Flag::ObjectId, 1}, |
||||
#endif |
||||
{"diffuse texture", PhongGL::Flag::DiffuseTexture, 1}, |
||||
{"ADS textures", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture, 1}, |
||||
{"ADS textures + alpha mask", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::AlphaMask, 1}, |
||||
{"ADS textures + transformation", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::TextureTransformation, 1}, |
||||
{"normal texture", PhongGL::Flag::NormalTexture, 1}, |
||||
{"normal texture with separate bitangent", PhongGL::Flag::NormalTexture|PhongGL::Flag::Bitangent, 1}, |
||||
{"instanced transformation", PhongGL::Flag::InstancedTransformation, 1}, |
||||
{"instanced transformation + color", PhongGL::Flag::InstancedTransformation|PhongGL::Flag::VertexColor, 1}, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
{"instanced transformation + object ID", PhongGL::Flag::InstancedTransformation|PhongGL::Flag::InstancedObjectId, 1}, |
||||
#endif |
||||
{"instanced transformation + ADS texture offset", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::InstancedTransformation|PhongGL::Flag::InstancedTextureOffset, 1}, |
||||
}; |
||||
|
||||
const struct { |
||||
const char* name; |
||||
VectorGL2D::Flags flags; |
||||
} VectorData[] { |
||||
{"", {}}, |
||||
{"texture transformation", VectorGL2D::Flag::TextureTransformation} |
||||
}; |
||||
|
||||
const struct { |
||||
const char* name; |
||||
DistanceFieldVectorGL2D::Flags flags; |
||||
} DistanceFieldVectorData[] { |
||||
{"", {}}, |
||||
{"texture transformation", DistanceFieldVectorGL2D::Flag::TextureTransformation} |
||||
}; |
||||
|
||||
const struct { |
||||
const char* name; |
||||
MeshVisualizerGL2D::Flags flags; |
||||
} MeshVisualizer2DData[] { |
||||
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) |
||||
{"wireframe", MeshVisualizerGL2D::Flag::Wireframe}, |
||||
#endif |
||||
{"wireframe w/o a GS", MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader}, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
{"instanced object ID", MeshVisualizerGL2D::Flag::InstancedObjectId}, |
||||
{"vertex ID", MeshVisualizerGL2D::Flag::VertexId}, |
||||
#ifndef MAGNUM_TARGET_WEBGL |
||||
{"primitive ID", MeshVisualizerGL2D::Flag::PrimitiveId}, |
||||
{"primitive ID from vertex ID", MeshVisualizerGL2D::Flag::PrimitiveIdFromVertexId}, |
||||
#endif |
||||
#endif |
||||
}; |
||||
|
||||
const struct { |
||||
const char* name; |
||||
MeshVisualizerGL3D::Flags flags; |
||||
} MeshVisualizer3DData[] { |
||||
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) |
||||
{"wireframe", MeshVisualizerGL3D::Flag::Wireframe}, |
||||
#endif |
||||
{"wireframe w/o a GS", MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader}, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
{"instanced object ID", MeshVisualizerGL3D::Flag::InstancedObjectId}, |
||||
{"vertex ID", MeshVisualizerGL3D::Flag::VertexId}, |
||||
#ifndef MAGNUM_TARGET_WEBGL |
||||
{"primitive ID", MeshVisualizerGL3D::Flag::PrimitiveId}, |
||||
{"primitive ID from vertex ID", MeshVisualizerGL3D::Flag::PrimitiveIdFromVertexId}, |
||||
#endif |
||||
#endif |
||||
}; |
||||
|
||||
ShadersGLBenchmark::ShadersGLBenchmark(): _framebuffer{{{}, RenderSize}} { |
||||
addInstancedBenchmarks({&ShadersGLBenchmark::flat<2>, |
||||
&ShadersGLBenchmark::flat<3>}, |
||||
BenchmarkRepeats, Containers::arraySize(FlatData), |
||||
&ShadersGLBenchmark::renderSetup, |
||||
&ShadersGLBenchmark::renderTeardown, |
||||
BenchmarkType::GpuTime); |
||||
|
||||
addInstancedBenchmarks({&ShadersGLBenchmark::phong}, |
||||
BenchmarkRepeats, Containers::arraySize(PhongData), |
||||
&ShadersGLBenchmark::renderSetup, |
||||
&ShadersGLBenchmark::renderTeardown, |
||||
BenchmarkType::GpuTime); |
||||
|
||||
addBenchmarks({&ShadersGLBenchmark::vertexColor<2>, |
||||
&ShadersGLBenchmark::vertexColor<3>}, |
||||
BenchmarkRepeats, |
||||
&ShadersGLBenchmark::renderSetup, |
||||
&ShadersGLBenchmark::renderTeardown, |
||||
BenchmarkType::GpuTime); |
||||
|
||||
addInstancedBenchmarks({&ShadersGLBenchmark::vector<2>, |
||||
&ShadersGLBenchmark::vector<3>}, |
||||
BenchmarkRepeats, Containers::arraySize(VectorData), |
||||
&ShadersGLBenchmark::renderSetup, |
||||
&ShadersGLBenchmark::renderTeardown, |
||||
BenchmarkType::GpuTime); |
||||
|
||||
addInstancedBenchmarks({&ShadersGLBenchmark::distanceFieldVector<2>, |
||||
&ShadersGLBenchmark::distanceFieldVector<3>}, |
||||
BenchmarkRepeats, Containers::arraySize(DistanceFieldVectorData), |
||||
&ShadersGLBenchmark::renderSetup, |
||||
&ShadersGLBenchmark::renderTeardown, |
||||
BenchmarkType::GpuTime); |
||||
|
||||
addInstancedBenchmarks({&ShadersGLBenchmark::meshVisualizer2D}, |
||||
BenchmarkRepeats, Containers::arraySize(MeshVisualizer2DData), |
||||
&ShadersGLBenchmark::renderSetup, |
||||
&ShadersGLBenchmark::renderTeardown, |
||||
BenchmarkType::GpuTime); |
||||
|
||||
addInstancedBenchmarks({&ShadersGLBenchmark::meshVisualizer3D}, |
||||
BenchmarkRepeats, Containers::arraySize(MeshVisualizer3DData), |
||||
&ShadersGLBenchmark::renderSetup, |
||||
&ShadersGLBenchmark::renderTeardown, |
||||
BenchmarkType::GpuTime); |
||||
|
||||
/* Set up the framebuffer */ |
||||
_color.setStorage( |
||||
#if !defined(MAGNUM_TARGET_GLES2) || !defined(MAGNUM_TARGET_WEBGL) |
||||
GL::RenderbufferFormat::RGBA8, |
||||
#else |
||||
GL::RenderbufferFormat::RGBA4, |
||||
#endif |
||||
RenderSize); |
||||
_framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, _color) |
||||
.bind(); |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
/* If we don't have EXT_gpu_shader4, we likely don't have integer
|
||||
framebuffers either (Mesa's Zink), so skip setting up integer |
||||
attachments to avoid GL errors */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(GL::Context::current().isExtensionSupported<GL::Extensions::EXT::gpu_shader4>()) |
||||
#endif |
||||
{ |
||||
_objectId = GL::Renderbuffer{}; |
||||
_objectId.setStorage(GL::RenderbufferFormat::R32UI, RenderSize); |
||||
_framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{1}, _objectId) |
||||
.mapForDraw({ |
||||
{FlatGL2D::ColorOutput, GL::Framebuffer::ColorAttachment{0}}, |
||||
{FlatGL2D::ObjectIdOutput, GL::Framebuffer::ColorAttachment{1}} |
||||
}); |
||||
} |
||||
#endif |
||||
|
||||
/* Set up the mesh */ |
||||
{ |
||||
Trade::MeshData data = Primitives::grid3DSolid(GridSubdivisions, |
||||
Primitives::GridFlag::TextureCoordinates| |
||||
Primitives::GridFlag::Normals| |
||||
Primitives::GridFlag::Tangents); |
||||
Containers::Array<Color4> vertexColors{DirectInit, data.vertexCount(), 0xffffffff_rgbaf}; |
||||
Containers::Array<Vector3> bitangents{DirectInit, data.vertexCount(), Vector3{0.0f, 1.0f, 0.0f}}; |
||||
Trade::MeshData dataWithVertexColors = MeshTools::interleave(std::move(data), { |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Color, arrayView(vertexColors)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, arrayView(bitangents)} |
||||
}); |
||||
_indices.setData(dataWithVertexColors.indexData()); |
||||
_vertices.setData(dataWithVertexColors.vertexData()); |
||||
_mesh = MeshTools::compile(dataWithVertexColors, _indices, _vertices); |
||||
|
||||
/* Instanced variant, if the divisor-related extension is supported */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(GL::Context::current().isExtensionSupported<GL::Extensions::ARB::instanced_arrays>()) |
||||
#elif defined(MAGNUM_TARGET_GLES2) |
||||
#ifndef MAGNUM_TARGET_WEBGL |
||||
if(GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::instanced_arrays>() || |
||||
GL::Context::current().isExtensionSupported<GL::Extensions::EXT::instanced_arrays>() || |
||||
GL::Context::current().isExtensionSupported<GL::Extensions::NV::instanced_arrays>()) |
||||
#else |
||||
if(GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::instanced_arrays>()) |
||||
#endif |
||||
#endif |
||||
{ |
||||
_meshInstanced = MeshTools::compile(dataWithVertexColors, _indices, _vertices); |
||||
struct { |
||||
/* Given the way the matrix attribute is specified (column by
|
||||
column), it should work for 2D as well */ |
||||
Matrix4 transformation{Math::IdentityInit}; |
||||
Matrix3x3 normalMatrix{Math::IdentityInit}; |
||||
Vector2 textureOffset{0.0f, 0.0f}; |
||||
Color4 color{0xffffffff_rgbaf}; |
||||
UnsignedInt objectId{0}; |
||||
} instanceData[1]; |
||||
_meshInstanced.addVertexBufferInstanced(GL::Buffer{instanceData}, 1, 0, |
||||
GenericGL3D::TransformationMatrix{}, |
||||
GenericGL3D::NormalMatrix{}, |
||||
GenericGL3D::TextureOffset{}, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
GenericGL3D::ObjectId{} |
||||
#else |
||||
sizeof(UnsignedInt) |
||||
#endif |
||||
); |
||||
/** @todo hmm, this doesn't really issue an instanced draw call, does
|
||||
that matter? */ |
||||
_meshInstanced.setInstanceCount(1); |
||||
} |
||||
|
||||
/* Non-indexed variant for GS-less wireframe drawing */ |
||||
_meshDuplicated = MeshTools::compile(MeshTools::duplicate(dataWithVertexColors)); |
||||
} |
||||
|
||||
/* Set up the textures */ |
||||
{ |
||||
const Color4ub white[1] { 0xffffffff_rgba }; |
||||
_textureWhite.setMinificationFilter(GL::SamplerFilter::Linear) |
||||
.setMagnificationFilter(GL::SamplerFilter::Linear) |
||||
.setWrapping(GL::SamplerWrapping::ClampToEdge) |
||||
.setStorage(1, |
||||
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) |
||||
GL::TextureFormat::RGBA8 |
||||
#else |
||||
GL::TextureFormat::RGBA |
||||
#endif |
||||
, {1, 1}) |
||||
.setSubImage(0, {}, ImageView2D{PixelFormat::RGBA8Unorm, {1, 1}, white}); |
||||
} { |
||||
const Color4ub blue[1] { 0x0000ffff_rgba }; |
||||
_textureBlue.setMinificationFilter(GL::SamplerFilter::Linear) |
||||
.setMagnificationFilter(GL::SamplerFilter::Linear) |
||||
.setWrapping(GL::SamplerWrapping::ClampToEdge) |
||||
.setStorage(1, |
||||
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) |
||||
GL::TextureFormat::RGBA8 |
||||
#else |
||||
GL::TextureFormat::RGBA |
||||
#endif |
||||
, {1, 1}) |
||||
.setSubImage(0, {}, ImageView2D{PixelFormat::RGBA8Unorm, {1, 1}, blue}); |
||||
} |
||||
|
||||
/* Load the plugins directly from the build tree. Otherwise they're either
|
||||
static and already loaded or not present in the build tree */ |
||||
#ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME |
||||
CORRADE_INTERNAL_ASSERT_OUTPUT(_manager.load(ANYIMAGEIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); |
||||
#endif |
||||
#ifdef TGAIMPORTER_PLUGIN_FILENAME |
||||
CORRADE_INTERNAL_ASSERT_OUTPUT(_manager.load(TGAIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); |
||||
#endif |
||||
} |
||||
|
||||
void ShadersGLBenchmark::renderSetup() { |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(GL::Context::current().isExtensionSupported<GL::Extensions::EXT::gpu_shader4>()) |
||||
#endif |
||||
{ |
||||
_framebuffer |
||||
.clearColor(0, Color4{}) |
||||
.clearColor(1, Vector4ui{}); |
||||
} |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
else |
||||
#endif |
||||
#endif |
||||
{ |
||||
_framebuffer.clear(GL::FramebufferClear::Color); |
||||
} |
||||
} |
||||
|
||||
void ShadersGLBenchmark::renderTeardown() { |
||||
/* Nothing to do here */ |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void ShadersGLBenchmark::flat() { |
||||
auto&& data = FlatData[testCaseInstanceId()]; |
||||
setTestCaseTemplateName(Utility::formatString("{}", dimensions)); |
||||
setTestCaseDescription(data.name); |
||||
|
||||
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || |
||||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) |
||||
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); |
||||
|
||||
FlatGL<dimensions> shader{data.flags}; |
||||
if(data.flags >= FlatGL2D::Flag::AlphaMask) |
||||
shader.setAlphaMask(0.0f); |
||||
if(data.flags >= FlatGL2D::Flag::Textured) |
||||
shader.bindTexture(_textureWhite); |
||||
|
||||
GL::Mesh* mesh; |
||||
/* InstancedTextureOffset is a superset of TextureTransformation, so
|
||||
remove those bits first when deciding if instanced */ |
||||
if((data.flags & ~FlatGL2D::Flag::TextureTransformation) & (FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::InstancedTextureOffset |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
|FlatGL2D::Flag::InstancedObjectId |
||||
#endif |
||||
)) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::instanced_arrays>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::instanced_arrays::string() << "is not supported."); |
||||
#elif defined(MAGNUM_TARGET_GLES2) |
||||
#ifndef MAGNUM_TARGET_WEBGL |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::instanced_arrays>() && |
||||
!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::instanced_arrays>() && |
||||
!GL::Context::current().isExtensionSupported<GL::Extensions::NV::instanced_arrays>()) |
||||
CORRADE_SKIP("Required extension is not available."); |
||||
#else |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::instanced_arrays>()) |
||||
CORRADE_SKIP(GL::Extensions::ANGLE::instanced_arrays::string() << "is not supported."); |
||||
#endif |
||||
#endif |
||||
mesh = &_meshInstanced; |
||||
} else { |
||||
mesh = &_mesh; |
||||
} |
||||
|
||||
/* Warmup run */ |
||||
/** @todo make this possible to do inside CORRADE_BENCHMARK() */ |
||||
for(std::size_t i = 0; i != 100; ++i) |
||||
shader.draw(*mesh); |
||||
|
||||
CORRADE_BENCHMARK(BenchmarkIterations) |
||||
shader.draw(*mesh); |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
|
||||
CORRADE_COMPARE_WITH(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}), |
||||
Utility::Directory::join(SHADERS_TEST_DIR, "BenchmarkFiles/trivial.tga"), |
||||
DebugTools::CompareImageToFile{_manager}); |
||||
} |
||||
|
||||
void ShadersGLBenchmark::phong() { |
||||
auto&& data = PhongData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || |
||||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) |
||||
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); |
||||
|
||||
PhongGL shader{data.flags, data.lights}; |
||||
/* White ambient so we always have a white output */ |
||||
shader.setAmbientColor(0xffffffff_rgbaf); |
||||
if(data.flags >= PhongGL::Flag::AlphaMask) |
||||
shader.setAlphaMask(0.0f); |
||||
if(data.flags >= PhongGL::Flag::AmbientTexture) |
||||
shader.bindAmbientTexture(_textureWhite); |
||||
if(data.flags >= PhongGL::Flag::DiffuseTexture) |
||||
shader.bindDiffuseTexture(_textureWhite); |
||||
if(data.flags >= PhongGL::Flag::SpecularTexture) |
||||
shader.bindSpecularTexture(_textureWhite); |
||||
if(data.flags >= PhongGL::Flag::NormalTexture) |
||||
shader.bindNormalTexture(_textureBlue); |
||||
|
||||
GL::Mesh* mesh; |
||||
/* InstancedTextureOffset is a superset of TextureTransformation, so
|
||||
remove those bits first when deciding if instanced */ |
||||
if((data.flags & ~PhongGL::Flag::TextureTransformation) & (PhongGL::Flag::InstancedTransformation|PhongGL::Flag::InstancedTextureOffset |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
|PhongGL::Flag::InstancedObjectId |
||||
#endif |
||||
)) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::draw_instanced>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::draw_instanced::string() << "is not supported."); |
||||
#elif defined(MAGNUM_TARGET_GLES2) |
||||
#ifndef MAGNUM_TARGET_WEBGL |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::instanced_arrays>() && |
||||
!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::instanced_arrays>() && |
||||
!GL::Context::current().isExtensionSupported<GL::Extensions::NV::instanced_arrays>()) |
||||
CORRADE_SKIP("Required extension is not available."); |
||||
#else |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::instanced_arrays>()) |
||||
CORRADE_SKIP(GL::Extensions::ANGLE::instanced_arrays::string() << "is not supported."); |
||||
#endif |
||||
#endif |
||||
mesh = &_meshInstanced; |
||||
} else { |
||||
mesh = &_mesh; |
||||
} |
||||
|
||||
/* Warmup run */ |
||||
/** @todo make this possible to do inside CORRADE_BENCHMARK() */ |
||||
for(std::size_t i = 0; i != WarmupIterations; ++i) |
||||
shader.draw(*mesh); |
||||
|
||||
CORRADE_BENCHMARK(BenchmarkIterations) |
||||
shader.draw(*mesh); |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
|
||||
CORRADE_COMPARE_WITH(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}), |
||||
Utility::Directory::join(SHADERS_TEST_DIR, "BenchmarkFiles/trivial.tga"), |
||||
DebugTools::CompareImageToFile{_manager}); |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void ShadersGLBenchmark::vertexColor() { |
||||
setTestCaseTemplateName(Utility::formatString("{}", dimensions)); |
||||
|
||||
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || |
||||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) |
||||
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); |
||||
|
||||
VertexColorGL<dimensions> shader; |
||||
|
||||
/* Warmup run */ |
||||
/** @todo make this possible to do inside CORRADE_BENCHMARK() */ |
||||
for(std::size_t i = 0; i != WarmupIterations; ++i) |
||||
shader.draw(_mesh); |
||||
|
||||
CORRADE_BENCHMARK(BenchmarkIterations) |
||||
shader.draw(_mesh); |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
|
||||
CORRADE_COMPARE_WITH(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}), |
||||
Utility::Directory::join(SHADERS_TEST_DIR, "BenchmarkFiles/trivial.tga"), |
||||
DebugTools::CompareImageToFile{_manager}); |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void ShadersGLBenchmark::vector() { |
||||
auto&& data = VectorData[testCaseInstanceId()]; |
||||
setTestCaseTemplateName(Utility::formatString("{}", dimensions)); |
||||
setTestCaseDescription(data.name); |
||||
|
||||
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || |
||||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) |
||||
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); |
||||
|
||||
VectorGL<dimensions> shader{data.flags}; |
||||
shader.bindVectorTexture(_textureWhite); |
||||
|
||||
/* Warmup run */ |
||||
/** @todo make this possible to do inside CORRADE_BENCHMARK() */ |
||||
for(std::size_t i = 0; i != WarmupIterations; ++i) |
||||
shader.draw(_mesh); |
||||
|
||||
CORRADE_BENCHMARK(BenchmarkIterations) |
||||
shader.draw(_mesh); |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
|
||||
CORRADE_COMPARE_WITH(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}), |
||||
Utility::Directory::join(SHADERS_TEST_DIR, "BenchmarkFiles/trivial.tga"), |
||||
DebugTools::CompareImageToFile{_manager}); |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void ShadersGLBenchmark::distanceFieldVector() { |
||||
auto&& data = DistanceFieldVectorData[testCaseInstanceId()]; |
||||
setTestCaseTemplateName(Utility::formatString("{}", dimensions)); |
||||
setTestCaseDescription(data.name); |
||||
|
||||
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || |
||||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) |
||||
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); |
||||
|
||||
DistanceFieldVectorGL<dimensions> shader{data.flags}; |
||||
shader.bindVectorTexture(_textureWhite); |
||||
|
||||
/* Warmup run */ |
||||
/** @todo make this possible to do inside CORRADE_BENCHMARK() */ |
||||
for(std::size_t i = 0; i != WarmupIterations; ++i) |
||||
shader.draw(_mesh); |
||||
|
||||
CORRADE_BENCHMARK(BenchmarkIterations) |
||||
shader.draw(_mesh); |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
|
||||
CORRADE_COMPARE_WITH(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}), |
||||
Utility::Directory::join(SHADERS_TEST_DIR, "BenchmarkFiles/trivial.tga"), |
||||
DebugTools::CompareImageToFile{_manager}); |
||||
} |
||||
|
||||
void ShadersGLBenchmark::meshVisualizer2D() { |
||||
auto&& data = MeshVisualizer2DData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || |
||||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) |
||||
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); |
||||
|
||||
/* Checks verbatim copied from MeshVisualizerGLTest::construct2D() */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if((data.flags & MeshVisualizerGL2D::Flag::InstancedObjectId) && !GL::Context::current().isExtensionSupported<GL::Extensions::EXT::gpu_shader4>()) |
||||
CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); |
||||
#endif |
||||
|
||||
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) |
||||
if(data.flags >= MeshVisualizerGL2D::Flag::PrimitiveIdFromVertexId && |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
!GL::Context::current().isVersionSupported(GL::Version::GL300) |
||||
#else |
||||
!GL::Context::current().isVersionSupported(GL::Version::GLES300) |
||||
#endif |
||||
) CORRADE_SKIP("gl_VertexID not supported."); |
||||
#endif |
||||
|
||||
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) |
||||
if(data.flags & MeshVisualizerGL2D::Flag::PrimitiveId && !(data.flags >= MeshVisualizerGL2D::Flag::PrimitiveIdFromVertexId) && |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
!GL::Context::current().isVersionSupported(GL::Version::GL320) |
||||
#else |
||||
!GL::Context::current().isVersionSupported(GL::Version::GLES320) |
||||
#endif |
||||
) CORRADE_SKIP("gl_PrimitiveID not supported."); |
||||
#endif |
||||
|
||||
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) |
||||
if((data.flags & MeshVisualizerGL2D::Flag::Wireframe) && !(data.flags & MeshVisualizerGL2D::Flag::NoGeometryShader)) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::geometry_shader4>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() << "is not supported."); |
||||
#else |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::geometry_shader>()) |
||||
CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() << "is not supported."); |
||||
#endif |
||||
|
||||
#ifdef MAGNUM_TARGET_GLES |
||||
if(GL::Context::current().isExtensionSupported<GL::Extensions::NV::shader_noperspective_interpolation>()) |
||||
CORRADE_INFO("Using" << GL::Extensions::NV::shader_noperspective_interpolation::string()); |
||||
#endif |
||||
} |
||||
#endif |
||||
|
||||
MeshVisualizerGL2D shader{data.flags}; |
||||
shader.setViewportSize(Vector2{RenderSize}); |
||||
if(data.flags >= MeshVisualizerGL2D::Flag::Wireframe) |
||||
shader.setWireframeColor(0xffffffff_rgbaf); |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
if(data.flags & (MeshVisualizerGL2D::Flag::InstancedObjectId|MeshVisualizerGL2D::Flag::VertexId|MeshVisualizerGL2D::Flag::PrimitiveIdFromVertexId |
||||
#ifndef MAGNUM_TARGET_WEBGL |
||||
|MeshVisualizerGL2D::Flag::PrimitiveId |
||||
#endif |
||||
)) |
||||
shader.bindColorMapTexture(_textureWhite); |
||||
#endif |
||||
|
||||
GL::Mesh* mesh; |
||||
if(data.flags >= MeshVisualizerGL2D::Flag::NoGeometryShader) { |
||||
mesh = &_meshDuplicated; |
||||
} |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
else if(data.flags & MeshVisualizerGL2D::Flag::InstancedObjectId) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::draw_instanced>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::draw_instanced::string() << "is not supported."); |
||||
#endif |
||||
mesh = &_meshInstanced; |
||||
} |
||||
#endif |
||||
else { |
||||
mesh = &_mesh; |
||||
} |
||||
|
||||
/* Warmup run */ |
||||
/** @todo make this possible to do inside CORRADE_BENCHMARK() */ |
||||
for(std::size_t i = 0; i != WarmupIterations; ++i) |
||||
shader.draw(*mesh); |
||||
|
||||
CORRADE_BENCHMARK(BenchmarkIterations) |
||||
shader.draw(*mesh); |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
|
||||
CORRADE_COMPARE_WITH(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}), |
||||
Utility::Directory::join(SHADERS_TEST_DIR, "BenchmarkFiles/trivial.tga"), |
||||
DebugTools::CompareImageToFile{_manager}); |
||||
} |
||||
|
||||
void ShadersGLBenchmark::meshVisualizer3D() { |
||||
auto&& data = MeshVisualizer3DData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || |
||||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) |
||||
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); |
||||
|
||||
/* Checks verbatim copied from MeshVisualizerGLTest:.construct3D() */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if((data.flags & MeshVisualizerGL3D::Flag::InstancedObjectId) && !GL::Context::current().isExtensionSupported<GL::Extensions::EXT::gpu_shader4>()) |
||||
CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); |
||||
#endif |
||||
|
||||
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) |
||||
if(data.flags >= MeshVisualizerGL3D::Flag::PrimitiveIdFromVertexId && |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
!GL::Context::current().isVersionSupported(GL::Version::GL300) |
||||
#else |
||||
!GL::Context::current().isVersionSupported(GL::Version::GLES300) |
||||
#endif |
||||
) CORRADE_SKIP("gl_VertexID not supported."); |
||||
#endif |
||||
|
||||
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) |
||||
if(data.flags & MeshVisualizerGL3D::Flag::PrimitiveId && !(data.flags >= MeshVisualizerGL3D::Flag::PrimitiveIdFromVertexId) && |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
!GL::Context::current().isVersionSupported(GL::Version::GL320) |
||||
#else |
||||
!GL::Context::current().isVersionSupported(GL::Version::GLES320) |
||||
#endif |
||||
) CORRADE_SKIP("gl_PrimitiveID not supported."); |
||||
#endif |
||||
|
||||
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) |
||||
if(((data.flags & MeshVisualizerGL3D::Flag::Wireframe) && !(data.flags & MeshVisualizerGL3D::Flag::NoGeometryShader)) || (data.flags & (MeshVisualizerGL3D::Flag::TangentDirection|MeshVisualizerGL3D::Flag::BitangentDirection|MeshVisualizerGL3D::Flag::BitangentFromTangentDirection|MeshVisualizerGL3D::Flag::NormalDirection))) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::geometry_shader4>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() << "is not supported."); |
||||
#else |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::geometry_shader>()) |
||||
CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() << "is not supported."); |
||||
#endif |
||||
|
||||
#ifdef MAGNUM_TARGET_GLES |
||||
if(GL::Context::current().isExtensionSupported<GL::Extensions::NV::shader_noperspective_interpolation>()) |
||||
CORRADE_INFO("Using" << GL::Extensions::NV::shader_noperspective_interpolation::string()); |
||||
#endif |
||||
} |
||||
#endif |
||||
|
||||
MeshVisualizerGL3D shader{data.flags}; |
||||
shader.setViewportSize(Vector2{RenderSize}); |
||||
if(data.flags >= MeshVisualizerGL3D::Flag::Wireframe) |
||||
shader.setWireframeColor(0xffffffff_rgbaf); |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
if(data.flags & (MeshVisualizerGL3D::Flag::InstancedObjectId|MeshVisualizerGL3D::Flag::VertexId|MeshVisualizerGL3D::Flag::PrimitiveIdFromVertexId |
||||
#ifndef MAGNUM_TARGET_WEBGL |
||||
|MeshVisualizerGL3D::Flag::PrimitiveId |
||||
#endif |
||||
)) |
||||
shader.bindColorMapTexture(_textureWhite); |
||||
#endif |
||||
|
||||
GL::Mesh* mesh; |
||||
if(data.flags >= MeshVisualizerGL3D::Flag::NoGeometryShader) |
||||
mesh = &_meshDuplicated; |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
else if(data.flags & MeshVisualizerGL3D::Flag::InstancedObjectId) |
||||
mesh = &_meshInstanced; |
||||
#endif |
||||
else |
||||
mesh = &_mesh; |
||||
|
||||
/* Warmup run */ |
||||
/** @todo make this possible to do inside CORRADE_BENCHMARK() */ |
||||
for(std::size_t i = 0; i != WarmupIterations; ++i) |
||||
shader.draw(*mesh); |
||||
|
||||
CORRADE_BENCHMARK(BenchmarkIterations) |
||||
shader.draw(*mesh); |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
|
||||
CORRADE_COMPARE_WITH(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}), |
||||
Utility::Directory::join(SHADERS_TEST_DIR, "BenchmarkFiles/trivial.tga"), |
||||
DebugTools::CompareImageToFile{_manager}); |
||||
} |
||||
|
||||
}}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Shaders::Test::ShadersGLBenchmark) |
||||
Loading…
Reference in new issue