2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "test-graphics-controller.h"
19 #include "test-graphics-buffer.h"
20 #include "test-graphics-command-buffer.h"
21 #include "test-graphics-sampler.h"
22 #include "test-graphics-texture.h"
24 #include <dali/integration-api/gl-defines.h>
32 T* Uncast(const Graphics::CommandBuffer* object)
34 return const_cast<T*>(static_cast<const T*>(object));
38 T* Uncast(const Graphics::Texture* object)
40 return const_cast<T*>(static_cast<const T*>(object));
44 T* Uncast(const Graphics::Sampler* object)
46 return const_cast<T*>(static_cast<const T*>(object));
50 T* Uncast(const Graphics::Buffer* object)
52 return const_cast<T*>(static_cast<const T*>(object));
55 std::ostream& operator<<(std::ostream& o, const Graphics::BufferCreateInfo& bufferCreateInfo)
57 return o << "usage:" << std::hex << bufferCreateInfo.usage << ", size:" << std::dec << bufferCreateInfo.size;
60 std::ostream& operator<<(std::ostream& o, const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo)
62 return o << "level:" << (commandBufferCreateInfo.level == Graphics::CommandBufferLevel::PRIMARY ? "PRIMARY" : "SECONDARY")
63 << ", fixedCapacity:" << std::dec << commandBufferCreateInfo.fixedCapacity;
66 std::ostream& operator<<(std::ostream& o, const Graphics::TextureType& textureType)
70 case Graphics::TextureType::TEXTURE_2D:
73 case Graphics::TextureType::TEXTURE_3D:
76 case Graphics::TextureType::TEXTURE_CUBEMAP:
77 o << "TEXTURE_CUBEMAP";
83 std::ostream& operator<<(std::ostream& o, const Graphics::Extent2D extent)
85 o << "width:" << extent.width << ", height:" << extent.height;
89 std::ostream& operator<<(std::ostream& o, const Graphics::TextureCreateInfo& createInfo)
91 o << "textureType:" << createInfo.textureType
92 << " size:" << createInfo.size
93 << " format:" << static_cast<uint32_t>(createInfo.format)
94 << " mipMapFlag:" << createInfo.mipMapFlag
95 << " layout:" << (createInfo.layout == Graphics::TextureLayout::LINEAR ? "LINEAR" : "OPTIMAL")
96 << " usageFlags:" << std::hex << createInfo.usageFlags
97 << " data:" << std::hex << createInfo.data
98 << " dataSize:" << std::dec << createInfo.dataSize
99 << " nativeImagePtr:" << std::hex << createInfo.nativeImagePtr;
103 std::ostream& operator<<(std::ostream& o, Graphics::SamplerAddressMode addressMode)
107 case Graphics::SamplerAddressMode::REPEAT:
110 case Graphics::SamplerAddressMode::MIRRORED_REPEAT:
111 o << "MIRRORED_REPEAT";
113 case Graphics::SamplerAddressMode::CLAMP_TO_EDGE:
114 o << "CLAMP_TO_EDGE";
116 case Graphics::SamplerAddressMode::CLAMP_TO_BORDER:
117 o << "CLAMP_TO_BORDER";
119 case Graphics::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE:
120 o << "MIRROR_CLAMP_TO_EDGE";
126 std::ostream& operator<<(std::ostream& o, Graphics::SamplerFilter filterMode)
130 case Graphics::SamplerFilter::LINEAR:
133 case Graphics::SamplerFilter::NEAREST:
140 std::ostream& operator<<(std::ostream& o, Graphics::SamplerMipmapMode mipmapMode)
144 case Graphics::SamplerMipmapMode::NONE:
147 case Graphics::SamplerMipmapMode::LINEAR:
150 case Graphics::SamplerMipmapMode::NEAREST:
157 std::ostream& operator<<(std::ostream& o, const Graphics::SamplerCreateInfo& createInfo)
159 o << "minFilter:" << createInfo.minFilter
160 << " magFilter:" << createInfo.magFilter
161 << " wrapModeU:" << createInfo.addressModeU
162 << " wrapModeV:" << createInfo.addressModeV
163 << " wrapModeW:" << createInfo.addressModeW
164 << " mipMapMode:" << createInfo.mipMapMode;
168 class TestGraphicsMemory : public Graphics::Memory
171 TestGraphicsMemory(TraceCallStack& callStack, TestGraphicsBuffer& buffer, uint32_t mappedOffset, uint32_t mappedSize)
172 : mCallStack(callStack),
174 mMappedOffset(mappedOffset),
175 mMappedSize(mappedSize)
179 void* LockRegion(uint32_t offset, uint32_t size) override
181 std::ostringstream o;
182 o << offset << ", " << size;
183 mCallStack.PushCall("Memory::LockRegion", o.str());
185 if(offset > mMappedOffset + mMappedSize ||
186 size + offset > mMappedOffset + mMappedSize)
188 fprintf(stderr, "TestGraphics.Memory::LockRegion() Out of bounds");
189 mBuffer.memory.resize(mMappedOffset + offset + size); // Grow to prevent memcpy from crashing
191 mLockedOffset = offset;
193 return &mBuffer.memory[mMappedOffset + offset];
196 void Unlock(bool flush) override
198 mCallStack.PushCall("Memory::Unlock", (flush ? "Flush" : "NoFlush"));
205 void Flush() override
207 mCallStack.PushCall("Memory::Flush", "");
209 mBuffer.Upload(mMappedOffset + mLockedOffset, mLockedSize);
213 TraceCallStack& mCallStack;
214 TestGraphicsBuffer& mBuffer;
215 uint32_t mMappedOffset;
216 uint32_t mMappedSize;
217 uint32_t mLockedOffset;
218 uint32_t mLockedSize;
221 TestGraphicsController::TestGraphicsController()
222 : mCallStack(true, "TestGraphicsController."),
223 mCommandBufferCallStack(true, "TestCommandBuffer.")
225 mCallStack.Enable(true);
226 mCommandBufferCallStack.Enable(true);
227 auto& trace = mGl.GetTextureTrace();
229 trace.EnableLogging(true);
232 int GetNumComponents(Graphics::VertexInputFormat vertexFormat)
236 case Graphics::VertexInputFormat::UNDEFINED:
237 case Graphics::VertexInputFormat::FLOAT:
238 case Graphics::VertexInputFormat::INTEGER:
240 case Graphics::VertexInputFormat::IVECTOR2:
241 case Graphics::VertexInputFormat::FVECTOR2:
243 case Graphics::VertexInputFormat::IVECTOR3:
244 case Graphics::VertexInputFormat::FVECTOR3:
246 case Graphics::VertexInputFormat::FVECTOR4:
247 case Graphics::VertexInputFormat::IVECTOR4:
253 GLint GetSize(Graphics::VertexInputFormat vertexFormat)
257 case Graphics::VertexInputFormat::UNDEFINED:
259 case Graphics::VertexInputFormat::INTEGER:
260 case Graphics::VertexInputFormat::IVECTOR2:
261 case Graphics::VertexInputFormat::IVECTOR3:
262 case Graphics::VertexInputFormat::IVECTOR4:
264 case Graphics::VertexInputFormat::FLOAT:
265 case Graphics::VertexInputFormat::FVECTOR2:
266 case Graphics::VertexInputFormat::FVECTOR3:
267 case Graphics::VertexInputFormat::FVECTOR4:
273 GLint GetGlType(Graphics::VertexInputFormat vertexFormat)
277 case Graphics::VertexInputFormat::UNDEFINED:
279 case Graphics::VertexInputFormat::INTEGER:
280 case Graphics::VertexInputFormat::IVECTOR2:
281 case Graphics::VertexInputFormat::IVECTOR3:
282 case Graphics::VertexInputFormat::IVECTOR4:
284 case Graphics::VertexInputFormat::FLOAT:
285 case Graphics::VertexInputFormat::FVECTOR2:
286 case Graphics::VertexInputFormat::FVECTOR3:
287 case Graphics::VertexInputFormat::FVECTOR4:
293 GLenum GetTopology(Graphics::PrimitiveTopology topology)
297 case Graphics::PrimitiveTopology::POINT_LIST:
300 case Graphics::PrimitiveTopology::LINE_LIST:
303 case Graphics::PrimitiveTopology::LINE_LOOP:
306 case Graphics::PrimitiveTopology::LINE_STRIP:
307 return GL_LINE_STRIP;
309 case Graphics::PrimitiveTopology::TRIANGLE_LIST:
312 case Graphics::PrimitiveTopology::TRIANGLE_STRIP:
313 return GL_TRIANGLE_STRIP;
315 case Graphics::PrimitiveTopology::TRIANGLE_FAN:
316 return GL_TRIANGLE_FAN;
321 void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo)
323 TraceCallStack::NamedParams namedParams;
324 namedParams["submitInfo"] << "cmdBuffer[" << submitInfo.cmdBuffer.size()
325 << "], flags:" << std::hex << submitInfo.flags;
327 mCallStack.PushCall("Controller::SubmitCommandBuffers", "", namedParams);
329 for(auto& graphicsCommandBuffer : submitInfo.cmdBuffer)
331 auto commandBuffer = Uncast<TestGraphicsCommandBuffer>(graphicsCommandBuffer);
332 for(auto& binding : commandBuffer->mTextureBindings)
336 auto texture = Uncast<TestGraphicsTexture>(binding.texture);
338 texture->Bind(binding.binding);
342 auto sampler = Uncast<TestGraphicsSampler>(binding.sampler);
345 sampler->Apply(texture->GetTarget());
349 texture->Prepare(); // Ensure native texture is ready
353 // IndexBuffer binding,
354 auto& indexBufferBinding = commandBuffer->mIndexBufferBinding;
355 if(indexBufferBinding.buffer)
357 auto buffer = Uncast<TestGraphicsBuffer>(indexBufferBinding.buffer);
361 // VertexBuffer binding,
362 for(auto graphicsBuffer : commandBuffer->mVertexBufferBindings.buffers)
364 auto vertexBuffer = Uncast<TestGraphicsBuffer>(graphicsBuffer);
365 vertexBuffer->Bind();
368 // Pipeline attribute setup
369 auto& vi = commandBuffer->mPipeline->vertexInputState;
370 for(auto& attribute : vi.attributes)
372 mGl.EnableVertexAttribArray(attribute.location);
373 uint32_t attributeOffset = attribute.offset;
374 GLsizei stride = vi.bufferBindings[attribute.binding].stride;
376 mGl.VertexAttribPointer(attribute.location,
377 GetNumComponents(attribute.format),
378 GetGlType(attribute.format),
379 GL_FALSE, // Not normalized
381 reinterpret_cast<void*>(attributeOffset));
385 auto topology = commandBuffer->mPipeline->inputAssemblyState.topology;
387 if(commandBuffer->drawCommand.drawType == TestGraphicsCommandBuffer::Draw::DrawType::Indexed)
389 mGl.DrawElements(GetTopology(topology),
390 static_cast<GLsizei>(commandBuffer->drawCommand.u.indexedDraw.indexCount),
392 reinterpret_cast<void*>(commandBuffer->drawCommand.u.indexedDraw.firstIndex));
396 mGl.DrawArrays(GetTopology(topology), 0, commandBuffer->drawCommand.u.unindexedDraw.vertexCount);
400 for(auto& attribute : vi.attributes)
402 mGl.DisableVertexAttribArray(attribute.location);
408 * @brief Presents render target
409 * @param renderTarget render target to present
411 void TestGraphicsController::PresentRenderTarget(Graphics::RenderTarget* renderTarget)
413 TraceCallStack::NamedParams namedParams;
414 namedParams["renderTarget"] << std::hex << renderTarget;
415 mCallStack.PushCall("Controller::PresentRenderTarget", "", namedParams);
419 * @brief Waits until the GPU is idle
421 void TestGraphicsController::WaitIdle()
423 mCallStack.PushCall("Controller::WaitIdle", "");
427 * @brief Lifecycle pause event
429 void TestGraphicsController::Pause()
431 mCallStack.PushCall("Controller::Pause", "");
435 * @brief Lifecycle resume event
437 void TestGraphicsController::Resume()
439 mCallStack.PushCall("Controller::Resume", "");
442 void TestGraphicsController::UpdateTextures(const std::vector<Graphics::TextureUpdateInfo>& updateInfoList,
443 const std::vector<Graphics::TextureUpdateSourceInfo>& sourceList)
445 TraceCallStack::NamedParams namedParams;
446 namedParams["updateInfoList"] << "[" << updateInfoList.size() << "]:";
447 namedParams["sourceList"] << "[" << sourceList.size() << "]:";
449 mCallStack.PushCall("Controller::UpdateTextures", "", namedParams);
451 // Call either TexImage2D or TexSubImage2D
452 for(unsigned int i = 0; i < updateInfoList.size(); ++i)
454 auto& updateInfo = updateInfoList[i];
455 auto& source = sourceList[i];
457 auto texture = static_cast<TestGraphicsTexture*>(updateInfo.dstTexture);
458 texture->Bind(0); // Use first texture unit during resource update
459 texture->Update(updateInfo, source);
463 bool TestGraphicsController::EnableDepthStencilBuffer(bool enableDepth, bool enableStencil)
465 TraceCallStack::NamedParams namedParams;
466 namedParams["enableDepth"] << (enableDepth ? "T" : "F");
467 namedParams["enableStencil"] << (enableStencil ? "T" : "F");
468 mCallStack.PushCall("Controller::EnableDepthStencilBuffer", "", namedParams);
472 void TestGraphicsController::RunGarbageCollector(size_t numberOfDiscardedRenderers)
474 TraceCallStack::NamedParams namedParams;
475 namedParams["numberOfDiscardedRenderers"] << numberOfDiscardedRenderers;
476 mCallStack.PushCall("Controller::RunGarbageCollector", "", namedParams);
479 void TestGraphicsController::DiscardUnusedResources()
481 mCallStack.PushCall("Controller::DiscardUnusedResources", "");
484 bool TestGraphicsController::IsDiscardQueueEmpty()
486 mCallStack.PushCall("Controller::IsDiscardQueueEmpty", "");
487 return isDiscardQueueEmptyResult;
491 * @brief Test if the graphics subsystem has resumed & should force a draw
493 * @return true if the graphics subsystem requires a re-draw
495 bool TestGraphicsController::IsDrawOnResumeRequired()
497 mCallStack.PushCall("Controller::IsDrawOnResumeRequired", "");
498 return isDrawOnResumeRequiredResult;
501 Graphics::UniquePtr<Graphics::Buffer> TestGraphicsController::CreateBuffer(const Graphics::BufferCreateInfo& createInfo, Graphics::UniquePtr<Graphics::Buffer>&& oldBuffer)
503 std::ostringstream oss;
504 oss << "bufferCreateInfo:" << createInfo;
505 mCallStack.PushCall("Controller::CreateBuffer", oss.str());
506 return Graphics::MakeUnique<TestGraphicsBuffer>(mCallStack, mGl, createInfo.size, createInfo.usage);
509 Graphics::UniquePtr<Graphics::CommandBuffer> TestGraphicsController::CreateCommandBuffer(const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo, Graphics::UniquePtr<Graphics::CommandBuffer>&& oldCommandBuffer)
511 std::ostringstream oss;
512 oss << "commandBufferCreateInfo:" << commandBufferCreateInfo;
513 mCallStack.PushCall("Controller::CreateCommandBuffer", oss.str());
514 return Graphics::MakeUnique<TestGraphicsCommandBuffer>(mCommandBufferCallStack, mGl);
517 Graphics::UniquePtr<Graphics::RenderPass> TestGraphicsController::CreateRenderPass(const Graphics::RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<Graphics::RenderPass>&& oldRenderPass)
519 mCallStack.PushCall("Controller::CreateRenderPass", "");
523 Graphics::UniquePtr<Graphics::Texture> TestGraphicsController::CreateTexture(const Graphics::TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Graphics::Texture>&& oldTexture)
525 TraceCallStack::NamedParams namedParams;
526 namedParams["textureCreateInfo"] << textureCreateInfo;
527 mCallStack.PushCall("Controller::CreateTexture", namedParams.str(), namedParams);
529 return Graphics::MakeUnique<TestGraphicsTexture>(mGl, textureCreateInfo);
532 Graphics::UniquePtr<Graphics::Framebuffer> TestGraphicsController::CreateFramebuffer(const Graphics::FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Graphics::Framebuffer>&& oldFramebuffer)
534 mCallStack.PushCall("Controller::CreateFramebuffer", "");
538 Graphics::UniquePtr<Graphics::Pipeline> TestGraphicsController::CreatePipeline(const Graphics::PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
540 mCallStack.PushCall("Controller::CreatePipeline", "");
541 return std::make_unique<TestGraphicsPipeline>(mGl, pipelineCreateInfo);
544 Graphics::UniquePtr<Graphics::Shader> TestGraphicsController::CreateShader(const Graphics::ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Graphics::Shader>&& oldShader)
546 mCallStack.PushCall("Controller::CreateShader", "");
550 Graphics::UniquePtr<Graphics::Sampler> TestGraphicsController::CreateSampler(const Graphics::SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Graphics::Sampler>&& oldSampler)
552 TraceCallStack::NamedParams namedParams;
553 namedParams["samplerCreateInfo"] << samplerCreateInfo;
554 mCallStack.PushCall("Controller::CreateSampler", namedParams.str(), namedParams);
556 return Graphics::MakeUnique<TestGraphicsSampler>(mGl, samplerCreateInfo);
559 Graphics::UniquePtr<Graphics::RenderTarget> TestGraphicsController::CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<Graphics::RenderTarget>&& oldRenderTarget)
561 mCallStack.PushCall("Controller::CreateRenderTarget", "");
565 Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapBufferRange(const Graphics::MapBufferInfo& mapInfo)
567 mCallStack.PushCall("Controller::MapBufferRange", "");
569 auto buffer = static_cast<TestGraphicsBuffer*>(mapInfo.buffer);
570 buffer->memory.resize(mapInfo.offset + mapInfo.size); // For initial testing, allow writes past capacity
572 return std::make_unique<TestGraphicsMemory>(mCallStack, *buffer, mapInfo.offset, mapInfo.size);
575 Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapTextureRange(const Graphics::MapTextureInfo& mapInfo)
577 mCallStack.PushCall("Controller::MapTextureRange", "");
581 void TestGraphicsController::UnmapMemory(Graphics::UniquePtr<Graphics::Memory> memory)
583 mCallStack.PushCall("Controller::UnmapMemory", "");
586 Graphics::MemoryRequirements TestGraphicsController::GetTextureMemoryRequirements(Graphics::Texture& texture) const
588 mCallStack.PushCall("Controller::GetTextureMemoryRequirements", "");
589 return Graphics::MemoryRequirements{};
592 Graphics::MemoryRequirements TestGraphicsController::GetBufferMemoryRequirements(Graphics::Buffer& buffer) const
594 mCallStack.PushCall("Controller::GetBufferMemoryRequirements", "");
595 return Graphics::MemoryRequirements{};
598 const Graphics::TextureProperties& TestGraphicsController::GetTextureProperties(const Graphics::Texture& texture)
600 static Graphics::TextureProperties textureProperties{};
601 mCallStack.PushCall("Controller::GetTextureProperties", "");
603 return textureProperties;
606 bool TestGraphicsController::PipelineEquals(const Graphics::Pipeline& pipeline0, const Graphics::Pipeline& pipeline1) const
608 mCallStack.PushCall("Controller::PipelineEquals", "");