Skip to main content

What is Opal?

Opal is Atlas Engine’s low-level rendering abstraction layer that provides a unified API across OpenGL, Vulkan, and Metal backends. It handles context creation, device management, command buffers, and GPU resources.
This is an alpha API and may change in future releases.

Multi-Backend Architecture

Opal automatically selects the appropriate backend based on compile-time flags:
  • OpenGL: Cross-platform fallback (4.1+ Core)
  • Vulkan: Modern low-overhead API for Windows/Linux
  • Metal: Native high-performance rendering on macOS/iOS

Core Components

Context Creation

The Context manages the GLFW window and backend initialization:
#include "opal/opal.h"

using namespace opal;

// Configure the rendering context
ContextConfiguration config;
config.useOpenGL = true;
config.majorVersion = 4;
config.minorVersion = 1;
config.profile = OpenGLProfile::Core;
config.applicationName = "My Atlas App";

// Create context
auto context = Context::create(config);
context->makeWindow(1600, 1200, "My Window");
context->makeCurrent();
useOpenGL
bool
default:"true"
Use OpenGL backend (set to false for Vulkan/Metal)
majorVersion
int
default:"4"
OpenGL major version number
minorVersion
int
default:"1"
OpenGL minor version number
createValidationLayers
bool
default:"true"
Enable validation layers for debugging (Vulkan)

Device Acquisition

The Device represents the GPU and manages rendering resources:
// Acquire device from context
auto device = Device::acquire(context);

// Get device information
DeviceInfo info = device->getDeviceInfo();
std::cout << "GPU: " << info.deviceName << std::endl;
std::cout << "Vendor: " << info.vendorName << std::endl;
std::cout << "Driver: " << info.driverVersion << std::endl;
std::cout << "Rendering API: " << info.renderingVersion << std::endl;

Command Buffers

Command buffers record and submit GPU commands:
// Acquire command buffer for rendering
auto commandBuffer = device->acquireCommandBuffer();

// Start recording
commandBuffer->start();

// Begin render pass
auto renderPass = RenderPass::create();
renderPass->setFramebuffer(framebuffer);
commandBuffer->beginPass(renderPass);

// Clear screen
commandBuffer->clear(0.1f, 0.1f, 0.15f, 1.0f, 1.0f);

// Bind pipeline and draw
commandBuffer->bindPipeline(pipeline);
commandBuffer->bindDrawingState(drawingState);
commandBuffer->drawIndexed(indexCount, 1);

// End pass and submit
commandBuffer->endPass();
commandBuffer->commit();
device->submitCommandBuffer(commandBuffer);

Textures

Opal supports multiple texture types and formats:
// Create a 2D RGBA texture
auto texture = Texture::create(
    TextureType::Texture2D,
    TextureFormat::Rgba8,
    1024, 1024,
    TextureDataFormat::Rgba,
    pixelData
);

// Create a multisampled texture for MSAA
auto msTexture = Texture::createMultisampled(
    TextureFormat::Rgba16F,
    1920, 1080,
    4  // 4x MSAA
);

// Create a depth cubemap for omnidirectional shadows
auto shadowCubemap = Texture::createDepthCubemap(
    TextureFormat::Depth32F,
    2048  // Resolution per face
);

// Configure texture sampling
texture->setParameters(
    TextureWrapMode::Repeat,
    TextureWrapMode::Repeat,
    TextureFilterMode::LinearMipmapLinear,
    TextureFilterMode::Linear
);

// Generate mipmaps
texture->automaticallyGenerateMipmaps();
type
TextureType
Texture2D | TextureCubeMap | Texture3D | Texture2DArray | Texture2DMultisample
format
TextureFormat
Rgba8 | sRgba8 | Rgba16F | Depth24Stencil8 | Depth32F | and more

Buffers

Manage vertex, index, and uniform buffers:
// Create vertex buffer
auto vertexBuffer = Buffer::create(
    BufferUsage::VertexBuffer,
    vertices.size() * sizeof(Vertex),
    vertices.data(),
    MemoryUsageType::GPUOnly
);

// Create index buffer
auto indexBuffer = Buffer::create(
    BufferUsage::IndexArray,
    indices.size() * sizeof(uint32_t),
    indices.data(),
    MemoryUsageType::GPUOnly
);

// Update buffer data
vertexBuffer->updateData(0, newData.size() * sizeof(Vertex), newData.data());

Framebuffers

Render to textures using framebuffer objects:
// Create framebuffer
auto framebuffer = Framebuffer::create(1920, 1080);

// Attach color texture
framebuffer->attachTexture(colorTexture, 0);

// Attach depth-stencil buffer
auto depthBuffer = DepthStencilBuffer::create(
    1920, 1080,
    TextureFormat::Depth24Stencil8
);
framebuffer->attachDepthStencilBuffer(depthBuffer);

// Bind and render
framebuffer->bind();
// ... rendering commands ...
framebuffer->unbind();

Shaders and Pipelines

Compile shaders and configure the graphics pipeline:
// Create shaders from source
auto vertShader = Shader::createFromSource(vertexSource, ShaderType::Vertex);
auto fragShader = Shader::createFromSource(fragmentSource, ShaderType::Fragment);

vertShader->compile();
fragShader->compile();

// Create shader program
auto shaderProgram = ShaderProgram::create();
shaderProgram->attachShader(vertShader);
shaderProgram->attachShader(fragShader);
shaderProgram->link();

// Create and configure pipeline
auto pipeline = Pipeline::create();
pipeline->setShaderProgram(shaderProgram);
pipeline->setPrimitiveStyle(PrimitiveStyle::Triangles);
pipeline->enableDepthTest(true);
pipeline->setDepthCompareOp(CompareOp::Less);
pipeline->setCullMode(CullMode::Back);
pipeline->enableBlending(true);
pipeline->setBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
pipeline->build();

Backend-Specific Features

Vulkan

When compiled with VULKAN defined:
  • Uses VkDevice, VkCommandBuffer, and VkPipeline
  • Supports descriptor sets for efficient resource binding
  • Includes push constants for small uniform data
  • Provides swapchain management

Metal

When compiled with METAL defined:
  • Uses Metal API on macOS/iOS
  • Optimized for Apple Silicon
  • Efficient memory management

OpenGL

Default fallback implementation:
  • Uses VAOs, VBOs, and FBOs
  • Compatible with OpenGL 4.1 Core and above
  • Widely supported across platforms

Best Practices

Batch draw calls with the same pipeline to reduce overhead.
Render multiple copies of objects with drawIndexed(count, instanceCount).
Always generate mipmaps for textures to improve performance and quality.
Use Texture::createMultisampled() for high-quality anti-aliasing.

See Also

Build docs developers (and LLMs) love