Test harness updates
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit / dali-toolkit-test-utils / test-graphics-controller.cpp
index 4732a9a..adacc11 100644 (file)
 
 #include "test-graphics-buffer.h"
 #include "test-graphics-command-buffer.h"
+#include "test-graphics-reflection.h"
 #include "test-graphics-sampler.h"
+#include "test-graphics-shader.h"
 #include "test-graphics-texture.h"
 
 #include <dali/integration-api/gl-defines.h>
+#include <cstdio>
 #include <iostream>
 #include <sstream>
 
 namespace Dali
 {
+template<typename T>
+T* Uncast(const Graphics::CommandBuffer* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Texture* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Sampler* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Buffer* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
 std::ostream& operator<<(std::ostream& o, const Graphics::BufferCreateInfo& bufferCreateInfo)
 {
   return o << "usage:" << std::hex << bufferCreateInfo.usage << ", size:" << std::dec << bufferCreateInfo.size;
@@ -140,39 +167,302 @@ std::ostream& operator<<(std::ostream& o, const Graphics::SamplerCreateInfo& cre
   return o;
 }
 
+class TestGraphicsMemory : public Graphics::Memory
+{
+public:
+  TestGraphicsMemory(TraceCallStack& callStack, TestGraphicsBuffer& buffer, uint32_t mappedOffset, uint32_t mappedSize)
+  : mCallStack(callStack),
+    mBuffer(buffer),
+    mMappedOffset(mappedOffset),
+    mMappedSize(mappedSize)
+  {
+  }
+
+  void* LockRegion(uint32_t offset, uint32_t size) override
+  {
+    std::ostringstream o;
+    o << offset << ", " << size;
+    mCallStack.PushCall("Memory::LockRegion", o.str());
+
+    if(offset > mMappedOffset + mMappedSize ||
+       size + offset > mMappedOffset + mMappedSize)
+    {
+      fprintf(stderr, "TestGraphics.Memory::LockRegion() Out of bounds");
+      mBuffer.memory.resize(mMappedOffset + offset + size); // Grow to prevent memcpy from crashing
+    }
+    mLockedOffset = offset;
+    mLockedSize   = size;
+    return &mBuffer.memory[mMappedOffset + offset];
+  }
+
+  void Unlock(bool flush) override
+  {
+    mCallStack.PushCall("Memory::Unlock", (flush ? "Flush" : "NoFlush"));
+    if(flush)
+    {
+      Flush();
+    }
+  }
+
+  void Flush() override
+  {
+    mCallStack.PushCall("Memory::Flush", "");
+    mBuffer.Bind();
+    mBuffer.Upload(mMappedOffset + mLockedOffset, mLockedSize);
+    mBuffer.Unbind();
+  }
+
+  TraceCallStack&     mCallStack;
+  TestGraphicsBuffer& mBuffer;
+  uint32_t            mMappedOffset;
+  uint32_t            mMappedSize;
+  uint32_t            mLockedOffset;
+  uint32_t            mLockedSize;
+};
+
 TestGraphicsController::TestGraphicsController()
+: mCallStack(true, "TestGraphicsController."),
+  mCommandBufferCallStack(true, "TestCommandBuffer.")
 {
   mCallStack.Enable(true);
-  mCallStack.EnableLogging(true);
   mCommandBufferCallStack.Enable(true);
-  mCommandBufferCallStack.EnableLogging(true);
-  auto& trace = mGlAbstraction.GetTextureTrace();
+  auto& trace = mGl.GetTextureTrace();
   trace.Enable(true);
   trace.EnableLogging(true);
 }
 
+int GetNumComponents(Graphics::VertexInputFormat vertexFormat)
+{
+  switch(vertexFormat)
+  {
+    case Graphics::VertexInputFormat::UNDEFINED:
+    case Graphics::VertexInputFormat::FLOAT:
+    case Graphics::VertexInputFormat::INTEGER:
+      return 1;
+    case Graphics::VertexInputFormat::IVECTOR2:
+    case Graphics::VertexInputFormat::FVECTOR2:
+      return 2;
+    case Graphics::VertexInputFormat::IVECTOR3:
+    case Graphics::VertexInputFormat::FVECTOR3:
+      return 3;
+    case Graphics::VertexInputFormat::FVECTOR4:
+    case Graphics::VertexInputFormat::IVECTOR4:
+      return 4;
+  }
+  return 1;
+}
+
+GLint GetSize(Graphics::VertexInputFormat vertexFormat)
+{
+  switch(vertexFormat)
+  {
+    case Graphics::VertexInputFormat::UNDEFINED:
+      return 1u;
+    case Graphics::VertexInputFormat::INTEGER:
+    case Graphics::VertexInputFormat::IVECTOR2:
+    case Graphics::VertexInputFormat::IVECTOR3:
+    case Graphics::VertexInputFormat::IVECTOR4:
+      return 2u;
+    case Graphics::VertexInputFormat::FLOAT:
+    case Graphics::VertexInputFormat::FVECTOR2:
+    case Graphics::VertexInputFormat::FVECTOR3:
+    case Graphics::VertexInputFormat::FVECTOR4:
+      return 4u;
+  }
+  return 1u;
+}
+
+GLint GetGlType(Graphics::VertexInputFormat vertexFormat)
+{
+  switch(vertexFormat)
+  {
+    case Graphics::VertexInputFormat::UNDEFINED:
+      return GL_BYTE;
+    case Graphics::VertexInputFormat::INTEGER:
+    case Graphics::VertexInputFormat::IVECTOR2:
+    case Graphics::VertexInputFormat::IVECTOR3:
+    case Graphics::VertexInputFormat::IVECTOR4:
+      return GL_SHORT;
+    case Graphics::VertexInputFormat::FLOAT:
+    case Graphics::VertexInputFormat::FVECTOR2:
+    case Graphics::VertexInputFormat::FVECTOR3:
+    case Graphics::VertexInputFormat::FVECTOR4:
+      return GL_FLOAT;
+  }
+  return GL_BYTE;
+}
+
+GLenum GetTopology(Graphics::PrimitiveTopology topology)
+{
+  switch(topology)
+  {
+    case Graphics::PrimitiveTopology::POINT_LIST:
+      return GL_POINTS;
+
+    case Graphics::PrimitiveTopology::LINE_LIST:
+      return GL_LINES;
+
+    case Graphics::PrimitiveTopology::LINE_LOOP:
+      return GL_LINE_LOOP;
+
+    case Graphics::PrimitiveTopology::LINE_STRIP:
+      return GL_LINE_STRIP;
+
+    case Graphics::PrimitiveTopology::TRIANGLE_LIST:
+      return GL_TRIANGLES;
+
+    case Graphics::PrimitiveTopology::TRIANGLE_STRIP:
+      return GL_TRIANGLE_STRIP;
+
+    case Graphics::PrimitiveTopology::TRIANGLE_FAN:
+      return GL_TRIANGLE_FAN;
+  }
+  return GL_TRIANGLES;
+}
+
+GLenum GetCullFace(Graphics::CullMode cullMode)
+{
+  switch(cullMode)
+  {
+    case Graphics::CullMode::NONE:
+      return GL_NONE;
+    case Graphics::CullMode::FRONT:
+      return GL_FRONT;
+    case Graphics::CullMode::BACK:
+      return GL_BACK;
+    case Graphics::CullMode::FRONT_AND_BACK:
+      return GL_FRONT_AND_BACK;
+  }
+  return GL_NONE;
+}
+
+GLenum GetFrontFace(Graphics::FrontFace frontFace)
+{
+  if(frontFace == Graphics::FrontFace::CLOCKWISE)
+  {
+    return GL_CW;
+  }
+  return GL_CCW;
+}
+
+GLenum GetBlendFactor(Graphics::BlendFactor blendFactor)
+{
+  GLenum glFactor = GL_ZERO;
+
+  switch(blendFactor)
+  {
+    case Graphics::BlendFactor::ZERO:
+      glFactor = GL_ZERO;
+      break;
+    case Graphics::BlendFactor::ONE:
+      glFactor = GL_ONE;
+      break;
+    case Graphics::BlendFactor::SRC_COLOR:
+      glFactor = GL_SRC_COLOR;
+      break;
+    case Graphics::BlendFactor::ONE_MINUS_SRC_COLOR:
+      glFactor = GL_ONE_MINUS_SRC_COLOR;
+      break;
+    case Graphics::BlendFactor::DST_COLOR:
+      glFactor = GL_DST_COLOR;
+      break;
+    case Graphics::BlendFactor::ONE_MINUS_DST_COLOR:
+      glFactor = GL_ONE_MINUS_DST_COLOR;
+      break;
+    case Graphics::BlendFactor::SRC_ALPHA:
+      glFactor = GL_SRC_ALPHA;
+      break;
+    case Graphics::BlendFactor::ONE_MINUS_SRC_ALPHA:
+      glFactor = GL_ONE_MINUS_SRC_ALPHA;
+      break;
+    case Graphics::BlendFactor::DST_ALPHA:
+      glFactor = GL_DST_ALPHA;
+      break;
+    case Graphics::BlendFactor::ONE_MINUS_DST_ALPHA:
+      glFactor = GL_ONE_MINUS_DST_ALPHA;
+      break;
+    case Graphics::BlendFactor::CONSTANT_COLOR:
+      glFactor = GL_CONSTANT_COLOR;
+      break;
+    case Graphics::BlendFactor::ONE_MINUS_CONSTANT_COLOR:
+      glFactor = GL_ONE_MINUS_CONSTANT_COLOR;
+      break;
+    case Graphics::BlendFactor::CONSTANT_ALPHA:
+      glFactor = GL_CONSTANT_ALPHA;
+      break;
+    case Graphics::BlendFactor::ONE_MINUS_CONSTANT_ALPHA:
+      glFactor = GL_ONE_MINUS_CONSTANT_ALPHA;
+      break;
+    case Graphics::BlendFactor::SRC_ALPHA_SATURATE:
+      glFactor = GL_SRC_ALPHA_SATURATE;
+      break;
+      // GLES doesn't appear to have dual source blending.
+    case Graphics::BlendFactor::SRC1_COLOR:
+      glFactor = GL_SRC_COLOR;
+      break;
+    case Graphics::BlendFactor::ONE_MINUS_SRC1_COLOR:
+      glFactor = GL_ONE_MINUS_SRC_COLOR;
+      break;
+    case Graphics::BlendFactor::SRC1_ALPHA:
+      glFactor = GL_SRC_ALPHA;
+      break;
+    case Graphics::BlendFactor::ONE_MINUS_SRC1_ALPHA:
+      glFactor = GL_ONE_MINUS_SRC_ALPHA;
+      break;
+  }
+  return glFactor;
+}
+
+GLenum GetBlendOp(Graphics::BlendOp blendOp)
+{
+  GLenum op = GL_FUNC_ADD;
+  switch(blendOp)
+  {
+    case Graphics::BlendOp::ADD:
+      op = GL_FUNC_ADD;
+      break;
+    case Graphics::BlendOp::SUBTRACT:
+      op = GL_FUNC_SUBTRACT;
+      break;
+    case Graphics::BlendOp::REVERSE_SUBTRACT:
+      op = GL_FUNC_REVERSE_SUBTRACT;
+      break;
+    case Graphics::BlendOp::MIN:
+      op = GL_MIN;
+      break;
+    case Graphics::BlendOp::MAX:
+      op = GL_MAX;
+      break;
+
+      // @todo Add advanced blend equations
+  }
+  return op;
+}
+
 void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo)
 {
-  std::ostringstream          out;
   TraceCallStack::NamedParams namedParams;
-  out << "cmdBuffer[" << submitInfo.cmdBuffer.size() << "], flags:" << std::hex << submitInfo.flags;
-  namedParams["submitInfo"] = out.str();
+  namedParams["submitInfo"] << "cmdBuffer[" << submitInfo.cmdBuffer.size()
+                            << "], flags:" << std::hex << submitInfo.flags;
 
   mCallStack.PushCall("SubmitCommandBuffers", "", namedParams);
 
-  for(auto& commandBuffer : submitInfo.cmdBuffer)
+  mSubmitStack.emplace_back(submitInfo);
+
+  for(auto& graphicsCommandBuffer : submitInfo.cmdBuffer)
   {
-    for(auto& binding : (static_cast<TestGraphicsCommandBuffer*>(commandBuffer))->mTextureBindings)
+    auto commandBuffer = Uncast<TestGraphicsCommandBuffer>(graphicsCommandBuffer);
+    for(auto& binding : commandBuffer->mTextureBindings)
     {
       if(binding.texture)
       {
-        auto texture = const_cast<TestGraphicsTexture*>(static_cast<const TestGraphicsTexture*>(binding.texture));
+        auto texture = Uncast<TestGraphicsTexture>(binding.texture);
 
         texture->Bind(binding.binding);
 
         if(binding.sampler)
         {
-          auto sampler = const_cast<TestGraphicsSampler*>(static_cast<const TestGraphicsSampler*>(binding.sampler));
+          auto sampler = Uncast<TestGraphicsSampler>(binding.sampler);
           if(sampler)
           {
             sampler->Apply(texture->GetTarget());
@@ -182,6 +472,102 @@ void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& su
         texture->Prepare(); // Ensure native texture is ready
       }
     }
+
+    // IndexBuffer binding,
+    auto& indexBufferBinding = commandBuffer->mIndexBufferBinding;
+    if(indexBufferBinding.buffer)
+    {
+      auto buffer = Uncast<TestGraphicsBuffer>(indexBufferBinding.buffer);
+      buffer->Bind();
+    }
+
+    // VertexBuffer binding,
+    for(auto graphicsBuffer : commandBuffer->mVertexBufferBindings.buffers)
+    {
+      auto vertexBuffer = Uncast<TestGraphicsBuffer>(graphicsBuffer);
+      vertexBuffer->Bind();
+    }
+
+    // Pipeline attribute setup
+    auto& vi = commandBuffer->mPipeline->vertexInputState;
+    for(auto& attribute : vi.attributes)
+    {
+      mGl.EnableVertexAttribArray(attribute.location);
+      uint32_t attributeOffset = attribute.offset;
+      GLsizei  stride          = vi.bufferBindings[attribute.binding].stride;
+
+      mGl.VertexAttribPointer(attribute.location,
+                              GetNumComponents(attribute.format),
+                              GetGlType(attribute.format),
+                              GL_FALSE, // Not normalized
+                              stride,
+                              reinterpret_cast<void*>(attributeOffset));
+    }
+
+    // Cull face setup
+    auto& rasterizationState = commandBuffer->mPipeline->rasterizationState;
+    if(rasterizationState.cullMode == Graphics::CullMode::NONE)
+    {
+      mGl.Disable(GL_CULL_FACE);
+    }
+    else
+    {
+      mGl.Enable(GL_CULL_FACE);
+      mGl.CullFace(GetCullFace(rasterizationState.cullMode));
+    }
+
+    mGl.FrontFace(GetFrontFace(rasterizationState.frontFace));
+    // We don't modify glPolygonMode in our context/abstraction from GL_FILL (the GL default),
+    // so it isn't present in the API (and won't have any tests!)
+
+    // Blending setup
+    auto& colorBlendState = commandBuffer->mPipeline->colorBlendState;
+    if(colorBlendState.blendEnable)
+    {
+      mGl.Enable(GL_BLEND);
+
+      mGl.BlendFuncSeparate(GetBlendFactor(colorBlendState.srcColorBlendFactor),
+                            GetBlendFactor(colorBlendState.dstColorBlendFactor),
+                            GetBlendFactor(colorBlendState.srcAlphaBlendFactor),
+                            GetBlendFactor(colorBlendState.dstAlphaBlendFactor));
+      if(colorBlendState.colorBlendOp != colorBlendState.alphaBlendOp)
+      {
+        mGl.BlendEquationSeparate(GetBlendOp(colorBlendState.colorBlendOp), GetBlendOp(colorBlendState.alphaBlendOp));
+      }
+      else
+      {
+        mGl.BlendEquation(GetBlendOp(colorBlendState.colorBlendOp));
+      }
+      mGl.BlendColor(colorBlendState.blendConstants[0],
+                     colorBlendState.blendConstants[1],
+                     colorBlendState.blendConstants[2],
+                     colorBlendState.blendConstants[3]);
+    }
+    else
+    {
+      mGl.Disable(GL_BLEND);
+    }
+
+    // draw call
+    auto topology = commandBuffer->mPipeline->inputAssemblyState.topology;
+
+    if(commandBuffer->drawCommand.drawType == TestGraphicsCommandBuffer::Draw::DrawType::Indexed)
+    {
+      mGl.DrawElements(GetTopology(topology),
+                       static_cast<GLsizei>(commandBuffer->drawCommand.u.indexedDraw.indexCount),
+                       GL_UNSIGNED_SHORT,
+                       reinterpret_cast<void*>(commandBuffer->drawCommand.u.indexedDraw.firstIndex));
+    }
+    else
+    {
+      mGl.DrawArrays(GetTopology(topology), 0, commandBuffer->drawCommand.u.unindexedDraw.vertexCount);
+    }
+
+    // attribute clear
+    for(auto& attribute : vi.attributes)
+    {
+      mGl.DisableVertexAttribArray(attribute.location);
+    }
   }
 }
 
@@ -191,10 +577,8 @@ void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& su
  */
 void TestGraphicsController::PresentRenderTarget(Graphics::RenderTarget* renderTarget)
 {
-  std::ostringstream          out;
   TraceCallStack::NamedParams namedParams;
-  out << std::hex << renderTarget;
-  namedParams["renderTarget"] = out.str();
+  namedParams["renderTarget"] << std::hex << renderTarget;
   mCallStack.PushCall("PresentRenderTarget", "", namedParams);
 }
 
@@ -225,13 +609,9 @@ void TestGraphicsController::Resume()
 void TestGraphicsController::UpdateTextures(const std::vector<Graphics::TextureUpdateInfo>&       updateInfoList,
                                             const std::vector<Graphics::TextureUpdateSourceInfo>& sourceList)
 {
-  std::ostringstream          out;
   TraceCallStack::NamedParams namedParams;
-  out << "[" << updateInfoList.size() << "]:";
-  namedParams["updateInfoList"] = out.str();
-  out.str("");
-  out << "[" << sourceList.size() << "]:";
-  namedParams["sourceList"] = out.str();
+  namedParams["updateInfoList"] << "[" << updateInfoList.size() << "]:";
+  namedParams["sourceList"] << "[" << sourceList.size() << "]:";
 
   mCallStack.PushCall("UpdateTextures", "", namedParams);
 
@@ -250,18 +630,16 @@ void TestGraphicsController::UpdateTextures(const std::vector<Graphics::TextureU
 bool TestGraphicsController::EnableDepthStencilBuffer(bool enableDepth, bool enableStencil)
 {
   TraceCallStack::NamedParams namedParams;
-  namedParams["enableDepth"]   = enableDepth ? "T" : "F";
-  namedParams["enableStencil"] = enableStencil ? "T" : "F";
+  namedParams["enableDepth"] << (enableDepth ? "T" : "F");
+  namedParams["enableStencil"] << (enableStencil ? "T" : "F");
   mCallStack.PushCall("EnableDepthStencilBuffer", "", namedParams);
   return false;
 }
 
 void TestGraphicsController::RunGarbageCollector(size_t numberOfDiscardedRenderers)
 {
-  std::ostringstream out;
-  out << numberOfDiscardedRenderers;
   TraceCallStack::NamedParams namedParams;
-  namedParams["numberOfDiscardedrenderers"] = out.str();
+  namedParams["numberOfDiscardedRenderers"] << numberOfDiscardedRenderers;
   mCallStack.PushCall("RunGarbageCollector", "", namedParams);
 }
 
@@ -287,13 +665,12 @@ bool TestGraphicsController::IsDrawOnResumeRequired()
   return isDrawOnResumeRequiredResult;
 }
 
-Graphics::UniquePtr<Graphics::Buffer> TestGraphicsController::CreateBuffer(const Graphics::BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Graphics::Buffer>&& oldBuffer)
+Graphics::UniquePtr<Graphics::Buffer> TestGraphicsController::CreateBuffer(const Graphics::BufferCreateInfo& createInfo, Graphics::UniquePtr<Graphics::Buffer>&& oldBuffer)
 {
   std::ostringstream oss;
-  oss << "bufferCreateInfo:" << bufferCreateInfo;
+  oss << "bufferCreateInfo:" << createInfo;
   mCallStack.PushCall("CreateBuffer", oss.str());
-
-  return Graphics::MakeUnique<TestGraphicsBuffer>();
+  return Graphics::MakeUnique<TestGraphicsBuffer>(mCallStack, mGl, createInfo.size, createInfo.usage);
 }
 
 Graphics::UniquePtr<Graphics::CommandBuffer> TestGraphicsController::CreateCommandBuffer(const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo, Graphics::UniquePtr<Graphics::CommandBuffer>&& oldCommandBuffer)
@@ -301,7 +678,7 @@ Graphics::UniquePtr<Graphics::CommandBuffer> TestGraphicsController::CreateComma
   std::ostringstream oss;
   oss << "commandBufferCreateInfo:" << commandBufferCreateInfo;
   mCallStack.PushCall("CreateCommandBuffer", oss.str());
-  return Graphics::MakeUnique<TestGraphicsCommandBuffer>(mCommandBufferCallStack, mGlAbstraction);
+  return Graphics::MakeUnique<TestGraphicsCommandBuffer>(mCommandBufferCallStack, mGl);
 }
 
 Graphics::UniquePtr<Graphics::RenderPass> TestGraphicsController::CreateRenderPass(const Graphics::RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<Graphics::RenderPass>&& oldRenderPass)
@@ -312,14 +689,11 @@ Graphics::UniquePtr<Graphics::RenderPass> TestGraphicsController::CreateRenderPa
 
 Graphics::UniquePtr<Graphics::Texture> TestGraphicsController::CreateTexture(const Graphics::TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Graphics::Texture>&& oldTexture)
 {
-  std::ostringstream params, oss;
-  params << "textureCreateInfo:" << textureCreateInfo;
   TraceCallStack::NamedParams namedParams;
-  oss << textureCreateInfo;
-  namedParams["textureCreateInfo"] = oss.str();
-  mCallStack.PushCall("CreateTexture", params.str(), namedParams);
+  namedParams["textureCreateInfo"] << textureCreateInfo;
+  mCallStack.PushCall("CreateTexture", namedParams.str(), namedParams);
 
-  return Graphics::MakeUnique<TestGraphicsTexture>(mGlAbstraction, textureCreateInfo);
+  return Graphics::MakeUnique<TestGraphicsTexture>(mGl, textureCreateInfo);
 }
 
 Graphics::UniquePtr<Graphics::Framebuffer> TestGraphicsController::CreateFramebuffer(const Graphics::FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Graphics::Framebuffer>&& oldFramebuffer)
@@ -331,25 +705,28 @@ Graphics::UniquePtr<Graphics::Framebuffer> TestGraphicsController::CreateFramebu
 Graphics::UniquePtr<Graphics::Pipeline> TestGraphicsController::CreatePipeline(const Graphics::PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
 {
   mCallStack.PushCall("CreatePipeline", "");
-  return nullptr;
+  return std::make_unique<TestGraphicsPipeline>(mGl, pipelineCreateInfo);
+}
+
+Graphics::UniquePtr<Graphics::Program> TestGraphicsController::CreateProgram(const Graphics::ProgramCreateInfo& programCreateInfo, Graphics::UniquePtr<Graphics::Program>&& oldProgram)
+{
+  mCallStack.PushCall("CreateProgram", "");
+  return Graphics::MakeUnique<TestGraphicsProgram>(mGl, programCreateInfo, mVertexFormats);
 }
 
 Graphics::UniquePtr<Graphics::Shader> TestGraphicsController::CreateShader(const Graphics::ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Graphics::Shader>&& oldShader)
 {
   mCallStack.PushCall("CreateShader", "");
-  return nullptr;
+  return Graphics::MakeUnique<TestGraphicsShader>(mGl, shaderCreateInfo);
 }
 
 Graphics::UniquePtr<Graphics::Sampler> TestGraphicsController::CreateSampler(const Graphics::SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Graphics::Sampler>&& oldSampler)
 {
-  std::ostringstream params, oss;
-  params << "samplerCreateInfo:" << samplerCreateInfo;
   TraceCallStack::NamedParams namedParams;
-  oss << samplerCreateInfo;
-  namedParams["samplerCreateInfo"] = oss.str();
-  mCallStack.PushCall("CreateSampler", params.str(), namedParams);
+  namedParams["samplerCreateInfo"] << samplerCreateInfo;
+  mCallStack.PushCall("CreateSampler", namedParams.str(), namedParams);
 
-  return Graphics::MakeUnique<TestGraphicsSampler>(mGlAbstraction, samplerCreateInfo);
+  return Graphics::MakeUnique<TestGraphicsSampler>(mGl, samplerCreateInfo);
 }
 
 Graphics::UniquePtr<Graphics::RenderTarget> TestGraphicsController::CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<Graphics::RenderTarget>&& oldRenderTarget)
@@ -361,7 +738,11 @@ Graphics::UniquePtr<Graphics::RenderTarget> TestGraphicsController::CreateRender
 Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapBufferRange(const Graphics::MapBufferInfo& mapInfo)
 {
   mCallStack.PushCall("MapBufferRange", "");
-  return nullptr;
+
+  auto buffer = static_cast<TestGraphicsBuffer*>(mapInfo.buffer);
+  buffer->memory.resize(mapInfo.offset + mapInfo.size); // For initial testing, allow writes past capacity
+
+  return std::make_unique<TestGraphicsMemory>(mCallStack, *buffer, mapInfo.offset, mapInfo.size);
 }
 
 Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapTextureRange(const Graphics::MapTextureInfo& mapInfo)
@@ -395,10 +776,24 @@ const Graphics::TextureProperties& TestGraphicsController::GetTextureProperties(
   return textureProperties;
 }
 
+const Graphics::Reflection& TestGraphicsController::GetProgramReflection(const Graphics::Program& program)
+{
+  mCallStack.PushCall("GetProgramReflection", "");
+
+  return static_cast<const TestGraphicsProgram*>(&program)->GetReflection();
+}
+
 bool TestGraphicsController::PipelineEquals(const Graphics::Pipeline& pipeline0, const Graphics::Pipeline& pipeline1) const
 {
   mCallStack.PushCall("PipelineEquals", "");
   return false;
 }
 
+bool TestGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData )
+{
+  mCallStack.PushCall("GetProgramParameter", "");
+  auto graphicsProgram = Uncast<TestGraphicsProgram>(&program);
+  return graphicsProgram->GetParameter(parameterId, outData);
+}
+
 } // namespace Dali