diff --git a/examples/Cpp/Animation/Example.cpp b/examples/Cpp/Animation/Example.cpp index 2c8c3aa553..df357b7922 100644 --- a/examples/Cpp/Animation/Example.cpp +++ b/examples/Cpp/Animation/Example.cpp @@ -153,21 +153,19 @@ class Example_Animation : public ExampleBase void CreatePipelines(const LLGL::VertexFormat& vertexFormat) { // Create graphics pipeline for scene rendering + LLGL::GraphicsPipelineDescriptor pipelineDesc; { - LLGL::GraphicsPipelineDescriptor pipelineDesc; - { - pipelineDesc.vertexShader = LoadStandardVertexShader("VS", { vertexFormat }); - pipelineDesc.fragmentShader = LoadStandardFragmentShader("PS"); - pipelineDesc.renderPass = swapChain->GetRenderPass(); - pipelineDesc.pipelineLayout = pipelineLayout; - pipelineDesc.depth.testEnabled = true; - pipelineDesc.depth.writeEnabled = true; - pipelineDesc.rasterizer.cullMode = LLGL::CullMode::Back; - pipelineDesc.rasterizer.multiSampleEnabled = (GetSampleCount() > 1); - } - pipelineScene = renderer->CreatePipelineState(pipelineDesc); - ThrowIfFailed(pipelineScene); + pipelineDesc.vertexShader = LoadStandardVertexShader("VS", { vertexFormat }); + pipelineDesc.fragmentShader = LoadStandardFragmentShader("PS"); + pipelineDesc.renderPass = swapChain->GetRenderPass(); + pipelineDesc.pipelineLayout = pipelineLayout; + pipelineDesc.depth.testEnabled = true; + pipelineDesc.depth.writeEnabled = true; + pipelineDesc.rasterizer.cullMode = LLGL::CullMode::Back; + pipelineDesc.rasterizer.multiSampleEnabled = (GetSampleCount() > 1); } + pipelineScene = renderer->CreatePipelineState(pipelineDesc); + ThrowIfFailed(pipelineScene); } void CreateResourceHeaps() @@ -327,7 +325,7 @@ class Example_Animation : public ExampleBase // Render everything directly into the swap-chain commands->BeginRenderPass(*swapChain); { - commands->Clear(LLGL::ClearFlags::All, backgroundColor); + commands->Clear(LLGL::ClearFlags::ColorDepth, backgroundColor); commands->SetViewport(swapChain->GetResolution()); RenderScene(); } diff --git a/examples/Cpp/ExampleBase/DDSImageReader.cpp b/examples/Cpp/ExampleBase/DDSImageReader.cpp index ad6a1a2f6d..be54f6e0d6 100644 --- a/examples/Cpp/ExampleBase/DDSImageReader.cpp +++ b/examples/Cpp/ExampleBase/DDSImageReader.cpp @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include #include @@ -215,12 +213,10 @@ void DDSImageReader::LoadFromFile(const std::string& filename) else { // Print error with FourCC as string - char fourCC[4] = {}; - ::memcpy(fourCC, &(header.format.fourCC), sizeof(fourCC)); + char fourCC[5] = {}; + ::memcpy(fourCC, &(header.format.fourCC), sizeof(header.format.fourCC)); - std::stringstream err; - err << "DDS image has unsupported FourCC value: " << fourCC[0] << fourCC[1] << fourCC[2] << fourCC[3]; - throw std::runtime_error(err.str()); + throw std::runtime_error("DDS image has unsupported FourCC value: " + std::string(fourCC)); } // Read image buffer diff --git a/examples/Cpp/ExampleBase/DDSImageReader.h b/examples/Cpp/ExampleBase/DDSImageReader.h index ae438b30c3..9894f1e4ef 100644 --- a/examples/Cpp/ExampleBase/DDSImageReader.h +++ b/examples/Cpp/ExampleBase/DDSImageReader.h @@ -13,7 +13,6 @@ #include #include #include -#include // Perlin noise generator class. diff --git a/examples/Cpp/ExampleBase/ExampleBase.cpp b/examples/Cpp/ExampleBase/ExampleBase.cpp index c6be458f06..44cc4dc0aa 100644 --- a/examples/Cpp/ExampleBase/ExampleBase.cpp +++ b/examples/Cpp/ExampleBase/ExampleBase.cpp @@ -8,8 +8,8 @@ #include #include #include -#include #include "FileUtils.h" +#include #define STB_IMAGE_IMPLEMENTATION #include @@ -17,6 +17,15 @@ #define STB_IMAGE_WRITE_IMPLEMENTATION #include + /* + Make PRIX64 macro visible inside ; Required on some hosts that predate C++11. + See https://www.gnu.org/software/gnulib/manual/html_node/inttypes_002eh.html + */ +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif +#include + /* * Global helper functions @@ -44,21 +53,29 @@ static std::string GetRendererModuleFromUserSelection(int argc, char* argv[]) while (rendererModule.empty()) { /* Print list of available modules */ - std::cout << "select renderer:" << std::endl; + LLGL::Log::Printf("select renderer:\n"); int i = 0; for (const std::string& mod : modules) - std::cout << " " << (++i) << ".) " << mod << std::endl; + LLGL::Log::Printf(" %d.) %s\n", ++i, mod.c_str()); /* Wait for user input */ - std::size_t selection = 0; - std::cin >> selection; - --selection; + char selectionBuffer[256] = {}; + (void)::fgets(selectionBuffer, sizeof(selectionBuffer), stdin); - if (selection < modules.size()) - rendererModule = modules[selection]; + std::string selectionStr = selectionBuffer; + selectionStr = selectionStr.substr(0, selectionStr.find_first_not_of("0123456789")); + if (!selectionStr.empty()) + { + int selection = std::stoi(selectionStr); + const std::size_t selectionIndex = static_cast(selection - 1); + if (selectionIndex < modules.size()) + rendererModule = modules[selectionIndex]; + else + LLGL::Log::Errorf("invalid input: %d is out of range\n", selection); + } else - std::cerr << "invalid input" << std::endl; + LLGL::Log::Errorf("invalid input: %s is not a number\n", selectionBuffer); } return rendererModule; @@ -113,12 +130,14 @@ static void GetSelectedRendererModuleOrDefault(std::string& rendererModule, int } } } - std::cout << "selected renderer: " << rendererModule << std::endl; + LLGL::Log::Printf("selected renderer: %s\n", rendererModule.c_str()); } static constexpr const char* GetDefaultRendererModule() { - #if defined LLGL_OS_WIN32 + #if defined LLGL_OS_UWP + return "Direct3D12"; + #elif defined LLGL_OS_WIN32 return "Direct3D11"; #elif defined LLGL_OS_IOS || defined LLGL_OS_MACOS return "Metal"; @@ -131,6 +150,8 @@ static constexpr const char* GetDefaultRendererModule() std::string GetSelectedRendererModule(int argc, char* argv[]) { + // Set report callback to standard output + LLGL::Log::RegisterCallbackStd(); std::string rendererModule = GetDefaultRendererModule(); GetSelectedRendererModuleOrDefault(rendererModule, argc, argv); return rendererModule; @@ -305,6 +326,7 @@ struct ExampleConfig std::uint32_t samples = 8; bool vsync = true; bool debugger = false; + long flags = 0; }; static ExampleConfig g_Config; @@ -322,6 +344,12 @@ void ExampleBase::ParseProgramArgs(int argc, char* argv[]) g_Config.vsync = false; if (HasArgument("-d", argc, argv) || HasArgument("--debug", argc, argv)) g_Config.debugger = true; + if (HasArgument("-nvidia", argc, argv)) + g_Config.flags |= LLGL::RenderSystemFlags::PreferNVIDIA; + if (HasArgument("-amd", argc, argv)) + g_Config.flags |= LLGL::RenderSystemFlags::PreferAMD; + if (HasArgument("-intel", argc, argv)) + g_Config.flags |= LLGL::RenderSystemFlags::PreferIntel; } #if defined LLGL_OS_ANDROID @@ -350,11 +378,13 @@ void ExampleBase::Run() if (showTimeRecords) { - std::cout << "\n"; - std::cout << "FRAME TIME RECORDS:\n"; - std::cout << "-------------------\n"; + LLGL::Log::Printf( + "\n" + "FRAME TIME RECORDS:\n" + "-------------------\n" + ); for (const LLGL::ProfileTimeRecord& rec : frameProfile.timeRecords) - std::cout << rec.annotation << ": " << rec.elapsedTime << " ns\n"; + LLGL::Log::Printf("%s: " PRIu64 " ns\n", rec.annotation, rec.elapsedTime); debuggerObj_->SetTimeRecording(false); showTimeRecords = false; @@ -425,7 +455,7 @@ static LLGL::Extent2D ScaleResolutionForDisplay(const LLGL::Extent2D& res, const ExampleBase::ExampleBase(const LLGL::UTF8String& title) { - // Set report callback to standard output + // Set report callback to standard output if not already done LLGL::Log::RegisterCallbackStd(); // Set up renderer descriptor @@ -448,6 +478,7 @@ ExampleBase::ExampleBase(const LLGL::UTF8String& title) } // Create render system + rendererDesc.flags |= g_Config.flags; renderer = LLGL::RenderSystem::Load(rendererDesc); // Apply device limits (not for GL, because we won't have a valid GL context until we create our first swap chain) @@ -468,7 +499,12 @@ ExampleBase::ExampleBase(const LLGL::UTF8String& title) swapChain->SetVsyncInterval(g_Config.vsync ? 1 : 0); // Create command buffer - commands = renderer->CreateCommandBuffer();//LLGL::CommandBufferFlags::ImmediateSubmit); + LLGL::CommandBufferDescriptor cmdBufferDesc; + { + cmdBufferDesc.debugName = "Commands"; + //cmdBufferDesc.flags = LLGL::CommandBufferFlags::ImmediateSubmit; + } + commands = renderer->CreateCommandBuffer(cmdBufferDesc); // Get command queue commandQueue = renderer->GetCommandQueue(); @@ -477,25 +513,36 @@ ExampleBase::ExampleBase(const LLGL::UTF8String& title) const auto& info = renderer->GetRendererInfo(); const auto swapChainRes = swapChain->GetResolution(); - std::cout << "render system:" << std::endl; - std::cout << " renderer: " << info.rendererName << std::endl; - std::cout << " device: " << info.deviceName << std::endl; - std::cout << " vendor: " << info.vendorName << std::endl; - std::cout << " shading language: " << info.shadingLanguageName << std::endl; - std::cout << std::endl; - std::cout << "swap-chain:" << std::endl; - std::cout << " resolution: " << swapChainRes.width << " x " << swapChainRes.height << std::endl; - std::cout << " samples: " << swapChain->GetSamples() << std::endl; - std::cout << " colorFormat: " << LLGL::ToString(swapChain->GetColorFormat()) << std::endl; - std::cout << " depthStencilFormat: " << LLGL::ToString(swapChain->GetDepthStencilFormat()) << std::endl; - std::cout << std::endl; + LLGL::Log::Printf( + "render system:\n" + " renderer: %s\n" + " device: %s\n" + " vendor: %s\n" + " shading language: %s\n" + "\n" + "swap-chain:\n" + " resolution: %u x %u\n" + " samples: %u\n" + " colorFormat: %s\n" + " depthStencilFormat: %s\n" + "\n", + info.rendererName.c_str(), + info.deviceName.c_str(), + info.vendorName.c_str(), + info.shadingLanguageName.c_str(), + swapChainRes.width, + swapChainRes.height, + swapChain->GetSamples(), + LLGL::ToString(swapChain->GetColorFormat()), + LLGL::ToString(swapChain->GetDepthStencilFormat()) + ); if (!info.extensionNames.empty()) { - std::cout << "extensions:" << std::endl; - for (const auto& name : info.extensionNames) - std::cout << " " << name << std::endl; - std::cout << std::endl; + LLGL::Log::Printf("extensions:\n"); + for (const std::string& name : info.extensionNames) + LLGL::Log::Printf(" %s\n", name.c_str()); + LLGL::Log::Printf("\n"); } #ifdef LLGL_MOBILE_PLATFORM @@ -567,8 +614,10 @@ LLGL::Shader* ExampleBase::LoadShaderInternal( } // Create shader - auto deviceShaderDesc = LLGL::ShaderDescFromFile(shaderDesc.type, shaderDesc.filename.c_str(), shaderDesc.entryPoint.c_str(), shaderDesc.profile.c_str()); + LLGL::ShaderDescriptor deviceShaderDesc = LLGL::ShaderDescFromFile(shaderDesc.type, shaderDesc.filename.c_str(), shaderDesc.entryPoint.c_str(), shaderDesc.profile.c_str()); { + deviceShaderDesc.debugName = shaderDesc.entryPoint.c_str(); + // Forward macro definitions deviceShaderDesc.defines = defines; @@ -608,10 +657,10 @@ LLGL::Shader* ExampleBase::LoadShaderInternal( if (Supported(LLGL::ShadingLanguage::ESSL)) deviceShaderDesc.profile = "300 es"; } - auto shader = renderer->CreateShader(deviceShaderDesc); + LLGL::Shader* shader = renderer->CreateShader(deviceShaderDesc); // Print info log (warnings and errors) - if (auto report = shader->GetReport()) + if (const LLGL::Report* report = shader->GetReport()) { if (*report->GetText() != '\0') { @@ -750,15 +799,15 @@ LLGL::Texture* LoadTextureWithRenderer(LLGL::RenderSystem& renderSys, const std: } // Create texture and upload image data onto hardware texture - auto tex = renderSys.CreateTexture( - LLGL::Texture2DDesc(format, width, height, bindFlags), &imageView - ); + LLGL::TextureDescriptor texDesc = LLGL::Texture2DDesc(format, width, height, bindFlags); + texDesc.debugName = filename.c_str(); + LLGL::Texture* tex = renderSys.CreateTexture(texDesc, &imageView); // Release image data stbi_image_free(imageBuffer); // Show info - std::cout << "loaded texture: " << filename << std::endl; + LLGL::Log::Printf("loaded texture: %s\n", filename.c_str()); return tex; } @@ -808,12 +857,12 @@ bool SaveTextureWithRenderer(LLGL::RenderSystem& renderSys, LLGL::Texture& textu if (!result) { - std::cerr << "failed to write texture to file: \"" + filename + "\"" << std::endl; + LLGL::Log::Errorf("failed to write texture to file: \"%s\"\n", filename.c_str()); return false; } // Show info - std::cout << "saved texture: " << filename << std::endl; + LLGL::Log::Printf("saved texture: %s\n", filename.c_str()); return true; } @@ -898,20 +947,39 @@ bool ExampleBase::IsScreenOriginLowerLeft() const return (renderer->GetRenderingCaps().screenOrigin == LLGL::ScreenOrigin::LowerLeft); } -Gs::Matrix4f ExampleBase::PerspectiveProjection(float aspectRatio, float near, float far, float fov) +Gs::Matrix4f ExampleBase::PerspectiveProjection(float aspectRatio, float near, float far, float fov) const { const bool isClipRangeUnitCube = (renderer->GetRenderingCaps().clippingRange == LLGL::ClippingRange::MinusOneToOne); int flags = (isClipRangeUnitCube ? Gs::ProjectionFlags::UnitCube : 0); return Gs::ProjectionMatrix4f::Perspective(aspectRatio, near, far, fov, flags).ToMatrix4(); } -Gs::Matrix4f ExampleBase::OrthogonalProjection(float width, float height, float near, float far) +Gs::Matrix4f ExampleBase::OrthogonalProjection(float width, float height, float near, float far) const { const bool isClipRangeUnitCube = (renderer->GetRenderingCaps().clippingRange == LLGL::ClippingRange::MinusOneToOne); int flags = (isClipRangeUnitCube ? Gs::ProjectionFlags::UnitCube : 0); return Gs::ProjectionMatrix4f::Orthogonal(width, height, near, far, flags).ToMatrix4(); } +Gs::Quaternionf ExampleBase::Rotation(float x, float y) const +{ + Gs::Matrix3f mat; + Gs::RotateFree(mat, Gs::Vector3f{ 1, 0, 0 }, y); + Gs::RotateFree(mat, Gs::Vector3f{ 0, 1, 0 }, x); + Gs::Quaternionf rotation; + Gs::MatrixToQuaternion(rotation, mat); + return rotation; +} + +Gs::Matrix4f ExampleBase::RotateModel(Gs::Quaternionf& rotation, float dx, float dy) const +{ + // Generate absolute matrix + rotation *= Rotation(dx, dy); + Gs::Matrix4f mat; + Gs::QuaternionToMatrix(mat, rotation); + return mat; +} + bool ExampleBase::Supported(const LLGL::ShadingLanguage shadingLanguage) const { const auto& languages = renderer->GetRenderingCaps().shadingLanguages; diff --git a/examples/Cpp/ExampleBase/ExampleBase.h b/examples/Cpp/ExampleBase/ExampleBase.h index 0b7a942e82..a4214494df 100644 --- a/examples/Cpp/ExampleBase/ExampleBase.h +++ b/examples/Cpp/ExampleBase/ExampleBase.h @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include #include #include @@ -293,10 +291,16 @@ class ExampleBase bool IsScreenOriginLowerLeft() const; // Returns a perspective projection with the specified parameters for the respective renderer. - Gs::Matrix4f PerspectiveProjection(float aspectRatio, float near, float far, float fov); + Gs::Matrix4f PerspectiveProjection(float aspectRatio, float near, float far, float fov) const; // Returns an orthogonal projection with the speciifed parameters for the respective renderer. - Gs::Matrix4f OrthogonalProjection(float width, float height, float near, float far); + Gs::Matrix4f OrthogonalProjection(float width, float height, float near, float far) const; + + // Returns a quoternion for the specified rotation + Gs::Quaternionf Rotation(float x, float y) const; + + // Rotates the specified quaternion for a model-to-world transformation matrix. + Gs::Matrix4f RotateModel(Gs::Quaternionf& rotation, float dx, float dy) const; // Returns true if the specified shading language is supported. bool Supported(const LLGL::ShadingLanguage shadingLanguage) const; diff --git a/examples/Cpp/IndirectDraw/Example.vert.spv b/examples/Cpp/IndirectDraw/Example.vert.spv index 2504308012..f6eaa54df2 100644 Binary files a/examples/Cpp/IndirectDraw/Example.vert.spv and b/examples/Cpp/IndirectDraw/Example.vert.spv differ diff --git a/examples/Cpp/Mapping/Example.cpp b/examples/Cpp/Mapping/Example.cpp index 7f7285f008..b659e813ae 100644 --- a/examples/Cpp/Mapping/Example.cpp +++ b/examples/Cpp/Mapping/Example.cpp @@ -6,13 +6,21 @@ */ #include -#include +#include // Use source textures instead for additional copy indirections -//#define ENABLE_INTERMEDIATE_TEXTURES +#define ENABLE_INTERMEDIATE_TEXTURES 0 +/* + * Texture and buffer mapping example + * ---------------------------------- + * This is a visually unimpressive example that only demonstrates how to copy data between buffers and textures. + * You'll see horizontal stripes of red, green, and blue across the window. + * By pressing the Tab key, you can modify the content in a seemingly unorganized manner. + * By pressing the Backspace key, you can reset the content to its initial state. + */ class Example_Mapping : public ExampleBase { @@ -27,7 +35,7 @@ class Example_Mapping : public ExampleBase LLGL::Buffer* vertexBuffer = nullptr; LLGL::Buffer* contentBuffer = nullptr; // Content buffer which is copied into the textures - #ifdef ENABLE_INTERMEDIATE_TEXTURES + #if ENABLE_INTERMEDIATE_TEXTURES LLGL::Texture* srcTextures[2] = {}; // Source textures for copy operations #endif LLGL::Texture* dstTextures[2] = {}; // Destination textures for display @@ -53,8 +61,10 @@ class Example_Mapping : public ExampleBase GenerateTextureContent(); // Print some information on the standard output - std::cout << "press TAB KEY to iterate copy operations on the texture" << std::endl; - std::cout << "press BACKSPACE KEY to reset the texture" << std::endl; + ::printf( + "press TAB KEY to iterate copy operations on the texture\n" + "press BACKSPACE KEY to reset the texture\n" + ); } private: @@ -93,13 +103,23 @@ class Example_Mapping : public ExampleBase auto MatchReadbackVerticesPosition = [&readbackVertices, &vertices](int v, int c) { if (readbackVertices[v].position[c] != vertices[v].position[c]) - std::cerr << "Readback data mismatch: Expected vertices[" << v << "].position[" << c << "] to be " << vertices[v].position[c] << ", but got " << readbackVertices[v].position[c] << std::endl; + { + ::fprintf( + stderr, "Readback data mismatch: Expected vertices[%d].position[%d] to be %f, but got %f\n", + v, c, vertices[v].position[c], readbackVertices[v].position[c] + ); + } }; auto MatchReadbackVerticesTexCoord = [&readbackVertices, &vertices](int v, int c) { if (readbackVertices[v].texCoord[c] != vertices[v].texCoord[c]) - std::cerr << "Readback data mismatch: Expected vertices[" << v << "].texCoord[" << c << "] to be " << vertices[v].texCoord[c] << ", but got " << readbackVertices[v].texCoord[c] << std::endl; + { + ::fprintf( + stderr, "Readback data mismatch: Expected vertices[%d].texCoord[%d] to be %f, but got %f\n", + v, c, vertices[v].texCoord[c], readbackVertices[v].texCoord[c] + ); + } }; for (int i = 0; i < 8; ++i) @@ -152,7 +172,7 @@ class Example_Mapping : public ExampleBase void CreateSourceTextures() { - #ifdef ENABLE_INTERMEDIATE_TEXTURES + #if ENABLE_INTERMEDIATE_TEXTURES // Create empty destination texture for (int i = 0; i < 2; ++i) @@ -233,7 +253,7 @@ class Example_Mapping : public ExampleBase commands->FillBuffer(*contentBuffer, /*Offset:*/ 128 * 4, /*Value:*/ 0xFF50D040, /*Size:*/ 128 * 4); // Green commands->FillBuffer(*contentBuffer, /*Offset:*/ 256 * 4, /*Value:*/ 0xFFD05050, /*Size:*/ 256 * 4); // Blue - #ifdef ENABLE_INTERMEDIATE_TEXTURES + #if ENABLE_INTERMEDIATE_TEXTURES // Copy buffer to source textures /*commands->CopyTextureFromBuffer( @@ -314,13 +334,11 @@ class Example_Mapping : public ExampleBase auto srcColors = reinterpret_cast(src); { const LLGL::ColorRGBAub srcColor0 = srcColors[0]; - std::cout - << std::setw(2) << std::hex << std::setfill('0') << std::uppercase - << "Left-top color in destination texture:" - << " (#" << static_cast(srcColor0.r) - << ", #" << static_cast(srcColor0.g) - << ", #" << static_cast(srcColor0.b) << ")\r"; - std::flush(std::cout); + ::printf( + "Left-top color in destination texture: (#%02X, #%02X, #%02X)\r", + static_cast(srcColor0.r), static_cast(srcColor0.g), static_cast(srcColor0.b) + ); + ::fflush(stdout); } renderer->UnmapBuffer(*contentBuffer); } diff --git a/examples/Cpp/MultiThreading/Example.cpp b/examples/Cpp/MultiThreading/Example.cpp index ca6e15ec6f..1ee71bebbe 100644 --- a/examples/Cpp/MultiThreading/Example.cpp +++ b/examples/Cpp/MultiThreading/Example.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include // Enables/disables the use of two secondary command buffers @@ -61,15 +61,13 @@ class Measure { if (samples_ > 0) { - auto averageTime = static_cast(elapsed_); + double averageTime = static_cast(elapsed_); averageTime /= static_cast(timer_.GetFrequency()); averageTime *= 1000000.0; averageTime /= static_cast(samples_); - std::cout << title_ << ": "; - std::cout << std::fixed << std::setprecision(6) << averageTime << " microseconds"; - std::cout << " \r"; - std::flush(std::cout); + printf("%s: %.6f microseconds \r", title_.c_str(), averageTime); + fflush(stdout); samples_ = 0; elapsed_ = 0; @@ -204,7 +202,7 @@ class Example_MultiThreading : public ExampleBase static void PrintThreadsafe(std::mutex& mtx, const std::string& text) { std::lock_guard guard { mtx }; - std::cout << text << std::endl; + printf("%s\n", text.c_str()); } static void EncodeSecondaryCommandBuffer( @@ -310,15 +308,7 @@ class Example_MultiThreading : public ExampleBase ); } - #endif // /ENABLE_SECONDARY_COMMAND_BUFFERS - - // Encode primary command buffer - for_range(i, swapChain->GetNumSwapBuffers()) - EncodePrimaryCommandBuffer(*primaryCmdBuffer[i], i, "mainThread"); - - #if ENABLE_SECONDARY_COMMAND_BUFFERS - - // Wait for worker threads to finish + // Secondary command buffers must have finished encoding before we can use them in a primary command buffer for (auto& worker : workerThread) { if (worker.joinable()) @@ -326,6 +316,10 @@ class Example_MultiThreading : public ExampleBase } #endif // /ENABLE_SECONDARY_COMMAND_BUFFERS + + // Encode primary command buffer + for_range(i, swapChain->GetNumSwapBuffers()) + EncodePrimaryCommandBuffer(*primaryCmdBuffer[i], i, "mainThread"); } void Transform(Bundle::Matrices& matrices, const Gs::Vector3f& pos, const Gs::Vector3f& axis, float angle) @@ -336,8 +330,38 @@ class Example_MultiThreading : public ExampleBase matrices.wvpMatrix = projection * matrices.wMatrix; } + void UpdateCommandBuffers() + { + std::thread workerThread[2]; + + for_range(i, 2) + { + // Start worker thread to encode secondary command buffer + workerThread[i] = std::thread( + Example_MultiThreading::EncodeSecondaryCommandBuffer, + std::ref(bundle[i]), + numIndices, + std::ref(logMutex), + "workerThread[" + std::to_string(i) + "]" + ); + } + + // Wait for worker threads to finish + for (auto& worker : workerThread) + { + if (worker.joinable()) + worker.join(); + } + + for_range(i, swapChain->GetNumSwapBuffers()) + EncodePrimaryCommandBuffer(*primaryCmdBuffer[i], i, "mainThread"); + } + void UpdateScene() { + if (input.KeyDown(LLGL::Key::Tab)) + UpdateCommandBuffers(); + // Animate rotation static float rotation; rotation += 0.01f; diff --git a/examples/Cpp/StreamOutput/Example.cpp b/examples/Cpp/StreamOutput/Example.cpp index e23c01077a..cb826b078f 100644 --- a/examples/Cpp/StreamOutput/Example.cpp +++ b/examples/Cpp/StreamOutput/Example.cpp @@ -6,7 +6,7 @@ */ #include -#include +#include class Example_StreamOutput : public ExampleBase @@ -131,8 +131,10 @@ class Example_StreamOutput : public ExampleBase void PrintOutputVector(std::size_t index, const Gs::Vector4f* outputVectors) { const auto& v = outputVectors[index]; - std::cout << std::fixed << std::setfill('0') << std::setprecision(2); - std::cout << "SV_Position[" << index << "] = " << v.x << ", " << v.y << ", " << v.z << ", " << v.w << " \r"; + ::printf( + "SV_Position[%d] = %.02f, %.02f, %.02f, %.02f \r", + static_cast(index), v.x, v.y, v.z, v.w + ); } void OnDrawFrame() override @@ -192,7 +194,7 @@ class Example_StreamOutput : public ExampleBase { // Print output data PrintOutputVector(1, reinterpret_cast(outputBuffer)); - std::flush(std::cout); + ::fflush(stdout); // Unmap buffer renderer->UnmapBuffer(*streamOutputBuffer);