Initial commit

This commit is contained in:
2025-12-17 16:47:48 +00:00
commit 13813f3363
4964 changed files with 1079753 additions and 0 deletions

View File

@@ -0,0 +1,314 @@
#include "DeviceBGFX.hpp"
#include "GeometryBGFX.hpp"
#include "ShaderBGFX.hpp"
#include "TextureBGFX.hpp"
#include "FramebufferBGFX.hpp"
#include "Profiler.hpp"
#include "ImGui.hpp"
#include <bgfx/bgfx.h>
#include <bgfx/platform.h>
#include <sstream>
#ifdef __linux
#include <wayland-client.h>
#include <X11/Xlib.h>
#endif
LOGGROUP(Graphics)
FASTFLAGVARIABLE(DebugGraphicsBGFX, false)
namespace Aya
{
namespace Graphics
{
static DeviceCapsBGFX createDeviceCaps()
{
const bgfx::Caps* bgfxCaps = bgfx::getCaps();
DeviceCapsBGFX caps;
caps.caps = bgfxCaps;
caps.supportsFramebuffer = true;
caps.supportsShaders = true;
caps.supportsFFP = false;
caps.supportsStencil = true;
caps.supportsIndex32 = bgfxCaps->supported & BGFX_CAPS_INDEX32;
caps.supportsTextureDXT = (bgfxCaps->formats[bgfx::TextureFormat::BC1] & BGFX_CAPS_FORMAT_TEXTURE_2D) != 0;
caps.supportsTexturePVR = (bgfxCaps->formats[bgfx::TextureFormat::PTC12] & BGFX_CAPS_FORMAT_TEXTURE_2D) != 0;
caps.supportsTextureHalfFloat = (bgfxCaps->formats[bgfx::TextureFormat::R16F] & BGFX_CAPS_FORMAT_TEXTURE_2D) != 0;
caps.supportsTexture3D = (bgfxCaps->supported & BGFX_CAPS_TEXTURE_3D) != 0;
caps.supportsTextureNPOT = true;
caps.supportsTextureETC1 = (bgfxCaps->formats[bgfx::TextureFormat::ETC1] & BGFX_CAPS_FORMAT_TEXTURE_2D) != 0;
caps.supportsTexturePartialMipChain = true;
caps.maxDrawBuffers = bgfxCaps->limits.maxFBAttachments;
caps.maxSamples = 1; // BGFX doesn't expose max MSAA samples directly
caps.maxTextureSize = bgfxCaps->limits.maxTextureSize;
caps.maxTextureUnits = bgfxCaps->limits.maxTextureSamplers;
caps.colorOrderBGR = bgfxCaps->rendererType == bgfx::RendererType::Direct3D11 || bgfxCaps->rendererType == bgfx::RendererType::Direct3D12;
caps.requiresRenderTargetFlipping =
bgfxCaps->rendererType == bgfx::RendererType::OpenGL || bgfxCaps->rendererType == bgfx::RendererType::OpenGLES;
caps.retina = false;
caps.supportsCompute = (bgfxCaps->supported & BGFX_CAPS_COMPUTE) != 0;
caps.supportsInstancing = (bgfxCaps->supported & BGFX_CAPS_INSTANCING) != 0;
caps.supportsTextureBlits = (bgfxCaps->supported & BGFX_CAPS_TEXTURE_BLIT) != 0;
caps.supportsTextureReadBack = (bgfxCaps->supported & BGFX_CAPS_TEXTURE_READ_BACK) != 0;
caps.supportsOcclusionQuery = (bgfxCaps->supported & BGFX_CAPS_OCCLUSION_QUERY) != 0;
return caps;
}
enum class DisplayBackend
{
Wayland,
X11,
Unknown
};
static DisplayBackend detectDisplayBackend()
{
const char* waylandDisplay = std::getenv("WAYLAND_DISPLAY");
const char* x11Display = std::getenv("DISPLAY");
if (waylandDisplay && waylandDisplay[0])
return DisplayBackend::Wayland;
if (x11Display && x11Display[0])
return DisplayBackend::X11;
return DisplayBackend::Unknown;
}
DeviceBGFX::DeviceBGFX(void* windowHandle, void* displayHandle)
: width(0)
, height(0)
, frameNumber(0)
{
bgfx::Init init;
init.type = bgfx::RendererType::Count; // Auto-select
init.platformData.nwh = windowHandle;
#ifdef __linux__
DisplayBackend backend = detectDisplayBackend();
if (backend == DisplayBackend::Wayland)
{
init.platformData.ndt = static_cast<wl_display*>(displayHandle);
init.platformData.type = bgfx::NativeWindowHandleType::Wayland;
}
else if (backend == DisplayBackend::X11)
{
init.platformData.ndt = static_cast<::Display*>(displayHandle);
init.platformData.type = bgfx::NativeWindowHandleType::Default; // X11 is default on Linux
}
#endif
if (!bgfx::init(init))
{
throw Aya::runtime_error("Failed to initialize BGFX");
}
rendererType = bgfx::getCaps()->rendererType;
caps = createDeviceCaps();
const char* rendererName = bgfx::getRendererName(rendererType);
FASTLOGS(FLog::Graphics, "BGFX Renderer: %s", rendererName);
caps.dumpToFLog(FLog::Graphics);
FASTLOG5(FLog::Graphics, "Caps: Compute %d Instancing %d TextureBlits %d TextureReadBack %d OcclusionQuery %d", caps.supportsCompute,
caps.supportsInstancing, caps.supportsTextureBlits, caps.supportsTextureReadBack, caps.supportsOcclusionQuery);
immediateContext.reset(new DeviceContextBGFX(this));
mainFramebuffer.reset(new FramebufferBGFX(this, BGFX_INVALID_HANDLE));
bgfx::setDebug(FFlag::DebugGraphicsBGFX ? BGFX_DEBUG_TEXT : BGFX_DEBUG_NONE);
#if defined(_WIN32) || defined(__linux__)
Profiler::gpuInit(0);
#endif
ImGui::gpuInit();
}
DeviceBGFX::~DeviceBGFX()
{
#if defined(_WIN32) || defined(__linux__)
Profiler::gpuShutdown();
#endif
ImGui::gpuShutdown();
immediateContext.reset();
mainFramebuffer.reset();
bgfx::shutdown();
}
void DeviceBGFX::resize(int w, int h)
{
width = w;
height = h;
bgfx::reset(width, height, BGFX_RESET_VSYNC);
}
std::string DeviceBGFX::getAPIName()
{
return bgfx::getRendererName(rendererType);
}
std::string DeviceBGFX::getFeatureLevel()
{
std::ostringstream oss;
oss << bgfx::getRendererName(rendererType);
return oss.str();
}
bool DeviceBGFX::validate()
{
// BGFX handles window resizing internally
return true;
}
DeviceContext* DeviceBGFX::beginFrame()
{
immediateContext->setCurrentView(0);
immediateContext->bindFramebuffer(mainFramebuffer.get());
immediateContext->clearStates();
return immediateContext.get();
}
void DeviceBGFX::endFrame()
{
bgfx::frame();
frameNumber++;
}
Framebuffer* DeviceBGFX::getMainFramebuffer()
{
return mainFramebuffer.get();
}
void DeviceBGFX::defineGlobalConstants(size_t dataSize, const std::vector<ShaderGlobalConstant>& constants)
{
AYAASSERT(globalConstants.empty());
AYAASSERT(!constants.empty());
globalConstants = constants;
immediateContext->defineGlobalConstants(dataSize);
}
std::string DeviceBGFX::createShaderSource(
const std::string& path, const std::string& defines, boost::function<std::string(const std::string&)> fileCallback)
{
return fileCallback(path);
}
std::vector<char> DeviceBGFX::createShaderBytecode(const std::string& source, const std::string& target, const std::string& entrypoint)
{
AYAASSERT(false && "BGFX shaders must be pre-compiled");
return std::vector<char>();
}
std::string DeviceBGFX::getShadingLanguage()
{
switch (rendererType)
{
case bgfx::RendererType::Direct3D11:
return "dx12";
case bgfx::RendererType::Direct3D12:
return "dx11";
case bgfx::RendererType::Metal:
return "metal";
case bgfx::RendererType::OpenGL:
return "glsl";
case bgfx::RendererType::OpenGLES:
return "glsles";
case bgfx::RendererType::Vulkan:
return "spirv";
default:
return "unknown";
}
}
shared_ptr<VertexShader> DeviceBGFX::createVertexShader(const std::vector<char>& bytecode)
{
return shared_ptr<VertexShader>(new VertexShaderBGFX(this, bytecode));
}
shared_ptr<FragmentShader> DeviceBGFX::createFragmentShader(const std::vector<char>& bytecode)
{
return shared_ptr<FragmentShader>(new FragmentShaderBGFX(this, bytecode));
}
shared_ptr<ShaderProgram> DeviceBGFX::createShaderProgram(
const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader)
{
return shared_ptr<ShaderProgram>(new ShaderProgramBGFX(this, vertexShader, fragmentShader));
}
shared_ptr<ShaderProgram> DeviceBGFX::createShaderProgramFFP()
{
throw Aya::runtime_error("No FFP support in BGFX");
}
shared_ptr<VertexBuffer> DeviceBGFX::createVertexBuffer(size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage)
{
return shared_ptr<VertexBuffer>(new VertexBufferBGFX(this, elementSize, elementCount, usage));
}
shared_ptr<IndexBuffer> DeviceBGFX::createIndexBuffer(size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage)
{
return shared_ptr<IndexBuffer>(new IndexBufferBGFX(this, elementSize, elementCount, usage));
}
shared_ptr<VertexLayout> DeviceBGFX::createVertexLayout(const std::vector<VertexLayout::Element>& elements)
{
return shared_ptr<VertexLayout>(new VertexLayoutBGFX(this, elements));
}
shared_ptr<Texture> DeviceBGFX::createTexture(Texture::Type type, Texture::Format format, unsigned int width, unsigned int height, unsigned int depth,
unsigned int mipLevels, Texture::Usage usage)
{
return shared_ptr<Texture>(new TextureBGFX(this, type, format, width, height, depth, mipLevels, usage));
}
shared_ptr<Renderbuffer> DeviceBGFX::createRenderbuffer(Texture::Format format, unsigned int width, unsigned int height, unsigned int samples)
{
return shared_ptr<Renderbuffer>(new RenderbufferBGFX(this, format, width, height, samples));
}
shared_ptr<Geometry> DeviceBGFX::createGeometryImpl(const shared_ptr<VertexLayout>& layout,
const std::vector<shared_ptr<VertexBuffer>>& vertexBuffers, const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex)
{
return shared_ptr<Geometry>(new GeometryBGFX(this, layout, vertexBuffers, indexBuffer, baseVertexIndex));
}
shared_ptr<Framebuffer> DeviceBGFX::createFramebufferImpl(const std::vector<shared_ptr<Renderbuffer>>& color, const shared_ptr<Renderbuffer>& depth)
{
return shared_ptr<Framebuffer>(new FramebufferBGFX(this, color, depth));
}
DeviceStats DeviceBGFX::getStatistics() const
{
DeviceStats result = {};
const bgfx::Stats* stats = bgfx::getStats();
result.gpuFrameTime = static_cast<float>(stats->gpuTimeEnd - stats->gpuTimeBegin) / stats->gpuTimerFreq * 1000.0f;
return result;
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,195 @@
#pragma once
#include "Core/Device.hpp"
#include "Core/States.hpp"
#include <bgfx/bgfx.h>
namespace Aya
{
namespace Graphics
{
class FramebufferBGFX;
class ShaderProgramBGFX;
class TextureBGFX;
class DeviceBGFX;
struct DeviceCapsBGFX : DeviceCaps
{
const bgfx::Caps* caps;
bool supportsCompute;
bool supportsInstancing;
bool supportsTextureBlits;
bool supportsTextureReadBack;
bool supportsOcclusionQuery;
};
class DeviceContextBGFX : public DeviceContext
{
public:
DeviceContextBGFX(DeviceBGFX* dev);
~DeviceContextBGFX();
void defineGlobalConstants(size_t dataSize);
void clearStates();
void invalidateCachedProgram();
void invalidateCachedTexture(Texture* texture);
void invalidateCachedTextureStage(unsigned int stage);
void handleStencilState();
virtual void setDefaultAnisotropy(unsigned int value);
virtual void updateGlobalConstants(const void* data, size_t dataSize);
virtual void bindFramebuffer(Framebuffer* buffer);
virtual void clearFramebuffer(unsigned int mask, const float color[4], float depth, unsigned int stencil);
virtual void copyFramebuffer(Framebuffer* buffer, Texture* texture, int xOffset, int yOffset);
virtual void resolveFramebuffer(Framebuffer* msaaBuffer, Framebuffer* buffer, unsigned int mask);
virtual void discardFramebuffer(Framebuffer* buffer, unsigned int mask);
virtual void bindProgram(ShaderProgram* program);
virtual void setWorldTransforms4x3(const float* data, size_t matrixCount);
virtual void setConstant(int handle, const float* data, size_t vectorCount);
virtual void bindTexture(unsigned int stage, Texture* texture, const SamplerState& state);
virtual void setRasterizerState(const RasterizerState& state);
virtual void setBlendState(const BlendState& state);
virtual void setDepthState(const DepthState& state);
virtual void drawImpl(Geometry* geometry, Geometry::Primitive primitive, unsigned int offset, unsigned int count, unsigned int indexRangeBegin,
unsigned int indexRangeEnd);
virtual void pushDebugMarkerGroup(const char* text);
virtual void popDebugMarkerGroup();
virtual void setDebugMarker(const char* text);
bgfx::ViewId getCurrentView() const
{
return currentView;
}
void setCurrentView(bgfx::ViewId view)
{
currentView = view;
}
private:
std::vector<char> globalData;
bgfx::UniformHandle globalUniform;
unsigned int globalDataVersion;
unsigned int defaultAnisotropy;
ShaderProgramBGFX* cachedProgram;
TextureBGFX* cachedTextures[16];
// Sampler uniforms for each texture stage
bgfx::UniformHandle samplerUniforms[16];
RasterizerState cachedRasterizerState;
BlendState cachedBlendState;
DepthState cachedDepthState;
uint64_t cachedStateFlags;
bgfx::ViewId currentView;
DeviceBGFX* device;
};
class DeviceBGFX : public Device
{
public:
DeviceBGFX(void* windowHandle, void* displayHandle);
~DeviceBGFX();
virtual bool validate();
virtual void resize(int w, int h);
virtual DeviceContext* beginFrame();
virtual void endFrame();
virtual Framebuffer* getMainFramebuffer();
virtual void defineGlobalConstants(size_t dataSize, const std::vector<ShaderGlobalConstant>& constants);
virtual std::string getAPIName();
virtual std::string getFeatureLevel();
virtual std::string getShadingLanguage();
virtual std::string createShaderSource(
const std::string& path, const std::string& defines, boost::function<std::string(const std::string&)> fileCallback);
virtual std::vector<char> createShaderBytecode(const std::string& source, const std::string& target, const std::string& entrypoint);
virtual shared_ptr<VertexShader> createVertexShader(const std::vector<char>& bytecode);
virtual shared_ptr<FragmentShader> createFragmentShader(const std::vector<char>& bytecode);
virtual shared_ptr<ShaderProgram> createShaderProgram(
const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader);
virtual shared_ptr<ShaderProgram> createShaderProgramFFP();
virtual shared_ptr<VertexBuffer> createVertexBuffer(size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage);
virtual shared_ptr<IndexBuffer> createIndexBuffer(size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage);
virtual shared_ptr<VertexLayout> createVertexLayout(const std::vector<VertexLayout::Element>& elements);
virtual shared_ptr<Texture> createTexture(Texture::Type type, Texture::Format format, unsigned int width, unsigned int height, unsigned int depth,
unsigned int mipLevels, Texture::Usage usage);
virtual shared_ptr<Renderbuffer> createRenderbuffer(Texture::Format format, unsigned int width, unsigned int height, unsigned int samples);
virtual shared_ptr<Geometry> createGeometryImpl(const shared_ptr<VertexLayout>& layout,
const std::vector<shared_ptr<VertexBuffer>>& vertexBuffers, const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex);
virtual shared_ptr<Framebuffer> createFramebufferImpl(const std::vector<shared_ptr<Renderbuffer>>& color, const shared_ptr<Renderbuffer>& depth);
virtual const DeviceCaps& getCaps() const
{
return caps;
}
virtual DeviceStats getStatistics() const;
DeviceContextBGFX* getImmediateContextBGFX()
{
return immediateContext.get();
}
const DeviceCapsBGFX& getCapsBGFX() const
{
return caps;
}
const std::vector<ShaderGlobalConstant>& getGlobalConstants() const
{
return globalConstants;
}
bgfx::RendererType::Enum getRendererType() const
{
return rendererType;
}
private:
DeviceCapsBGFX caps;
scoped_ptr<DeviceContextBGFX> immediateContext;
scoped_ptr<FramebufferBGFX> mainFramebuffer;
std::vector<ShaderGlobalConstant> globalConstants;
bgfx::RendererType::Enum rendererType;
uint32_t width;
uint32_t height;
uint32_t frameNumber;
float gpuTime;
};
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,552 @@
#include "DeviceBGFX.hpp"
#include "GeometryBGFX.hpp"
#include "ShaderBGFX.hpp"
#include "TextureBGFX.hpp"
#include "FramebufferBGFX.hpp"
#include <bgfx/bgfx.h>
#ifdef AYA_OS_WINDOWS
#include <Windows.h>
#endif
namespace Aya
{
namespace Graphics
{
// Convert RasterizerState cull mode to BGFX state flags
static uint64_t getCullStateFlags(RasterizerState::CullMode mode)
{
switch (mode)
{
case RasterizerState::Cull_None:
return BGFX_STATE_CULL_CW | BGFX_STATE_CULL_CCW; // Disable culling
case RasterizerState::Cull_Back:
return BGFX_STATE_CULL_CW;
case RasterizerState::Cull_Front:
return BGFX_STATE_CULL_CCW;
default:
return 0;
}
}
// Convert BlendState factors to BGFX blend equation
static uint64_t getBlendStateFlags(const BlendState& state)
{
if (!state.blendingNeeded())
return 0;
static const uint64_t blendFactorsBGFX[BlendState::Factor_Count] = {
BGFX_STATE_BLEND_ONE, // Factor_One
BGFX_STATE_BLEND_ZERO, // Factor_Zero
BGFX_STATE_BLEND_DST_COLOR, // Factor_DstColor
BGFX_STATE_BLEND_SRC_ALPHA, // Factor_SrcAlpha
BGFX_STATE_BLEND_INV_SRC_ALPHA, // Factor_InvSrcAlpha
BGFX_STATE_BLEND_DST_ALPHA, // Factor_DstAlpha
BGFX_STATE_BLEND_INV_DST_ALPHA // Factor_InvDstAlpha
};
uint64_t srcBlend = blendFactorsBGFX[state.getColorSrc()];
uint64_t dstBlend = blendFactorsBGFX[state.getColorDst()];
uint64_t flags = BGFX_STATE_BLEND_FUNC(srcBlend, dstBlend);
if (state.separateAlphaBlend())
{
uint64_t srcAlpha = blendFactorsBGFX[state.getAlphaSrc()];
uint64_t dstAlpha = blendFactorsBGFX[state.getAlphaDst()];
flags = BGFX_STATE_BLEND_FUNC_SEPARATE(srcBlend, dstBlend, srcAlpha, dstAlpha);
}
return flags;
}
// Convert DepthState to BGFX state flags
static uint64_t getDepthStateFlags(const DepthState& state)
{
uint64_t flags = 0;
if (state.getFunction() != DepthState::Function_None)
{
switch (state.getFunction())
{
case DepthState::Function_Always:
flags |= BGFX_STATE_DEPTH_TEST_ALWAYS;
break;
case DepthState::Function_Less:
flags |= BGFX_STATE_DEPTH_TEST_LESS;
break;
case DepthState::Function_LessEqual:
flags |= BGFX_STATE_DEPTH_TEST_LEQUAL;
break;
default:
break;
}
}
if (state.getWrite())
{
flags |= BGFX_STATE_WRITE_Z;
}
return flags;
}
// Convert color mask to BGFX state flags
static uint64_t getColorMaskFlags(unsigned int colorMask)
{
uint64_t flags = 0;
if (colorMask & BlendState::Color_R)
flags |= BGFX_STATE_WRITE_R;
if (colorMask & BlendState::Color_G)
flags |= BGFX_STATE_WRITE_G;
if (colorMask & BlendState::Color_B)
flags |= BGFX_STATE_WRITE_B;
if (colorMask & BlendState::Color_A)
flags |= BGFX_STATE_WRITE_A;
return flags;
}
DeviceContextBGFX::DeviceContextBGFX(DeviceBGFX* dev)
: globalDataVersion(0)
, device(dev)
, defaultAnisotropy(1)
, cachedProgram(nullptr)
, cachedRasterizerState(RasterizerState::Cull_None)
, cachedBlendState(BlendState::Mode_None)
, cachedDepthState(DepthState::Function_Always, false)
, cachedStateFlags(0)
, currentView(0)
{
globalUniform = BGFX_INVALID_HANDLE;
for (size_t i = 0; i < ARRAYSIZE(cachedTextures); ++i)
{
cachedTextures[i] = nullptr;
// Create sampler uniforms for each texture stage
char uniformName[32];
snprintf(uniformName, sizeof(uniformName), "s_texColor%d", (int)i);
samplerUniforms[i] = bgfx::createUniform(uniformName, bgfx::UniformType::Sampler);
}
}
DeviceContextBGFX::~DeviceContextBGFX()
{
if (bgfx::isValid(globalUniform))
{
bgfx::destroy(globalUniform);
globalUniform = BGFX_INVALID_HANDLE;
}
// Destroy sampler uniforms
for (size_t i = 0; i < ARRAYSIZE(samplerUniforms); ++i)
{
if (bgfx::isValid(samplerUniforms[i]))
{
bgfx::destroy(samplerUniforms[i]);
samplerUniforms[i] = BGFX_INVALID_HANDLE;
}
}
}
void DeviceContextBGFX::clearStates()
{
// Clear program cache
cachedProgram = nullptr;
// Clear texture cache
for (size_t i = 0; i < ARRAYSIZE(cachedTextures); ++i)
cachedTextures[i] = nullptr;
// Clear states to invalid values to guarantee a cache miss on the next setup
cachedRasterizerState = RasterizerState(RasterizerState::Cull_Count);
cachedBlendState = BlendState(BlendState::Mode_Count);
cachedDepthState = DepthState(DepthState::Function_Count, false);
cachedStateFlags = 0;
}
void DeviceContextBGFX::invalidateCachedProgram()
{
cachedProgram = nullptr;
}
void DeviceContextBGFX::invalidateCachedTexture(Texture* texture)
{
TextureBGFX* textureBGFX = static_cast<TextureBGFX*>(texture);
for (unsigned int stage = 0; stage < ARRAYSIZE(cachedTextures); ++stage)
if (cachedTextures[stage] == textureBGFX)
cachedTextures[stage] = nullptr;
}
void DeviceContextBGFX::invalidateCachedTextureStage(unsigned int stage)
{
AYAASSERT(stage < ARRAYSIZE(cachedTextures));
cachedTextures[stage] = nullptr;
}
void DeviceContextBGFX::defineGlobalConstants(size_t dataSize)
{
AYAASSERT(globalData.empty());
AYAASSERT(dataSize > 0);
globalData.resize(dataSize);
// Create a uniform buffer for global constants
char uniformName[256];
snprintf(uniformName, sizeof(uniformName), "u_globals");
globalUniform = bgfx::createUniform(uniformName, bgfx::UniformType::Vec4, (dataSize + 15) / 16);
}
void DeviceContextBGFX::setDefaultAnisotropy(unsigned int value)
{
defaultAnisotropy = value;
}
void DeviceContextBGFX::updateGlobalConstants(const void* data, size_t dataSize)
{
AYAASSERT(dataSize == globalData.size());
memcpy(&globalData[0], data, dataSize);
globalDataVersion++;
// Update the uniform buffer
if (bgfx::isValid(globalUniform))
{
bgfx::setUniform(globalUniform, &globalData[0], (dataSize + 15) / 16);
}
}
void DeviceContextBGFX::bindFramebuffer(Framebuffer* buffer)
{
FramebufferBGFX* framebufferBGFX = static_cast<FramebufferBGFX*>(buffer);
// Set the framebuffer for the current view
bgfx::setViewFrameBuffer(currentView, framebufferBGFX->getHandle());
bgfx::setViewRect(currentView, 0, 0, uint16_t(buffer->getWidth()), uint16_t(buffer->getHeight()));
}
void DeviceContextBGFX::clearFramebuffer(unsigned int mask, const float color[4], float depth, unsigned int stencil)
{
uint16_t clearFlags = 0;
if (mask & Buffer_Color)
{
clearFlags |= BGFX_CLEAR_COLOR;
}
if (mask & Buffer_Depth)
{
clearFlags |= BGFX_CLEAR_DEPTH;
}
if (mask & Buffer_Stencil)
{
clearFlags |= BGFX_CLEAR_STENCIL;
}
uint32_t rgba = 0;
if (mask & Buffer_Color)
{
rgba = (static_cast<uint32_t>(color[0] * 255.0f) << 24) | (static_cast<uint32_t>(color[1] * 255.0f) << 16) |
(static_cast<uint32_t>(color[2] * 255.0f) << 8) | (static_cast<uint32_t>(color[3] * 255.0f));
}
bgfx::setViewClear(currentView, clearFlags, rgba, depth, static_cast<uint8_t>(stencil));
// Touch the view to ensure clear happens
bgfx::touch(currentView);
}
void DeviceContextBGFX::copyFramebuffer(Framebuffer* buffer, Texture* texture, int xOffset, int yOffset)
{
AYAASSERT(texture->getType() == Texture::Type_2D);
AYAASSERT(buffer->getWidth() == texture->getWidth() && buffer->getHeight() == texture->getHeight());
if (!device->getCapsBGFX().supportsTextureBlits)
{
// Fall back to a different method or log warning
return;
}
FramebufferBGFX* framebufferBGFX = static_cast<FramebufferBGFX*>(buffer);
TextureBGFX* textureBGFX = static_cast<TextureBGFX*>(texture);
// BGFX blit from framebuffer to texture
// Note: BGFX handles this differently - would need access to the framebuffer's texture attachments
invalidateCachedTextureStage(0);
// bgfx::blit(currentView, textureBGFX->getHandle(), 0, xOffset, yOffset, framebufferTexture, 0, 0, 0, width, height);
}
void DeviceContextBGFX::resolveFramebuffer(Framebuffer* msaaBuffer, Framebuffer* buffer, unsigned int mask)
{
AYAASSERT(msaaBuffer->getSamples() > 1);
AYAASSERT(buffer->getSamples() == 1);
AYAASSERT(msaaBuffer->getWidth() == buffer->getWidth() && msaaBuffer->getHeight() == buffer->getHeight());
// BGFX handles MSAA resolve automatically when rendering to a MSAA framebuffer
// and then using it as a texture or blitting to a non-MSAA target
// This may not need explicit implementation
}
void DeviceContextBGFX::discardFramebuffer(Framebuffer* buffer, unsigned int mask)
{
// BGFX handles framebuffer discard internally
// bgfx::discard() is used differently - it discards all pending draw calls
uint8_t discardFlags = 0;
// BGFX doesn't have per-buffer discard flags like GL
// The discard() function discards all state changes
if (mask != 0)
{
bgfx::discard();
}
}
void DeviceContextBGFX::bindProgram(ShaderProgram* program)
{
ShaderProgramBGFX* programBGFX = static_cast<ShaderProgramBGFX*>(program);
cachedProgram = programBGFX;
// BGFX sets the program per-draw call via bgfx::submit, not here
// Just cache the program for later use
}
void DeviceContextBGFX::setWorldTransforms4x3(const float* data, size_t matrixCount)
{
if (cachedProgram)
{
cachedProgram->setWorldTransforms4x3(data, matrixCount);
}
}
void DeviceContextBGFX::setConstant(int handle, const float* data, size_t vectorCount)
{
if (cachedProgram)
{
cachedProgram->setConstant(handle, data, vectorCount);
}
}
void DeviceContextBGFX::bindTexture(unsigned int stage, Texture* texture, const SamplerState& state)
{
SamplerState realState = (state.getFilter() == SamplerState::Filter_Anisotropic && state.getAnisotropy() == 0)
? SamplerState(state.getFilter(), state.getAddress(), defaultAnisotropy)
: state;
AYAASSERT(stage < device->getCaps().maxTextureUnits);
AYAASSERT(stage < ARRAYSIZE(cachedTextures));
TextureBGFX* textureBGFX = static_cast<TextureBGFX*>(texture);
if (textureBGFX != cachedTextures[stage])
{
cachedTextures[stage] = textureBGFX;
}
// Set texture with proper sampler uniform
textureBGFX->bindWithUniform(stage, samplerUniforms[stage], realState);
}
void DeviceContextBGFX::setRasterizerState(const RasterizerState& state)
{
if (cachedRasterizerState != state)
{
cachedRasterizerState = state;
// Update cached state flags
cachedStateFlags &= ~(BGFX_STATE_CULL_MASK);
cachedStateFlags |= getCullStateFlags(state.getCullMode());
// Handle depth bias (polygon offset)
if (state.getDepthBias() != 0)
{
// BGFX doesn't have a direct polygon offset equivalent in state flags
// This would need to be handled differently, possibly in shader or via uniforms
}
}
}
void DeviceContextBGFX::setBlendState(const BlendState& state)
{
if (cachedBlendState != state)
{
cachedBlendState = state;
// Update cached state flags
cachedStateFlags &= ~(BGFX_STATE_BLEND_MASK | BGFX_STATE_WRITE_MASK);
cachedStateFlags |= getBlendStateFlags(state);
cachedStateFlags |= getColorMaskFlags(state.getColorMask());
}
}
void DeviceContextBGFX::setDepthState(const DepthState& state)
{
if (cachedDepthState != state)
{
cachedDepthState = state;
// Update cached state flags
cachedStateFlags &= ~(BGFX_STATE_DEPTH_TEST_MASK | BGFX_STATE_WRITE_Z);
cachedStateFlags |= getDepthStateFlags(state);
// Handle stencil modes - BGFX uses bgfx::setStencil() separately
// For now, we'll handle basic stencil modes
// More complex stencil operations would need to be set per-draw call
switch (state.getStencilMode())
{
case DepthState::Stencil_None:
// No stencil test
break;
case DepthState::Stencil_IsNotZero:
case DepthState::Stencil_UpdateZFail:
case DepthState::Stencil_Increment:
case DepthState::Stencil_Decrement:
case DepthState::Stencil_IsNotZeroReplace:
// Stencil operations in BGFX require setting stencil per-draw
// Mark that stencil is needed
break;
default:
AYAASSERT(false);
}
}
}
void DeviceContextBGFX::handleStencilState()
{
// Convert DepthState stencil modes to BGFX stencil operations
uint32_t frontStencil = BGFX_STENCIL_NONE;
uint32_t backStencil = BGFX_STENCIL_NONE;
switch (cachedDepthState.getStencilMode())
{
case DepthState::Stencil_None:
// No stencil test
break;
case DepthState::Stencil_IsNotZero:
frontStencil = BGFX_STENCIL_TEST_NOTEQUAL | BGFX_STENCIL_FUNC_REF(0) | BGFX_STENCIL_FUNC_RMASK(0xFF) | BGFX_STENCIL_OP_FAIL_S_KEEP |
BGFX_STENCIL_OP_FAIL_Z_KEEP | BGFX_STENCIL_OP_PASS_Z_KEEP;
backStencil = frontStencil;
break;
case DepthState::Stencil_UpdateZFail:
// Front faces: decrement on z-fail
frontStencil = BGFX_STENCIL_TEST_ALWAYS | BGFX_STENCIL_FUNC_REF(0) | BGFX_STENCIL_FUNC_RMASK(0xFF) | BGFX_STENCIL_OP_FAIL_S_KEEP |
BGFX_STENCIL_OP_FAIL_Z_DECR | BGFX_STENCIL_OP_PASS_Z_KEEP;
// Back faces: increment on z-fail
backStencil = BGFX_STENCIL_TEST_ALWAYS | BGFX_STENCIL_FUNC_REF(0) | BGFX_STENCIL_FUNC_RMASK(0xFF) | BGFX_STENCIL_OP_FAIL_S_KEEP |
BGFX_STENCIL_OP_FAIL_Z_INCR | BGFX_STENCIL_OP_PASS_Z_KEEP;
break;
case DepthState::Stencil_Increment:
// This mode has special requirements - it modifies the state flags
// Disable color writes, enable front-face culling, increment stencil
frontStencil = BGFX_STENCIL_TEST_ALWAYS | BGFX_STENCIL_FUNC_REF(0) | BGFX_STENCIL_FUNC_RMASK(0xFF) | BGFX_STENCIL_OP_FAIL_S_KEEP |
BGFX_STENCIL_OP_FAIL_Z_KEEP | BGFX_STENCIL_OP_PASS_Z_INCR;
backStencil = frontStencil;
// Modify state flags: disable color writes, enable culling of front faces
cachedStateFlags &= ~BGFX_STATE_WRITE_MASK;
cachedStateFlags &= ~BGFX_STATE_CULL_MASK;
cachedStateFlags |= BGFX_STATE_CULL_CCW; // Cull front faces
break;
case DepthState::Stencil_Decrement:
// Continue from Increment - now cull back faces and decrement
frontStencil = BGFX_STENCIL_TEST_ALWAYS | BGFX_STENCIL_FUNC_REF(0) | BGFX_STENCIL_FUNC_RMASK(0xFF) | BGFX_STENCIL_OP_FAIL_S_KEEP |
BGFX_STENCIL_OP_FAIL_Z_KEEP | BGFX_STENCIL_OP_PASS_Z_DECR;
backStencil = frontStencil;
// Modify state flags: disable color writes, enable culling of back faces
cachedStateFlags &= ~BGFX_STATE_WRITE_MASK;
cachedStateFlags &= ~BGFX_STATE_CULL_MASK;
cachedStateFlags |= BGFX_STATE_CULL_CW; // Cull back faces
break;
case DepthState::Stencil_IsNotZeroReplace:
// Test stencil < 1, enable blending and color writes
frontStencil = BGFX_STENCIL_TEST_LESS | BGFX_STENCIL_FUNC_REF(1) | BGFX_STENCIL_FUNC_RMASK(0xFF) | BGFX_STENCIL_OP_FAIL_S_KEEP |
BGFX_STENCIL_OP_FAIL_Z_KEEP | BGFX_STENCIL_OP_PASS_Z_KEEP;
backStencil = frontStencil;
// Re-enable color writes, disable culling, enable blending
cachedStateFlags |= BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A;
cachedStateFlags &= ~BGFX_STATE_CULL_MASK;
cachedStateFlags |= BGFX_STATE_CULL_CW | BGFX_STATE_CULL_CCW; // Disable culling
// Enable alpha blending for shadow compositing
cachedStateFlags &= ~BGFX_STATE_BLEND_MASK;
cachedStateFlags |= BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA);
break;
default:
AYAASSERT(false);
}
if (frontStencil != BGFX_STENCIL_NONE || backStencil != BGFX_STENCIL_NONE)
{
bgfx::setStencil(frontStencil, backStencil);
}
}
void DeviceContextBGFX::drawImpl(Geometry* geometry, Geometry::Primitive primitive, unsigned int offset, unsigned int count,
unsigned int indexRangeBegin, unsigned int indexRangeEnd)
{
AYAASSERT(cachedProgram != nullptr);
// Update global constants if needed
if (cachedProgram)
{
cachedProgram->updateGlobalConstants(&globalData[0], globalDataVersion);
}
// Set the accumulated state flags
uint64_t stateFlags = cachedStateFlags;
// Ensure we always write to RGB and A unless masked
if ((stateFlags & BGFX_STATE_WRITE_MASK) == 0)
{
stateFlags |= BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A;
}
bgfx::setState(stateFlags);
// Handle stencil state separately
handleStencilState();
// Set vertex and index buffers - GeometryBGFX handles binding
GeometryBGFX* geometryBGFX = static_cast<GeometryBGFX*>(geometry);
geometryBGFX->bindBuffers(offset, count);
// CRITICAL: Actually submit the draw call with the shader program
// This is what actually triggers rendering in BGFX!
bgfx::submit(currentView, cachedProgram->getHandle());
}
void DeviceContextBGFX::pushDebugMarkerGroup(const char* text)
{
bgfx::setViewName(currentView, text);
}
void DeviceContextBGFX::popDebugMarkerGroup()
{
// BGFX doesn't have a direct equivalent to pop marker groups
// Markers are set per-view
}
void DeviceContextBGFX::setDebugMarker(const char* text)
{
bgfx::setMarker(text);
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,148 @@
#include "FramebufferBGFX.hpp"
#include "TextureBGFX.hpp"
#include "DeviceBGFX.hpp"
#include <bgfx/bgfx.h>
namespace Aya
{
namespace Graphics
{
RenderbufferBGFX::RenderbufferBGFX(Device* device, Texture::Format format, unsigned int width, unsigned int height, unsigned int samples)
: Renderbuffer(device, format, width, height, samples)
{
AYAASSERT(samples);
if (samples > device->getCaps().maxSamples)
{
throw Aya::runtime_error("Unsupported renderbuffer: too many samples (%d)", samples);
}
// Create a texture that will be used as a renderbuffer
bgfx::TextureFormat::Enum bgfxFormat = TextureBGFX::getBGFXFormat(format);
if (bgfxFormat == bgfx::TextureFormat::Unknown)
{
throw Aya::runtime_error("Unsupported renderbuffer format");
}
uint64_t flags = BGFX_TEXTURE_RT;
if (samples > 1)
{
flags |= BGFX_TEXTURE_RT_MSAA_X4; // BGFX has predefined MSAA levels
}
textureHandle = bgfx::createTexture2D(width, height, false, 1, bgfxFormat, flags);
if (!bgfx::isValid(textureHandle))
{
throw Aya::runtime_error("Failed to create renderbuffer texture");
}
}
RenderbufferBGFX::~RenderbufferBGFX()
{
if (bgfx::isValid(textureHandle))
{
bgfx::destroy(textureHandle);
}
}
FramebufferBGFX::FramebufferBGFX(Device* device, bgfx::FrameBufferHandle handle)
: Framebuffer(device, 0, 0, 1)
, handle(handle)
, isMain(true)
{
// Main framebuffer - dimensions will be set by the window
}
FramebufferBGFX::FramebufferBGFX(Device* device, const std::vector<shared_ptr<Renderbuffer>>& color, const shared_ptr<Renderbuffer>& depth)
: Framebuffer(device, 0, 0, 0)
, handle(BGFX_INVALID_HANDLE)
, isMain(false)
, color(color)
, depth(depth)
{
AYAASSERT(!color.empty());
if (color.size() > device->getCaps().maxDrawBuffers)
{
throw Aya::runtime_error("Unsupported framebuffer configuration: too many buffers (%d)", (int)color.size());
}
// Collect all texture handles for the framebuffer
std::vector<bgfx::TextureHandle> textures;
for (size_t i = 0; i < color.size(); ++i)
{
RenderbufferBGFX* buffer = static_cast<RenderbufferBGFX*>(color[i].get());
AYAASSERT(buffer);
AYAASSERT(!Texture::isFormatDepth(buffer->getFormat()));
textures.push_back(buffer->getTextureHandle());
if (i == 0)
{
width = buffer->getWidth();
height = buffer->getHeight();
samples = buffer->getSamples();
}
else
{
AYAASSERT(width == buffer->getWidth());
AYAASSERT(height == buffer->getHeight());
AYAASSERT(samples == buffer->getSamples());
}
}
// Add depth buffer if present
if (depth)
{
RenderbufferBGFX* buffer = static_cast<RenderbufferBGFX*>(depth.get());
AYAASSERT(Texture::isFormatDepth(buffer->getFormat()));
AYAASSERT(width == buffer->getWidth());
AYAASSERT(height == buffer->getHeight());
AYAASSERT(samples == buffer->getSamples());
textures.push_back(buffer->getTextureHandle());
}
// Create framebuffer from textures
handle = bgfx::createFrameBuffer(textures.size(), textures.data(), false);
if (!bgfx::isValid(handle))
{
throw Aya::runtime_error("Failed to create framebuffer");
}
}
FramebufferBGFX::~FramebufferBGFX()
{
if (!isMain && bgfx::isValid(handle))
{
bgfx::destroy(handle);
}
}
void FramebufferBGFX::download(void* data, unsigned int size)
{
AYAASSERT(size == width * height * 4);
// BGFX doesn't support synchronous framebuffer downloads like OpenGL
// You would need to use bgfx::readTexture which is asynchronous
// and requires a callback
// For now, we'll just assert that this isn't implemented
// In a real implementation, you'd need to:
// 1. Create a callback to receive the data
// 2. Call bgfx::readTexture on the color attachment
// 3. Wait for the callback (which might require frame coordination)
AYAASSERT(false && "Framebuffer download not implemented for BGFX");
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,53 @@
#pragma once
#include "Core/Framebuffer.hpp"
#include <bgfx/bgfx.h>
#include <vector>
namespace Aya
{
namespace Graphics
{
class DeviceBGFX;
class TextureBGFX;
class RenderbufferBGFX : public Renderbuffer
{
public:
RenderbufferBGFX(Device* device, Texture::Format format, unsigned int width, unsigned int height, unsigned int samples);
~RenderbufferBGFX();
bgfx::TextureHandle getTextureHandle() const
{
return textureHandle;
}
private:
bgfx::TextureHandle textureHandle;
};
class FramebufferBGFX : public Framebuffer
{
public:
FramebufferBGFX(Device* device, bgfx::FrameBufferHandle handle);
FramebufferBGFX(Device* device, const std::vector<shared_ptr<Renderbuffer>>& color, const shared_ptr<Renderbuffer>& depth);
~FramebufferBGFX();
virtual void download(void* data, unsigned int size);
bgfx::FrameBufferHandle getHandle() const
{
return handle;
}
private:
bgfx::FrameBufferHandle handle;
bool isMain;
std::vector<shared_ptr<Renderbuffer>> color;
shared_ptr<Renderbuffer> depth;
};
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,343 @@
#include "GeometryBGFX.hpp"
#include "DeviceBGFX.hpp"
#include <bgfx/bgfx.h>
namespace Aya
{
namespace Graphics
{
bgfx::Attrib::Enum VertexLayoutBGFX::getAttribType(unsigned int semanticId)
{
switch (semanticId)
{
case 0: // Position
return bgfx::Attrib::Position;
case 1: // Normal
return bgfx::Attrib::Normal;
case 2: // Color0
return bgfx::Attrib::Color0;
case 3: // Color1
return bgfx::Attrib::Color1;
case 4: // TexCoord0
return bgfx::Attrib::TexCoord0;
case 5: // TexCoord1
return bgfx::Attrib::TexCoord1;
case 6: // TexCoord2
return bgfx::Attrib::TexCoord2;
case 7: // TexCoord3
return bgfx::Attrib::TexCoord3;
case 8: // TexCoord4
return bgfx::Attrib::TexCoord4;
case 9: // TexCoord5
return bgfx::Attrib::TexCoord5;
case 10: // TexCoord6
return bgfx::Attrib::TexCoord6;
case 11: // TexCoord7
return bgfx::Attrib::TexCoord7;
default:
return bgfx::Attrib::Count;
}
}
static bgfx::AttribType::Enum getAttribFormat(VertexLayout::Format format)
{
switch (format)
{
case VertexLayout::Format_Float1:
case VertexLayout::Format_Float2:
case VertexLayout::Format_Float3:
case VertexLayout::Format_Float4:
return bgfx::AttribType::Float;
case VertexLayout::Format_Short2:
case VertexLayout::Format_Short4:
return bgfx::AttribType::Int16;
case VertexLayout::Format_UByte4:
case VertexLayout::Format_Color:
return bgfx::AttribType::Uint8;
default:
return bgfx::AttribType::Count;
}
}
static uint8_t getAttribCount(VertexLayout::Format format)
{
switch (format)
{
case VertexLayout::Format_Float1:
return 1;
case VertexLayout::Format_Float2:
case VertexLayout::Format_Short2:
return 2;
case VertexLayout::Format_Float3:
return 3;
case VertexLayout::Format_Float4:
case VertexLayout::Format_Short4:
case VertexLayout::Format_UByte4:
case VertexLayout::Format_Color:
return 4;
default:
return 0;
}
}
static bool isNormalized(VertexLayout::Format format)
{
return format == VertexLayout::Format_Color;
}
static unsigned int getVertexAttributeId(VertexLayout::Semantic semantic, unsigned int index)
{
switch (semantic)
{
case VertexLayout::Semantic_Position:
AYAASSERT(index == 0);
return 0;
case VertexLayout::Semantic_Normal:
AYAASSERT(index == 0);
return 1;
case VertexLayout::Semantic_Color:
AYAASSERT(index < 2);
return 2 + index;
case VertexLayout::Semantic_Texture:
AYAASSERT(index < 8);
return 4 + index;
default:
AYAASSERT(false);
return 0;
}
}
VertexLayoutBGFX::VertexLayoutBGFX(Device* device, const std::vector<Element>& elements)
: VertexLayout(device, elements)
{
layout.begin();
for (size_t i = 0; i < elements.size(); ++i)
{
const Element& e = elements[i];
unsigned int attribId = getVertexAttributeId(e.semantic, e.semanticIndex);
bgfx::Attrib::Enum attrib = getAttribType(attribId);
bgfx::AttribType::Enum type = getAttribFormat(e.format);
uint8_t count = getAttribCount(e.format);
bool normalized = isNormalized(e.format);
layout.add(attrib, count, type, normalized);
}
layout.end();
}
VertexLayoutBGFX::~VertexLayoutBGFX() {}
template<typename Base>
GeometryBufferBGFX<Base>::GeometryBufferBGFX(Device* device, size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage, bool isIndex)
: Base(device, elementSize, elementCount, usage)
, isIndex(isIndex)
, memory(nullptr)
, locked(nullptr)
{
vertexHandle = BGFX_INVALID_HANDLE;
indexHandle = BGFX_INVALID_HANDLE;
}
template<typename Base>
void GeometryBufferBGFX<Base>::create()
{
uint32_t size = this->elementSize * this->elementCount;
if (isIndex)
{
uint16_t flags = (this->usage == GeometryBuffer::Usage_Dynamic) ? BGFX_BUFFER_NONE : BGFX_BUFFER_NONE;
indexHandle = bgfx::createDynamicIndexBuffer(this->elementCount, flags);
}
else
{
// Vertex buffers need a layout - we'll create the handle later in GeometryBGFX
// when we have access to the actual layout
vertexHandle = BGFX_INVALID_HANDLE;
}
}
template<typename Base>
void GeometryBufferBGFX<Base>::createVertexBuffer(const bgfx::VertexLayout& layout)
{
AYAASSERT(!isIndex);
AYAASSERT(!bgfx::isValid(vertexHandle));
uint16_t flags = (this->usage == GeometryBuffer::Usage_Dynamic) ? BGFX_BUFFER_NONE : BGFX_BUFFER_NONE;
vertexHandle = bgfx::createDynamicVertexBuffer(this->elementCount, layout, flags);
}
template<typename Base>
GeometryBufferBGFX<Base>::~GeometryBufferBGFX()
{
AYAASSERT(!locked);
if (bgfx::isValid(vertexHandle))
{
bgfx::destroy(vertexHandle);
}
if (bgfx::isValid(indexHandle))
{
bgfx::destroy(indexHandle);
}
}
template<typename Base>
void* GeometryBufferBGFX<Base>::lock(GeometryBuffer::LockMode mode)
{
AYAASSERT(!locked);
unsigned int size = this->elementSize * this->elementCount;
// Allocate temporary buffer
locked = new char[size];
AYAASSERT(locked);
return locked;
}
template<typename Base>
void GeometryBufferBGFX<Base>::unlock()
{
AYAASSERT(locked);
// Upload data to BGFX
upload(0, locked, this->elementSize * this->elementCount);
delete[] static_cast<char*>(locked);
locked = nullptr;
}
template<typename Base>
void GeometryBufferBGFX<Base>::upload(unsigned int offset, const void* data, unsigned int size)
{
AYAASSERT(!locked);
AYAASSERT(offset + size <= this->elementSize * this->elementCount);
const bgfx::Memory* mem = bgfx::copy(static_cast<const char*>(data) + offset, size);
if (isIndex)
{
if (bgfx::isValid(indexHandle))
{
bgfx::update(indexHandle, 0, mem);
}
}
else
{
if (bgfx::isValid(vertexHandle))
{
bgfx::update(vertexHandle, 0, mem);
}
}
}
VertexBufferBGFX::VertexBufferBGFX(Device* device, size_t elementSize, size_t elementCount, Usage usage)
: GeometryBufferBGFX<VertexBuffer>(device, elementSize, elementCount, usage, false)
{
create();
}
VertexBufferBGFX::~VertexBufferBGFX() {}
IndexBufferBGFX::IndexBufferBGFX(Device* device, size_t elementSize, size_t elementCount, Usage usage)
: GeometryBufferBGFX<IndexBuffer>(device, elementSize, elementCount, usage, true)
{
if (elementSize != 2 && elementSize != 4)
throw Aya::runtime_error("Invalid element size: %d", (int)elementSize);
create();
}
IndexBufferBGFX::~IndexBufferBGFX() {}
GeometryBGFX::GeometryBGFX(Device* device, const shared_ptr<VertexLayout>& layout, const std::vector<shared_ptr<VertexBuffer>>& vertexBuffers,
const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex)
: Geometry(device, layout, vertexBuffers, indexBuffer, baseVertexIndex)
, indexElementSize(0)
{
if (indexBuffer)
{
indexElementSize = indexBuffer->getElementSize();
}
// Create vertex buffers with proper layout
VertexLayoutBGFX* layoutBGFX = static_cast<VertexLayoutBGFX*>(layout.get());
const bgfx::VertexLayout& bgfxLayout = layoutBGFX->getBGFXLayout();
for (size_t i = 0; i < vertexBuffers.size(); ++i)
{
VertexBufferBGFX* vb = static_cast<VertexBufferBGFX*>(vertexBuffers[i].get());
// Create the vertex buffer handle with the layout if not already created
if (!bgfx::isValid(vb->getVertexHandle()))
{
vb->createVertexBuffer(bgfxLayout);
}
}
}
GeometryBGFX::~GeometryBGFX() {}
void GeometryBGFX::bindBuffers(unsigned int offset, unsigned int count)
{
// Set vertex buffers
for (size_t i = 0; i < vertexBuffers.size(); ++i)
{
VertexBufferBGFX* vb = static_cast<VertexBufferBGFX*>(vertexBuffers[i].get());
if (bgfx::isValid(vb->getVertexHandle()))
{
bgfx::setVertexBuffer(i, vb->getVertexHandle(), baseVertexIndex, vb->getElementCount());
}
}
// Set index buffer if present
if (indexBuffer)
{
IndexBufferBGFX* ib = static_cast<IndexBufferBGFX*>(indexBuffer.get());
if (bgfx::isValid(ib->getIndexHandle()))
{
bgfx::setIndexBuffer(ib->getIndexHandle(), offset, count);
}
}
}
uint64_t GeometryBGFX::convertPrimitive(Primitive primitive)
{
// This function is not used in BGFX - primitives are set via state flags
// Keeping for potential future use
switch (primitive)
{
case Primitive_Triangles:
return BGFX_STATE_PT_TRISTRIP;
case Primitive_Lines:
return BGFX_STATE_PT_LINES;
case Primitive_Points:
return BGFX_STATE_PT_POINTS;
case Primitive_TriangleStrip:
return BGFX_STATE_PT_TRISTRIP;
default:
return BGFX_STATE_PT_TRISTRIP;
}
}
void GeometryBGFX::draw(bgfx::ViewId view, Primitive primitive, unsigned int offset, unsigned int count)
{
// Legacy method - not used anymore
// Drawing is now handled by bindBuffers() + bgfx::submit() in DeviceContextBGFX::drawImpl()
}
// Explicit template instantiation
template class GeometryBufferBGFX<VertexBuffer>;
template class GeometryBufferBGFX<IndexBuffer>;
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,100 @@
#pragma once
#include "Core/Geometry.hpp"
#include <bgfx/bgfx.h>
namespace Aya
{
namespace Graphics
{
class DeviceBGFX;
class VertexLayoutBGFX : public VertexLayout
{
public:
VertexLayoutBGFX(Device* device, const std::vector<Element>& elements);
~VertexLayoutBGFX();
const bgfx::VertexLayout& getBGFXLayout() const
{
return layout;
}
static bgfx::Attrib::Enum getAttribType(unsigned int semanticId);
private:
bgfx::VertexLayout layout;
};
template<typename Base>
class GeometryBufferBGFX : public Base
{
public:
GeometryBufferBGFX(Device* device, size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage, bool isIndex);
~GeometryBufferBGFX();
virtual void* lock(GeometryBuffer::LockMode mode);
virtual void unlock();
virtual void upload(unsigned int offset, const void* data, unsigned int size);
void createVertexBuffer(const bgfx::VertexLayout& layout);
bgfx::DynamicVertexBufferHandle getVertexHandle() const
{
return vertexHandle;
}
bgfx::DynamicIndexBufferHandle getIndexHandle() const
{
return indexHandle;
}
const bgfx::Memory* getMemory() const
{
return memory;
}
protected:
void create();
private:
bool isIndex;
bgfx::DynamicVertexBufferHandle vertexHandle;
bgfx::DynamicIndexBufferHandle indexHandle;
const bgfx::Memory* memory;
void* locked;
};
class VertexBufferBGFX : public GeometryBufferBGFX<VertexBuffer>
{
public:
VertexBufferBGFX(Device* device, size_t elementSize, size_t elementCount, Usage usage);
~VertexBufferBGFX();
};
class IndexBufferBGFX : public GeometryBufferBGFX<IndexBuffer>
{
public:
IndexBufferBGFX(Device* device, size_t elementSize, size_t elementCount, Usage usage);
~IndexBufferBGFX();
};
class GeometryBGFX : public Geometry
{
public:
GeometryBGFX(Device* device, const shared_ptr<VertexLayout>& layout, const std::vector<shared_ptr<VertexBuffer>>& vertexBuffers,
const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex);
~GeometryBGFX();
void bindBuffers(unsigned int offset, unsigned int count);
void draw(bgfx::ViewId view, Primitive primitive, unsigned int offset, unsigned int count);
private:
unsigned int indexElementSize;
static uint64_t convertPrimitive(Primitive primitive);
};
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,14 @@
#pragma once
// BGFX headers
#include <bgfx/bgfx.h>
#include <bgfx/platform.h>
// Common macros
#ifndef AYAASSERT
#define AYAASSERT(x) assert(x)
#endif
#ifndef ARRAYSIZE
#define ARRAYSIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif

View File

@@ -0,0 +1,293 @@
#include "ShaderBGFX.hpp"
#include "DeviceBGFX.hpp"
#include "GeometryBGFX.hpp"
#include <bgfx/bgfx.h>
LOGGROUP(Graphics)
namespace Aya
{
namespace Graphics
{
VertexShaderBGFX::VertexShaderBGFX(Device* device, const std::vector<char>& bytecode)
: VertexShader(device)
{
const bgfx::Memory* mem = bgfx::copy(bytecode.data(), bytecode.size());
handle = bgfx::createShader(mem);
if (!bgfx::isValid(handle))
{
throw std::runtime_error("Failed to create vertex shader");
}
}
VertexShaderBGFX::~VertexShaderBGFX()
{
if (bgfx::isValid(handle))
{
bgfx::destroy(handle);
}
}
void VertexShaderBGFX::reloadBytecode(const std::vector<char>& bytecode)
{
if (bgfx::isValid(handle))
{
bgfx::destroy(handle);
}
const bgfx::Memory* mem = bgfx::copy(bytecode.data(), bytecode.size());
handle = bgfx::createShader(mem);
if (!bgfx::isValid(handle))
{
throw std::runtime_error("Failed to reload vertex shader");
}
}
FragmentShaderBGFX::FragmentShaderBGFX(Device* device, const std::vector<char>& bytecode)
: FragmentShader(device)
{
const bgfx::Memory* mem = bgfx::copy(bytecode.data(), bytecode.size());
handle = bgfx::createShader(mem);
if (!bgfx::isValid(handle))
{
throw std::runtime_error("Failed to create fragment shader");
}
}
FragmentShaderBGFX::~FragmentShaderBGFX()
{
if (bgfx::isValid(handle))
{
bgfx::destroy(handle);
}
}
void FragmentShaderBGFX::reloadBytecode(const std::vector<char>& bytecode)
{
if (bgfx::isValid(handle))
{
bgfx::destroy(handle);
}
const bgfx::Memory* mem = bgfx::copy(bytecode.data(), bytecode.size());
handle = bgfx::createShader(mem);
if (!bgfx::isValid(handle))
{
throw std::runtime_error("Failed to reload fragment shader");
}
}
ShaderProgramBGFX::ShaderProgramBGFX(Device* device, const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader)
: ShaderProgram(device, vertexShader, fragmentShader)
, cachedGlobalVersion(0)
, maxWorldTransforms(0)
, samplerMask(0)
, nextConstantHandle(0)
{
VertexShaderBGFX* vs = static_cast<VertexShaderBGFX*>(vertexShader.get());
FragmentShaderBGFX* fs = static_cast<FragmentShaderBGFX*>(fragmentShader.get());
handle = bgfx::createProgram(vs->getHandle(), fs->getHandle(), false);
if (!bgfx::isValid(handle))
{
throw std::runtime_error("Failed to create shader program");
}
// Create uniforms for world matrices
worldMatrixUniform = bgfx::createUniform("u_worldMatrix", bgfx::UniformType::Mat4);
worldMatrixArrayUniform = bgfx::createUniform("u_worldMatrixArray", bgfx::UniformType::Vec4);
if (bgfx::isValid(worldMatrixArrayUniform))
{
maxWorldTransforms = 32; // Default maximum, can be adjusted
}
else if (bgfx::isValid(worldMatrixUniform))
{
maxWorldTransforms = 1;
}
// In BGFX, samplers are bound separately, so we'll assume all texture stages could be used
samplerMask = 0xFFFF;
}
ShaderProgramBGFX::~ShaderProgramBGFX()
{
if (bgfx::isValid(handle))
{
bgfx::destroy(handle);
}
if (bgfx::isValid(worldMatrixUniform))
{
bgfx::destroy(worldMatrixUniform);
}
if (bgfx::isValid(worldMatrixArrayUniform))
{
bgfx::destroy(worldMatrixArrayUniform);
}
// Destroy all created uniforms
for (auto& pair : uniforms)
{
if (bgfx::isValid(pair.second.handle))
{
bgfx::destroy(pair.second.handle);
}
}
}
int ShaderProgramBGFX::getConstantHandle(const char* name) const
{
// Check if we already have this uniform
for (const auto& pair : handleToName)
{
if (pair.second == name)
{
return pair.first;
}
}
// Create new handle - we need to make this non-const to modify handleToName
// In practice, this is fine as we're just caching uniform lookups
ShaderProgramBGFX* mutableThis = const_cast<ShaderProgramBGFX*>(this);
// Create uniform on first use
std::string uniformName = name;
bgfx::UniformHandle uniformHandle = bgfx::createUniform(uniformName.c_str(), bgfx::UniformType::Vec4);
if (bgfx::isValid(uniformHandle))
{
int handle = mutableThis->nextConstantHandle++;
UniformInfo info;
info.handle = uniformHandle;
info.type = bgfx::UniformType::Vec4;
info.size = 1;
mutableThis->uniforms[uniformName] = info;
mutableThis->handleToName[handle] = uniformName;
return handle;
}
return -1;
}
unsigned int ShaderProgramBGFX::getMaxWorldTransforms() const
{
return maxWorldTransforms;
}
unsigned int ShaderProgramBGFX::getSamplerMask() const
{
return samplerMask;
}
void ShaderProgramBGFX::updateGlobalConstants(const void* globalData, unsigned int globalVersion)
{
if (cachedGlobalVersion == globalVersion)
return;
cachedGlobalVersion = globalVersion;
// Update global constants
const std::vector<ShaderGlobalConstant>& globalConstants = static_cast<DeviceBGFX*>(device)->getGlobalConstants();
for (size_t i = 0; i < globalConstants.size(); ++i)
{
const ShaderGlobalConstant& gc = globalConstants[i];
// Check if we have a uniform for this constant
auto it = uniforms.find(gc.name);
if (it == uniforms.end())
{
// Create uniform on first use
std::string uniformName = gc.name;
bgfx::UniformHandle uniformHandle = bgfx::createUniform(uniformName.c_str(), bgfx::UniformType::Vec4);
if (bgfx::isValid(uniformHandle))
{
UniformInfo info;
info.handle = uniformHandle;
info.type = bgfx::UniformType::Vec4;
info.size = 1;
uniforms[uniformName] = info;
it = uniforms.find(uniformName);
}
else
{
continue;
}
}
const float* data = reinterpret_cast<const float*>(static_cast<const char*>(globalData) + gc.offset);
bgfx::setUniform(it->second.handle, data);
}
}
void ShaderProgramBGFX::setWorldTransforms4x3(const float* data, size_t matrixCount)
{
if (matrixCount == 0)
return;
if (matrixCount == 1 && bgfx::isValid(worldMatrixUniform))
{
// Convert 4x3 matrix to 4x4
float matrix[16];
matrix[0] = data[0];
matrix[1] = data[1];
matrix[2] = data[2];
matrix[3] = 0.0f;
matrix[4] = data[4];
matrix[5] = data[5];
matrix[6] = data[6];
matrix[7] = 0.0f;
matrix[8] = data[8];
matrix[9] = data[9];
matrix[10] = data[10];
matrix[11] = 0.0f;
matrix[12] = data[12];
matrix[13] = data[13];
matrix[14] = data[14];
matrix[15] = 1.0f;
bgfx::setUniform(worldMatrixUniform, matrix);
}
else if (bgfx::isValid(worldMatrixArrayUniform))
{
AYAASSERT(matrixCount <= maxWorldTransforms);
// Pass array of vec4s (3 per matrix for 4x3)
bgfx::setUniform(worldMatrixArrayUniform, data, matrixCount * 3);
}
}
void ShaderProgramBGFX::setConstant(int handle, const float* data, size_t vectorCount)
{
if (handle < 0)
return;
auto it = handleToName.find(handle);
if (it == handleToName.end())
return;
auto uniformIt = uniforms.find(it->second);
if (uniformIt == uniforms.end())
return;
bgfx::setUniform(uniformIt->second.handle, data, vectorCount);
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,93 @@
#pragma once
#include "Core/Shader.hpp"
#include <bgfx/bgfx.h>
#include <vector>
#include <map>
namespace Aya
{
namespace Graphics
{
class DeviceBGFX;
class VertexShaderBGFX : public VertexShader
{
public:
VertexShaderBGFX(Device* device, const std::vector<char>& bytecode);
~VertexShaderBGFX();
virtual void reloadBytecode(const std::vector<char>& bytecode);
bgfx::ShaderHandle getHandle() const
{
return handle;
}
private:
bgfx::ShaderHandle handle;
};
class FragmentShaderBGFX : public FragmentShader
{
public:
FragmentShaderBGFX(Device* device, const std::vector<char>& bytecode);
~FragmentShaderBGFX();
virtual void reloadBytecode(const std::vector<char>& bytecode);
bgfx::ShaderHandle getHandle() const
{
return handle;
}
private:
bgfx::ShaderHandle handle;
};
class ShaderProgramBGFX : public ShaderProgram
{
public:
ShaderProgramBGFX(Device* device, const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader);
~ShaderProgramBGFX();
virtual int getConstantHandle(const char* name) const;
virtual unsigned int getMaxWorldTransforms() const;
virtual unsigned int getSamplerMask() const;
void updateGlobalConstants(const void* globalData, unsigned int globalVersion);
void setWorldTransforms4x3(const float* data, size_t matrixCount);
void setConstant(int handle, const float* data, size_t vectorCount);
bgfx::ProgramHandle getHandle() const
{
return handle;
}
private:
bgfx::ProgramHandle handle;
struct UniformInfo
{
bgfx::UniformHandle handle;
bgfx::UniformType::Enum type;
unsigned int size;
};
std::map<std::string, UniformInfo> uniforms;
std::map<int, std::string> handleToName;
bgfx::UniformHandle worldMatrixUniform;
bgfx::UniformHandle worldMatrixArrayUniform;
unsigned int cachedGlobalVersion;
unsigned int maxWorldTransforms;
unsigned int samplerMask;
int nextConstantHandle;
};
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,269 @@
#include "TextureBGFX.hpp"
#include "DeviceBGFX.hpp"
#include "FramebufferBGFX.hpp"
#include <bgfx/bgfx.h>
LOGGROUP(Graphics)
namespace Aya
{
namespace Graphics
{
bgfx::TextureFormat::Enum TextureBGFX::getBGFXFormat(Format format)
{
switch (format)
{
case Format_L8:
return bgfx::TextureFormat::R8;
case Format_LA8:
return bgfx::TextureFormat::RG8;
case Format_RGB5A1:
return bgfx::TextureFormat::RGB5A1;
case Format_RGBA8:
return bgfx::TextureFormat::RGBA8;
case Format_RG16:
return bgfx::TextureFormat::RG16;
case Format_RGBA16F:
return bgfx::TextureFormat::RGBA16F;
case Format_BC1:
return bgfx::TextureFormat::BC1;
case Format_BC2:
return bgfx::TextureFormat::BC2;
case Format_BC3:
return bgfx::TextureFormat::BC3;
case Format_PVRTC_RGB2:
return bgfx::TextureFormat::PTC12;
case Format_PVRTC_RGBA2:
return bgfx::TextureFormat::PTC12A;
case Format_PVRTC_RGB4:
return bgfx::TextureFormat::PTC14;
case Format_PVRTC_RGBA4:
return bgfx::TextureFormat::PTC14A;
case Format_ETC1:
return bgfx::TextureFormat::ETC1;
case Format_D16:
return bgfx::TextureFormat::D16;
case Format_D24S8:
return bgfx::TextureFormat::D24S8;
default:
return bgfx::TextureFormat::Unknown;
}
}
static uint64_t getBGFXTextureFlags(Texture::Usage usage, unsigned int mipLevels)
{
uint64_t flags = BGFX_TEXTURE_NONE;
if (usage == Texture::Usage_Renderbuffer)
{
flags |= BGFX_TEXTURE_RT;
}
if (mipLevels > 1)
{
flags |= BGFX_TEXTURE_NONE; // Mips are created by default
}
return flags;
}
static uint32_t getBGFXSamplerFlags(const SamplerState& state)
{
uint32_t flags = BGFX_SAMPLER_NONE;
// Filter mode
switch (state.getFilter())
{
case SamplerState::Filter_Point:
flags |= BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT;
break;
case SamplerState::Filter_Linear:
flags |= BGFX_SAMPLER_MIN_ANISOTROPIC | BGFX_SAMPLER_MAG_ANISOTROPIC;
break;
case SamplerState::Filter_Anisotropic:
flags |= BGFX_SAMPLER_MIN_ANISOTROPIC | BGFX_SAMPLER_MAG_ANISOTROPIC;
break;
}
// Address mode
switch (state.getAddress())
{
case SamplerState::Address_Wrap:
// Wrap is the default - no flags needed
break;
case SamplerState::Address_Clamp:
flags |= BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP | BGFX_SAMPLER_W_CLAMP;
break;
}
return flags;
}
TextureBGFX::TextureBGFX(
Device* device, Type type, Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels, Usage usage)
: Texture(device, type, format, width, height, depth, mipLevels, usage)
, cachedState(SamplerState::Filter_Count)
{
bgfx::TextureFormat::Enum bgfxFormat = getBGFXFormat(format);
if (bgfxFormat == bgfx::TextureFormat::Unknown)
{
throw Aya::runtime_error("Unsupported texture format");
}
uint64_t flags = getBGFXTextureFlags(usage, mipLevels);
if (type == Type_3D)
{
handle = bgfx::createTexture3D(width, height, depth, mipLevels > 1, bgfxFormat, flags);
}
else if (type == Type_Cube)
{
handle = bgfx::createTextureCube(width, mipLevels > 1, 1, bgfxFormat, flags);
}
else if (type == Type_2DMultisampled)
{
handle = bgfx::createTexture2D(width, height, mipLevels > 1, 1, bgfxFormat, flags | BGFX_TEXTURE_RT_MSAA_X4);
}
else // Type_2D
{
handle = bgfx::createTexture2D(width, height, mipLevels > 1, 1, bgfxFormat, flags);
}
if (!bgfx::isValid(handle))
{
throw Aya::runtime_error("Failed to create texture");
}
}
TextureBGFX::~TextureBGFX()
{
if (bgfx::isValid(handle))
{
bgfx::destroy(handle);
}
}
void TextureBGFX::upload(unsigned int index, unsigned int mip, const TextureRegion& region, const void* data, unsigned int size)
{
AYAASSERT(index < (type == Type_Cube ? 6u : 1u));
AYAASSERT(mip < mipLevels);
unsigned int mipWidth = getMipSide(width, mip);
unsigned int mipHeight = getMipSide(height, mip);
unsigned int mipDepth = getMipSide(depth, mip);
AYAASSERT(region.x + region.width <= mipWidth);
AYAASSERT(region.y + region.height <= mipHeight);
AYAASSERT(region.z + region.depth <= mipDepth);
AYAASSERT(size == getImageSize(format, region.width, region.height) * region.depth);
const bgfx::Memory* mem = bgfx::copy(data, size);
if (type == Type_3D)
{
bgfx::updateTexture3D(handle, mip, region.x, region.y, region.z, region.width, region.height, region.depth, mem);
}
else if (type == Type_Cube)
{
bgfx::updateTextureCube(handle, 0, index, mip, region.x, region.y, region.width, region.height, mem);
}
else
{
bgfx::updateTexture2D(handle, 0, mip, region.x, region.y, region.width, region.height, mem);
}
}
bool TextureBGFX::download(unsigned int index, unsigned int mip, void* data, unsigned int size)
{
// BGFX doesn't support direct texture download in the same way as GL
// This would require reading from a framebuffer that the texture is attached to
const DeviceCapsBGFX& caps = static_cast<DeviceBGFX*>(device)->getCapsBGFX();
if (!caps.supportsTextureReadBack)
{
return false;
}
// Reading back texture data would require creating a framebuffer and using bgfx::readTexture
// which is async in BGFX
return false;
}
bool TextureBGFX::supportsLocking() const
{
// BGFX doesn't support texture locking in the traditional sense
return false;
}
Texture::LockResult TextureBGFX::lock(unsigned int index, unsigned int mip, const TextureRegion& region)
{
// BGFX doesn't support direct texture locking
LockResult result = {0, 0, 0};
return result;
}
void TextureBGFX::unlock(unsigned int index, unsigned int mip)
{
// BGFX doesn't support direct texture locking
}
shared_ptr<Renderbuffer> TextureBGFX::getRenderbuffer(unsigned int index, unsigned int mip)
{
AYAASSERT(index < (type == Type_Cube ? 6u : 1u));
AYAASSERT(mip < mipLevels);
AYAASSERT(usage == Usage_Renderbuffer);
std::pair<unsigned, unsigned> key(index, mip);
shared_ptr<Renderbuffer> result = renderBuffers[key].lock();
if (!result)
{
result.reset(new RenderbufferBGFX(device, format, getMipSide(width, mip), getMipSide(height, mip), getType() == Type_2DMultisampled ? 4 : 1));
renderBuffers[key] = result;
}
return result;
}
void TextureBGFX::commitChanges()
{
// BGFX handles texture updates immediately
// No deferred commit needed
}
void TextureBGFX::generateMipmaps()
{
// BGFX generates mipmaps automatically when creating textures with mipLevels > 1
// Or we can request regeneration if needed
// Note: Not all backends support runtime mipmap generation
}
void TextureBGFX::bind(unsigned int stage, const SamplerState& state)
{
uint32_t samplerFlags = getBGFXSamplerFlags(state);
// In BGFX, textures are set per-draw call, not globally
// We just set the texture and sampler for the given stage
// Note: This requires a valid sampler uniform handle to be passed from the caller
bgfx::setTexture(stage, BGFX_INVALID_HANDLE, handle, samplerFlags);
cachedState = state;
}
void TextureBGFX::bindWithUniform(unsigned int stage, bgfx::UniformHandle samplerUniform, const SamplerState& state)
{
uint32_t samplerFlags = getBGFXSamplerFlags(state);
// Set texture with the proper sampler uniform
bgfx::setTexture(stage, samplerUniform, handle, samplerFlags);
cachedState = state;
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,57 @@
#pragma once
#include "Core/Texture.hpp"
#include "Core/States.hpp"
#include <bgfx/bgfx.h>
#include <boost/enable_shared_from_this.hpp>
#include <map>
namespace Aya
{
namespace Graphics
{
class DeviceBGFX;
class TextureBGFX
: public Texture
, public boost::enable_shared_from_this<TextureBGFX>
{
public:
TextureBGFX(
Device* device, Type type, Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels, Usage usage);
~TextureBGFX();
virtual void upload(unsigned int index, unsigned int mip, const TextureRegion& region, const void* data, unsigned int size);
virtual bool download(unsigned int index, unsigned int mip, void* data, unsigned int size);
virtual bool supportsLocking() const;
virtual LockResult lock(unsigned int index, unsigned int mip, const TextureRegion& region);
virtual void unlock(unsigned int index, unsigned int mip);
virtual shared_ptr<Renderbuffer> getRenderbuffer(unsigned int index, unsigned int mip);
virtual void commitChanges();
virtual void generateMipmaps();
void bind(unsigned int stage, const SamplerState& state);
void bindWithUniform(unsigned int stage, bgfx::UniformHandle samplerUniform, const SamplerState& state);
bgfx::TextureHandle getHandle() const
{
return handle;
}
static bgfx::TextureFormat::Enum getBGFXFormat(Format format);
private:
bgfx::TextureHandle handle;
SamplerState cachedState;
typedef std::map<std::pair<unsigned, unsigned>, weak_ptr<Renderbuffer>> RenderBufferMap;
RenderBufferMap renderBuffers;
};
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,201 @@
#include "ContextGL.hpp"
#include "HeadersGL.hpp"
#include "Debug.hpp"
#include <glad/egl.h>
#include <wayland-client.h>
#include <wayland-egl.h>
#include <X11/Xlib.h>
#include <EGL/eglext.h>
#include <cstdlib>
LOGGROUP(Graphics)
namespace Aya
{
namespace Graphics
{
enum class DisplayBackend
{
Wayland,
X11,
Unknown
};
static DisplayBackend detectDisplayBackend()
{
const char* waylandDisplay = std::getenv("WAYLAND_DISPLAY");
const char* x11Display = std::getenv("DISPLAY");
if (waylandDisplay && waylandDisplay[0])
return DisplayBackend::Wayland;
if (x11Display && x11Display[0])
return DisplayBackend::X11;
return DisplayBackend::Unknown;
}
class ContextEGL : public ContextGL
{
public:
ContextEGL(void* windowHandle, void* windowScreen, int w, int h)
{
DisplayBackend backend = detectDisplayBackend();
// Load core EGL API
gladLoaderLoadEGL(nullptr);
// Load required EGL extensions
auto eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
auto eglCreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
if (!eglGetPlatformDisplayEXT || !eglCreatePlatformWindowSurfaceEXT)
throw Aya::runtime_error("Missing required EGL extension functions");
// Create EGL display based on backend
if (backend == DisplayBackend::Wayland)
{
wl_display* wlDisplay = static_cast<wl_display*>(windowScreen);
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, wlDisplay, nullptr);
}
else if (backend == DisplayBackend::X11)
{
::Display* x11Display = static_cast<::Display*>(windowScreen);
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, x11Display, nullptr);
}
else
{
throw Aya::runtime_error("Unknown or unsupported display backend");
}
if (display == EGL_NO_DISPLAY)
throw Aya::runtime_error("eglGetPlatformDisplayEXT failed: %x", eglGetError());
if (!eglInitialize(display, nullptr, nullptr))
throw Aya::runtime_error("eglInitialize failed: %x", eglGetError());
if (!gladLoaderLoadEGL(display))
throw Aya::runtime_error("gladLoaderLoadEGL failed");
// EGL Config
static const EGLint configAttribs[] = {EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE,
8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8, EGL_NONE};
EGLint numConfigs;
if (!eglChooseConfig(display, configAttribs, &config, 1, &numConfigs) || numConfigs == 0)
throw Aya::runtime_error("eglChooseConfig failed: %x", eglGetError());
// Surface creation
if (windowHandle)
{
if (backend == DisplayBackend::Wayland)
{
surface = eglCreatePlatformWindowSurfaceEXT(display, config, windowHandle, nullptr);
}
else // X11
{
surface = eglCreatePlatformWindowSurfaceEXT(display, config, windowHandle, nullptr);
}
}
else
{
// Create pbuffer
static const EGLint pbufferAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
surface = eglCreatePbufferSurface(display, config, pbufferAttribs);
}
if (surface == EGL_NO_SURFACE)
throw Aya::runtime_error("Failed to create EGL surface: %x", eglGetError());
// Bind OpenGL API
eglBindAPI(EGL_OPENGL_API);
static const EGLint contextAttribs[] = {EGL_CONTEXT_MAJOR_VERSION, 3, EGL_CONTEXT_MINOR_VERSION, 3, EGL_CONTEXT_OPENGL_PROFILE_MASK,
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
#ifndef NDEBUG
EGL_CONTEXT_OPENGL_DEBUG, EGL_TRUE,
#endif
EGL_NONE};
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
if (context == EGL_NO_CONTEXT)
throw Aya::runtime_error("eglCreateContext failed: %x", eglGetError());
if (!eglMakeCurrent(display, surface, surface, context))
throw Aya::runtime_error("eglMakeCurrent failed: %x", eglGetError());
gladLoaderLoadGL();
}
virtual void setCurrent() override
{
eglMakeCurrent(display, surface, surface, context);
}
virtual void swapBuffers() override
{
eglSwapBuffers(display, surface);
}
virtual unsigned int getMainFramebufferId() override
{
return 0;
}
virtual bool isMainFramebufferRetina() override
{
return false;
}
void resizeWindow(int w, int h)
{
if (egl_window)
{
wl_egl_window_resize(egl_window, w, h, 0, 0);
}
}
virtual std::pair<unsigned int, unsigned int> updateMainFramebuffer(unsigned int width, unsigned int height) override
{
EGLint w, h;
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
return std::make_pair((unsigned int)w, (unsigned int)h);
}
virtual ~ContextEGL()
{
if (display != EGL_NO_DISPLAY)
{
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (context != EGL_NO_CONTEXT)
eglDestroyContext(display, context);
if (surface != EGL_NO_SURFACE)
eglDestroySurface(display, surface);
eglTerminate(display);
}
if (egl_window)
{
wl_egl_window_destroy(egl_window);
egl_window = nullptr;
}
}
private:
EGLDisplay display = EGL_NO_DISPLAY;
EGLContext context = EGL_NO_CONTEXT;
EGLSurface surface = EGL_NO_SURFACE;
EGLConfig config = nullptr;
wl_egl_window* egl_window = nullptr;
};
ContextGL* ContextGL::create(void* windowHandle, void* display, int w, int h)
{
return new ContextEGL(windowHandle, display, w, h);
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,28 @@
#pragma once
#include <utility>
namespace Aya
{
namespace Graphics
{
class ContextGL
{
public:
static ContextGL* create(void* windowHandle, void* display, int w, int h);
virtual ~ContextGL() {}
virtual void setCurrent() = 0;
virtual void swapBuffers() = 0;
virtual unsigned int getMainFramebufferId() = 0;
virtual bool isMainFramebufferRetina() = 0;
virtual std::pair<unsigned int, unsigned int> updateMainFramebuffer(unsigned int width, unsigned int height) = 0;
virtual void resizeWindow(int width, int height) = 0;
};
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,286 @@
#include "ContextGL.hpp"
#include "HeadersGL.hpp"
#include "Debug.hpp"
#include <android/native_window.h>
#include <EGL/egl.h>
LOGGROUP(Graphics)
// GL extensions
static GLvoid(GL_APIENTRY* glBindVertexArrayPtr)(GLuint array);
static GLvoid(GL_APIENTRY* glDeleteVertexArraysPtr)(GLsizei n, const GLuint* arrays);
static GLvoid(GL_APIENTRY* glGenVertexArraysPtr)(GLsizei n, const GLuint* arrays);
static GLvoid*(GL_APIENTRY* glMapBufferPtr)(GLenum target, GLenum access);
static GLboolean(GL_APIENTRY* glUnmapBufferPtr)(GLenum target);
static GLvoid*(GL_APIENTRY* glMapBufferRangePtr)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
static GLvoid(GL_APIENTRY* glTexImage3DPtr)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLenum format, GLenum type, const GLvoid* pixels);
static GLvoid(GL_APIENTRY* glTexSubImage3DPtr)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height,
GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
static GLvoid(GL_APIENTRY* glTexStorage2DPtr)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
static GLvoid(GL_APIENTRY* glTexStorage3DPtr)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
static GLsync(GL_APIENTRY* glFenceSyncPtr)(GLenum condition, GLbitfield flags);
static void(GL_APIENTRY* glDeleteSyncPtr)(GLsync sync);
static GLenum(GL_APIENTRY* glClientWaitSyncPtr)(GLsync sync, GLbitfield flags, GLuint64 timeout);
static void(GL_APIENTRY* glWaitSyncPtr)(GLsync sync, GLbitfield flags, GLuint64 timeout);
static GLvoid(GL_APIENTRY* glBlitFramebufferPtr)(
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
static GLvoid(GL_APIENTRY* glRenderbufferStorageMultisamplePtr)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
static GLvoid(GL_APIENTRY* glInvalidateFramebufferPtr)(GLenum target, GLsizei numAttachments, const GLenum* attachments);
template<typename T>
static void loadExtensionGL(T& ptr, const char* namecore, const char* nameext)
{
if (!ptr)
ptr = reinterpret_cast<T>(eglGetProcAddress(namecore));
if (!ptr)
ptr = reinterpret_cast<T>(eglGetProcAddress(nameext));
}
#define LOAD_EXTENSION_GL(name, suffix) loadExtensionGL(name##Ptr, #name, #name #suffix)
// GL stubs
GLvoid glBindVertexArray(GLuint array)
{
glBindVertexArrayPtr(array);
}
GLvoid glDeleteVertexArrays(GLsizei n, const GLuint* arrays)
{
glDeleteVertexArraysPtr(n, arrays);
}
GLvoid glGenVertexArrays(GLsizei n, GLuint* arrays)
{
glGenVertexArraysPtr(n, arrays);
}
GLvoid* glMapBuffer(GLenum target, GLenum access)
{
return glMapBufferPtr(target, access);
}
GLboolean glUnmapBuffer(GLenum target)
{
return glUnmapBufferPtr(target);
}
GLvoid* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
{
return glMapBufferRangePtr(target, offset, length, access);
}
GLvoid glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
{
glTexStorage2DPtr(target, levels, internalformat, width, height);
}
GLvoid glTexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format,
GLenum type, const GLvoid* pixels)
{
glTexImage3DPtr(target, level, internalFormat, width, height, depth, border, format, type, pixels);
}
GLvoid glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const GLvoid* pixels)
{
glTexSubImage3DPtr(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
}
GLvoid glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
{
glTexStorage3DPtr(target, levels, internalformat, width, height, depth);
}
GLsync glFenceSync(GLenum condition, GLbitfield flags)
{
return glFenceSyncPtr(condition, flags);
}
void glDeleteSync(GLsync sync)
{
glDeleteSyncPtr(sync);
}
GLenum glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
{
return glClientWaitSyncPtr(sync, flags, timeout);
}
void glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
{
glWaitSyncPtr(sync, flags, timeout);
}
GLvoid glBlitFramebuffer(
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
{
glBlitFramebufferPtr(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
}
GLvoid glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
{
glRenderbufferStorageMultisamplePtr(target, samples, internalformat, width, height);
}
GLvoid glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments)
{
glInvalidateFramebufferPtr(target, numAttachments, attachments);
}
namespace Aya
{
namespace Graphics
{
class ContextGLAndroid : public ContextGL
{
public:
ContextGLAndroid(void* windowHandle)
{
aNativeWindow = static_cast<ANativeWindow*>(windowHandle);
ANativeWindow_acquire(aNativeWindow);
FASTLOG2(FLog::Graphics, "Window size: %dx%d", ANativeWindow_getWidth(aNativeWindow), ANativeWindow_getHeight(aNativeWindow));
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY)
throw runtime_error("Error creating context: eglGetDisplay %x", eglGetError());
if (!eglInitialize(display, 0, 0))
throw runtime_error("Error creating context: eglInitialize %x", eglGetError());
EGLConfig config;
if (!tryChooseConfig(display, &config, 8, 8, 8, 24, 0) && !tryChooseConfig(display, &config, 8, 8, 8, 16, 0) &&
!tryChooseConfig(display, &config, 5, 6, 5, 16, 0) && !tryChooseConfig(display, &config, 8, 8, 8, 24, 1) &&
!tryChooseConfig(display, &config, 8, 8, 8, 16, 1) && !tryChooseConfig(display, &config, 5, 6, 5, 16, 1))
throw runtime_error("Error creating context: could not find suitable config (%x)", eglGetError());
surface = eglCreateWindowSurface(display, config, aNativeWindow, 0);
if (!surface)
{
throw runtime_error("Error creating context: eglCreateWindowSurface %x", eglGetError());
}
static const EGLint contextAttrs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
context = eglCreateContext(display, config, NULL, contextAttrs);
if (!context)
throw runtime_error("Error creating context: eglCreateContext %x", eglGetError());
if (!eglMakeCurrent(display, surface, surface, context))
throw runtime_error("Error creating context: eglMakeCurrent %x", eglGetError());
eglQuerySurface(display, surface, EGL_WIDTH, &surfaceWidth);
eglQuerySurface(display, surface, EGL_HEIGHT, &surfaceHeight);
FASTLOG4(FLog::Graphics, "Initialized EGL context %p (surface %p) with renderbuffer %dx%d", context, surface, surfaceWidth, surfaceHeight);
EGLint minSwapInterval = -1;
eglGetConfigAttrib(display, config, EGL_MIN_SWAP_INTERVAL, &minSwapInterval);
FASTLOG1(FLog::Graphics, "EGL_MIN_SWAP_INTERVAL: %d", minSwapInterval);
if (eglSwapInterval(display, 0) == EGL_FALSE)
{
// This should be impossible as the interval is silently clamped to EGL_MIN_SWAP_INTERVAL.
FASTLOG(FLog::Graphics, "*** eglSwapInterval EGL_FALSE");
}
LOAD_EXTENSION_GL(glBindVertexArray, OES);
LOAD_EXTENSION_GL(glDeleteVertexArrays, OES);
LOAD_EXTENSION_GL(glGenVertexArrays, OES);
LOAD_EXTENSION_GL(glMapBuffer, OES);
LOAD_EXTENSION_GL(glUnmapBuffer, OES);
LOAD_EXTENSION_GL(glMapBufferRange, EXT);
LOAD_EXTENSION_GL(glTexImage3D, OES);
LOAD_EXTENSION_GL(glTexSubImage3D, OES);
LOAD_EXTENSION_GL(glTexStorage2D, EXT);
LOAD_EXTENSION_GL(glTexStorage3D, EXT);
LOAD_EXTENSION_GL(glFenceSync, EXT);
LOAD_EXTENSION_GL(glDeleteSync, EXT);
LOAD_EXTENSION_GL(glClientWaitSync, EXT);
LOAD_EXTENSION_GL(glWaitSync, EXT);
LOAD_EXTENSION_GL(glBlitFramebuffer, EXT);
LOAD_EXTENSION_GL(glRenderbufferStorageMultisample, EXT);
LOAD_EXTENSION_GL(glInvalidateFramebuffer, EXT);
}
~ContextGLAndroid()
{
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(display, context);
eglDestroySurface(display, surface);
eglTerminate(display);
ANativeWindow_release(aNativeWindow);
}
virtual void setCurrent()
{
bool result = eglMakeCurrent(display, surface, surface, context);
AYAASSERT(result);
}
virtual void swapBuffers()
{
bool result = eglSwapBuffers(display, surface);
AYAASSERT(result);
}
virtual unsigned int getMainFramebufferId()
{
return 0;
}
virtual bool isMainFramebufferRetina()
{
return false;
}
virtual void resizeWindow(int w, int h)
{
return;
}
virtual std::pair<unsigned int, unsigned int> updateMainFramebuffer(unsigned int width, unsigned int height)
{
return std::make_pair(surfaceWidth, surfaceHeight);
}
private:
ANativeWindow* aNativeWindow;
EGLDisplay display;
EGLSurface surface;
EGLContext context;
EGLint surfaceWidth;
EGLint surfaceHeight;
static bool tryChooseConfig(EGLDisplay display, EGLConfig* config, int redBits, int greenBits, int blueBits, int depthBits, int swapInterval)
{
const EGLint attribs[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_MIN_SWAP_INTERVAL, swapInterval, EGL_RED_SIZE, redBits, EGL_GREEN_SIZE,
greenBits, EGL_BLUE_SIZE, blueBits, EGL_DEPTH_SIZE, depthBits, EGL_NONE};
FASTLOG4(FLog::Graphics, "Trying to choose EGL config r%d g%d b%d d%d", redBits, greenBits, blueBits, depthBits);
EGLint numConfigs = 0;
return eglChooseConfig(display, attribs, config, 1, &numConfigs) && numConfigs > 0;
}
};
ContextGL* ContextGL::create(void* windowHandle, void* display, int w, int h)
{
return new ContextGLAndroid(windowHandle);
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,177 @@
#include "ContextGL.hpp"
#include "HeadersGL.hpp"
#include "Debug.hpp"
#ifdef __APPLE__
#import <Cocoa/Cocoa.h>
#import <OpenGL/OpenGL.h>
#import <OpenGL/gl3.h>
#endif
LOGGROUP(Graphics)
namespace Aya
{
namespace Graphics
{
#ifdef __APPLE__
class ContextGLMacOS : public ContextGL
{
public:
ContextGLMacOS(void* windowHandle)
{
// Handle both NSWindow and NSView (Qt widgets)
NSView* view = (__bridge NSView*)windowHandle;
if (!view) {
printf("ERROR: Invalid window/view handle\n");
return;
}
// Determine if it's a window or view
NSWindow* window = nil;
NSView* targetView = view;
if ([view isKindOfClass:[NSWindow class]]) {
window = (NSWindow*)view;
targetView = [window contentView];
nsWindow = window;
} else {
// If it's a view, try to get its window
window = [view window];
targetView = view;
nsWindow = window;
}
if (!targetView) {
printf("ERROR: Could not get target view\n");
return;
}
printf("Creating native macOS OpenGL context...\n");
// Create OpenGL pixel format
NSOpenGLPixelFormatAttribute attrs[] = {
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 24,
NSOpenGLPFAStencilSize, 8,
NSOpenGLPFAColorSize, 24,
NSOpenGLPFAAlphaSize, 8,
NSOpenGLPFAAccelerated,
NSOpenGLPFANoRecovery,
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
0
};
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
if (!pixelFormat) {
printf("Failed to create OpenGL pixel format\n");
return;
}
// Create OpenGL context
glContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
if (!glContext) {
printf("Failed to create OpenGL context\n");
return;
}
// Set the target view
[glContext setView:targetView];
// Make context current
[glContext makeCurrentContext];
printf("Context created and made current successfully\n");
// Test OpenGL
const GLubyte* version = glGetString(GL_VERSION);
if (version) {
printf("OpenGL Version: %s\n", version);
}
const GLubyte* vendor = glGetString(GL_VENDOR);
if (vendor) {
printf("OpenGL Vendor: %s\n", vendor);
}
const GLubyte* renderer = glGetString(GL_RENDERER);
if (renderer) {
printf("OpenGL Renderer: %s\n", renderer);
}
}
~ContextGLMacOS()
{
if (glContext) {
[NSOpenGLContext clearCurrentContext];
}
}
virtual void setCurrent() override
{
if (glContext) {
[glContext makeCurrentContext];
}
}
virtual void swapBuffers() override
{
if (glContext) {
[glContext flushBuffer];
}
}
virtual unsigned int getMainFramebufferId() override
{
return 0; // Default framebuffer on macOS
}
virtual bool isMainFramebufferRetina() override
{
if (!nsWindow) return false;
NSScreen* screen = [nsWindow screen];
if (!screen) return false;
return [screen backingScaleFactor] > 1.0;
}
virtual std::pair<unsigned int, unsigned int> updateMainFramebuffer(unsigned int width, unsigned int height) override
{
if (!nsWindow) {
return std::make_pair(width, height);
}
NSView* contentView = [nsWindow contentView];
if (!contentView) {
return std::make_pair(width, height);
}
NSRect contentRect = [contentView bounds];
NSRect backingRect = [contentView convertRectToBacking:contentRect];
return std::make_pair((unsigned int)backingRect.size.width,
(unsigned int)backingRect.size.height);
}
virtual void resizeWindow(int w, int h) override
{
return;
}
private:
NSWindow* nsWindow;
NSOpenGLContext* glContext;
NSOpenGLPixelFormat* pixelFormat;
};
#endif
ContextGL* ContextGL::create(void* windowHandle, void* display, int w, int h)
{
return new ContextGLMacOS(windowHandle);
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,146 @@
#include "ContextGL.hpp"
#include "HeadersGL.hpp"
#include "Debug.hpp"
#include <Windows.h>
#include <glad/gl.h>
#include <glad/wgl.h>
#include "Utility/StandardOut.hpp"
FASTFLAG(DebugGraphicsGL)
namespace Aya
{
namespace Graphics
{
class ContextGLWin32 : public ContextGL
{
public:
ContextGLWin32(void* windowHandle)
: hwnd(reinterpret_cast<HWND>(windowHandle))
, hdc(GetDC(hwnd))
, hglrc(NULL)
{
PIXELFORMATDESCRIPTOR pfd = {};
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cAlphaBits = 8;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
int pf = ChoosePixelFormat(hdc, &pfd);
if (!pf)
throw Aya::runtime_error("Error choosing pixel format: %x", GetLastError());
if (!SetPixelFormat(hdc, pf, &pfd))
throw Aya::runtime_error("Error setting pixel format: %x", GetLastError());
hglrc = wglCreateContext(hdc);
if (!hglrc)
throw Aya::runtime_error("Error creating context: %x", GetLastError());
if (!wglMakeCurrent(hdc, hglrc))
throw Aya::runtime_error("Error changing context: %x", GetLastError());
if (!gladLoaderLoadWGL(hdc))
throw Aya::runtime_error("Failed to initialize GLAD WGL with hdc");
// Initialize GLAD
if (!gladLoaderLoadGL())
throw Aya::runtime_error("Failed to initialize GLAD");
if (GLAD_WGL_ARB_create_context)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hglrc);
const int attribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 2, 0, 0};
hglrc = wglCreateContextAttribsARB(hdc, NULL, attribs);
if (!hglrc)
throw Aya::runtime_error("Error creating context: %x", GetLastError());
if (!wglMakeCurrent(hdc, hglrc))
throw Aya::runtime_error("Error changing context: %x", GetLastError());
// Reinitialize GLAD with the new context
if (!gladLoaderLoadGL())
throw Aya::runtime_error("Failed to reinitialize GLAD");
}
if (GLAD_WGL_EXT_swap_control)
wglSwapIntervalEXT(0);
}
~ContextGLWin32()
{
if (wglGetCurrentContext() == hglrc)
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hglrc);
}
virtual void setCurrent()
{
if (wglGetCurrentContext() != hglrc)
{
BOOL result = wglMakeCurrent(hdc, hglrc);
AYAASSERT(result);
}
}
virtual void swapBuffers()
{
AYAASSERT(wglGetCurrentContext() == hglrc);
SwapBuffers(hdc);
}
virtual unsigned int getMainFramebufferId()
{
return 0;
}
virtual bool isMainFramebufferRetina()
{
return false;
}
virtual std::pair<unsigned int, unsigned int> updateMainFramebuffer(unsigned int width, unsigned int height)
{
RECT rect = {};
GetClientRect(hwnd, &rect);
return std::make_pair(rect.right - rect.left, rect.bottom - rect.top);
}
virtual void resizeWindow(int w, int h)
{
return;
}
private:
HWND hwnd;
HDC hdc;
HGLRC hglrc;
};
ContextGL* ContextGL::create(void* windowHandle, void* display, int w, int h)
{
return new ContextGLWin32(windowHandle);
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,513 @@
#include "DeviceGL.hpp"
#include "GeometryGL.hpp"
#include "ShaderGL.hpp"
#include "TextureGL.hpp"
#include "FramebufferGL.hpp"
#include "HeadersGL.hpp"
#ifdef AYA_OS_WINDOWS
#include <Windows.h>
#endif
FASTFLAGVARIABLE(GraphicsGLUseDiscard, false)
namespace Aya
{
namespace Graphics
{
static const GLenum gCullModeGL[RasterizerState::Cull_Count] = {GL_NONE, GL_BACK, GL_FRONT};
struct BlendFuncGL
{
GLenum src, dst;
};
static const GLenum gBlendFactorsGL[BlendState::Factor_Count] = {
GL_ONE, GL_ZERO, GL_DST_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA};
static const GLenum gDepthFuncGL[DepthState::Function_Count] = {GL_ALWAYS, GL_LESS, GL_LEQUAL};
DeviceContextGL::DeviceContextGL(DeviceGL* dev)
: globalDataVersion(0)
, device(dev)
, defaultAnisotropy(1)
, cachedProgram(0)
, cachedRasterizerState(RasterizerState::Cull_None)
, cachedBlendState(BlendState::Mode_None)
, cachedDepthState(DepthState::Function_Always, false)
{
for (size_t i = 0; i < ARRAYSIZE(cachedTextures); ++i)
cachedTextures[i] = NULL;
}
DeviceContextGL::~DeviceContextGL() {}
void DeviceContextGL::clearStates()
{
// Clear framebuffer cache
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Clear program cache
cachedProgram = 0;
glUseProgram(0);
// Clear texture cache
for (size_t i = 0; i < ARRAYSIZE(cachedTextures); ++i)
cachedTextures[i] = NULL;
// Clear states to invalid values to guarantee a cache miss on the next setup
cachedRasterizerState = RasterizerState(RasterizerState::Cull_Count);
cachedBlendState = BlendState(BlendState::Mode_Count);
cachedDepthState = DepthState(DepthState::Function_Count, false);
// Setup state we never touch once
#ifndef GLES
glEnable(GL_PROGRAM_POINT_SIZE);
#endif
}
void DeviceContextGL::invalidateCachedProgram()
{
cachedProgram = 0;
}
void DeviceContextGL::invalidateCachedTexture(Texture* texture)
{
for (unsigned int stage = 0; stage < ARRAYSIZE(cachedTextures); ++stage)
if (cachedTextures[stage] == texture)
cachedTextures[stage] = NULL;
}
void DeviceContextGL::invalidateCachedTextureStage(unsigned int stage)
{
AYAASSERT(stage < ARRAYSIZE(cachedTextures));
cachedTextures[stage] = NULL;
}
void DeviceContextGL::defineGlobalConstants(size_t dataSize)
{
AYAASSERT(globalData.empty());
AYAASSERT(dataSize > 0);
globalData.resize(dataSize);
}
void DeviceContextGL::setDefaultAnisotropy(unsigned int value)
{
defaultAnisotropy = value;
}
void DeviceContextGL::updateGlobalConstants(const void* data, size_t dataSize)
{
AYAASSERT(dataSize == globalData.size());
memcpy(&globalData[0], data, dataSize);
globalDataVersion++;
}
void DeviceContextGL::bindFramebuffer(Framebuffer* buffer)
{
unsigned int drawId = static_cast<FramebufferGL*>(buffer)->getId();
glBindFramebuffer(GL_FRAMEBUFFER, drawId);
glViewport(0, 0, buffer->getWidth(), buffer->getHeight());
#ifndef GLES
unsigned int drawBuffers = static_cast<FramebufferGL*>(buffer)->getDrawBuffers();
if (drawId == 0)
{
glDrawBuffer(GL_BACK);
}
else if (glDrawBuffers)
{
GLenum buffers[16];
AYAASSERT(drawBuffers < ARRAYSIZE(buffers));
for (unsigned int i = 0; i < drawBuffers; ++i)
buffers[i] = GL_COLOR_ATTACHMENT0 + i;
glDrawBuffers(drawBuffers, buffers);
}
#endif
}
void DeviceContextGL::clearFramebuffer(unsigned int mask, const float color[4], float depth, unsigned int stencil)
{
unsigned int maskGl = 0;
if (mask & Buffer_Color)
{
// Need color writes for color clear to work
setBlendState(BlendState(BlendState::Mode_None, BlendState::Color_All));
maskGl |= GL_COLOR_BUFFER_BIT;
glClearColor(color[0], color[1], color[2], color[3]);
}
if (mask & Buffer_Depth)
{
// Need depth writes for depth clear to work
setDepthState(DepthState(DepthState::Function_Always, true));
maskGl |= GL_DEPTH_BUFFER_BIT;
glClearDepth(depth);
}
if (mask & Buffer_Stencil)
{
// Need stencil writes for stencil clear to work
glStencilMask(~0u);
maskGl |= GL_STENCIL_BUFFER_BIT;
glClearStencil(stencil);
}
AYAASSERT(maskGl);
glClear(maskGl);
}
void DeviceContextGL::copyFramebuffer(Framebuffer* buffer, Texture* texture, int xOffset, int yOffset)
{
AYAASSERT(texture->getType() == Texture::Type_2D);
AYAASSERT(buffer->getWidth() == texture->getWidth() && buffer->getHeight() == texture->getHeight());
invalidateCachedTextureStage(0);
GLint oldfb = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb);
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<FramebufferGL*>(buffer)->getId());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, static_cast<TextureGL*>(texture)->getId());
#ifndef GLES
glReadBuffer(GL_COLOR_ATTACHMENT0);
#endif
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, -xOffset, yOffset, texture->getWidth(), texture->getHeight());
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, oldfb);
}
void DeviceContextGL::resolveFramebuffer(Framebuffer* msaaBuffer, Framebuffer* buffer, unsigned int mask)
{
AYAASSERT(msaaBuffer->getSamples() > 1);
AYAASSERT(buffer->getSamples() == 1);
AYAASSERT(msaaBuffer->getWidth() == buffer->getWidth() && msaaBuffer->getHeight() == buffer->getHeight());
GLint oldfb = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb);
glBindFramebuffer(GL_READ_FRAMEBUFFER, static_cast<FramebufferGL*>(msaaBuffer)->getId());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, static_cast<FramebufferGL*>(buffer)->getId());
if (mask & Buffer_Color)
{
#ifndef GLES
glReadBuffer(GL_COLOR_ATTACHMENT0);
#endif
glBlitFramebuffer(
0, 0, buffer->getWidth(), buffer->getHeight(), 0, 0, buffer->getWidth(), buffer->getHeight(), GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
if (mask & (Buffer_Depth | Buffer_Stencil))
{
unsigned int maskGl = 0;
if (mask & Buffer_Depth)
maskGl |= GL_DEPTH_BUFFER_BIT;
if (mask & Buffer_Stencil)
maskGl |= GL_STENCIL_BUFFER_BIT;
glBlitFramebuffer(0, 0, buffer->getWidth(), buffer->getHeight(), 0, 0, buffer->getWidth(), buffer->getHeight(), maskGl, GL_NEAREST);
}
glBindFramebuffer(GL_FRAMEBUFFER, oldfb);
}
void DeviceContextGL::discardFramebuffer(Framebuffer* buffer, unsigned int mask)
{
if (!device->getCapsGL().ext3)
return;
if (!FFlag::GraphicsGLUseDiscard)
return;
unsigned int drawBuffers = static_cast<FramebufferGL*>(buffer)->getDrawBuffers();
GLenum attachments[16];
unsigned int index = 0;
if (mask & Buffer_Color)
for (unsigned int i = 0; i < drawBuffers; ++i)
attachments[index++] = GL_COLOR_ATTACHMENT0 + i;
if (mask & Buffer_Depth)
attachments[index++] = GL_DEPTH_ATTACHMENT;
if (mask & Buffer_Stencil)
attachments[index++] = GL_STENCIL_ATTACHMENT;
if (index > 0)
{
GLint oldfb = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb);
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<FramebufferGL*>(buffer)->getId());
glInvalidateFramebuffer(GL_FRAMEBUFFER, index, attachments);
glBindFramebuffer(GL_FRAMEBUFFER, oldfb);
}
}
void DeviceContextGL::bindProgram(ShaderProgram* program)
{
static_cast<ShaderProgramGL*>(program)->bind(&globalData[0], globalDataVersion, &cachedProgram);
}
void DeviceContextGL::setWorldTransforms4x3(const float* data, size_t matrixCount)
{
cachedProgram->setWorldTransforms4x3(data, matrixCount);
}
void DeviceContextGL::setConstant(int handle, const float* data, size_t vectorCount)
{
cachedProgram->setConstant(handle, data, vectorCount);
}
void DeviceContextGL::bindTexture(unsigned int stage, Texture* texture, const SamplerState& state)
{
SamplerState realState = (state.getFilter() == SamplerState::Filter_Anisotropic && state.getAnisotropy() == 0)
? SamplerState(state.getFilter(), state.getAddress(), defaultAnisotropy)
: state;
AYAASSERT(stage < device->getCaps().maxTextureUnits);
AYAASSERT(stage < ARRAYSIZE(cachedTextures));
static_cast<TextureGL*>(texture)->bind(stage, realState, &cachedTextures[stage]);
}
void DeviceContextGL::setRasterizerState(const RasterizerState& state)
{
if (cachedRasterizerState != state)
{
cachedRasterizerState = state;
if (state.getCullMode() == RasterizerState::Cull_None)
{
glDisable(GL_CULL_FACE);
}
else
{
glEnable(GL_CULL_FACE);
glCullFace(gCullModeGL[state.getCullMode()]);
}
if (state.getDepthBias() == 0)
{
glDisable(GL_POLYGON_OFFSET_FILL);
}
else
{
float bias = static_cast<float>(state.getDepthBias());
float slopeBias = bias / 32.f; // do we need explicit control over slope or just a better formula since these numbers are magic anyway?
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(slopeBias, bias);
}
}
}
void DeviceContextGL::setBlendState(const BlendState& state)
{
if (cachedBlendState != state)
{
cachedBlendState = state;
unsigned int colorMask = state.getColorMask();
glColorMask((colorMask & BlendState::Color_R) != 0, (colorMask & BlendState::Color_G) != 0, (colorMask & BlendState::Color_B) != 0,
(colorMask & BlendState::Color_A) != 0);
if (!state.blendingNeeded())
{
glDisable(GL_BLEND);
}
else
{
glEnable(GL_BLEND);
if (!state.separateAlphaBlend())
glBlendFunc(gBlendFactorsGL[state.getColorSrc()], gBlendFactorsGL[state.getColorDst()]);
else
glBlendFuncSeparate(gBlendFactorsGL[state.getColorSrc()], gBlendFactorsGL[state.getColorDst()], gBlendFactorsGL[state.getAlphaSrc()],
gBlendFactorsGL[state.getAlphaDst()]);
}
}
}
void DeviceContextGL::setDepthState(const DepthState& state)
{
if (cachedDepthState != state)
{
cachedDepthState = state;
if (state.getFunction() != DepthState::Function_None && state.getFunction() == DepthState::Function_Always && !state.getWrite())
{
glDisable(GL_DEPTH_TEST);
}
else
{
if (state.getFunction() != DepthState::Function_None)
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(gDepthFuncGL[state.getFunction()]);
glDepthMask(state.getWrite());
}
}
switch (state.getStencilMode())
{
case DepthState::Stencil_None:
glDisable(GL_STENCIL_TEST);
break;
case DepthState::Stencil_IsNotZero:
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_NOTEQUAL, 0, ~0u);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
break;
case DepthState::Stencil_UpdateZFail:
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, ~0u);
glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR_WRAP, GL_KEEP);
glStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR_WRAP, GL_KEEP);
break;
case DepthState::Stencil_Increment:
// disable writing to color & depth buffers
// clear stencil buffer
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glClear(GL_STENCIL_BUFFER_BIT);
glDepthMask(GL_FALSE);
glEnable(GL_DEPTH_CLAMP);
// enable face culling
glEnable(GL_CULL_FACE);
// enable stencil testing, always pass
glEnable(GL_STENCIL_TEST);
glEnable(GL_DEPTH_TEST);
glStencilMask(~0u);
// (?) not sure what exactly this is supposed to do, added based on analysis of the framebuffer of the graphics pipeline in older clients
glDepthFunc(GL_LESS);
// increase for back faces, decrease stencil bit for front faces
glCullFace(GL_FRONT);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP);
glStencilFunc(GL_ALWAYS, 0, ~0u);
break;
case DepthState::Stencil_Decrement:
glCullFace(GL_BACK);
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP);
glStencilFunc(GL_ALWAYS, 0, ~0u);
break;
case DepthState::Stencil_IsNotZeroReplace:
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_CLAMP);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_FALSE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_LESS, 0x01, ~0u);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glDepthFunc(GL_LEQUAL);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
default:
AYAASSERT(false);
}
}
}
void DeviceContextGL::drawImpl(Geometry* geometry, Geometry::Primitive primitive, unsigned int offset, unsigned int count,
unsigned int indexRangeBegin, unsigned int indexRangeEnd)
{
static_cast<GeometryGL*>(geometry)->draw(primitive, offset, count);
}
//////////////////////////////////////////////////////////////////////////
// Markers:
void DeviceContextGL::pushDebugMarkerGroup(const char* text)
{
#ifdef AYA_PLATFORM_IOS
if (device->getCapsGL().extDebugMarkers)
{
glPushGroupMarkerEXT(0, text);
}
#elif defined(__ANDROID__)
;
#else
if (glPushDebugGroup) // Requires GL4.3, because ARB-version does not have marker enums for type
{
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION_ARB, 0, -1, text);
}
#endif
}
void DeviceContextGL::popDebugMarkerGroup()
{
#ifdef AYA_PLATFORM_IOS
if (device->getCapsGL().extDebugMarkers)
{
glPopGroupMarkerEXT();
}
#elif defined(__ANDROID__)
;
#else
if (glPopDebugGroup) // Requires GL4.3, because ARB-version does not have marker enums for type
{
glPopDebugGroup();
}
#endif
}
void DeviceContextGL::setDebugMarker(const char* text)
{
#ifdef AYA_PLATFORM_IOS
if (device->getCapsGL().extDebugMarkers)
{
glInsertEventMarkerEXT(0, text);
}
#elif defined(__ANDROID__)
;
#else
if (glDebugMessageInsert) // Requires GL4.3, because ARB-version does not have marker enums for type
{
glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_MARKER, 0, GL_DEBUG_SEVERITY_NOTIFICATION, -1, text);
}
#endif
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,617 @@
#include "DeviceGL.hpp"
#include "GeometryGL.hpp"
#include "ShaderGL.hpp"
#include "TextureGL.hpp"
#include "FramebufferGL.hpp"
#include "ContextGL.hpp"
#include "HeadersGL.hpp"
#include "Profiler.hpp"
#include "ImGui.hpp"
#include <set>
#include <sstream>
#if defined(__linux) || defined(__APPLE__)
// https://stackoverflow.com/questions/33257597/segmentation-fault-in-c-linux-but-not-in-windows
#include <string.h>
#endif
LOGGROUP(Graphics)
FASTFLAGVARIABLE(DebugGraphicsGL, false)
FASTFLAGVARIABLE(GraphicsGL3, true)
FASTFLAGVARIABLE(GraphicsGLReduceLatency, true)
namespace Aya
{
namespace Graphics
{
static std::set<std::string> getExtensions()
{
std::set<std::string> result;
if (const char* extensionString = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)))
{
std::istringstream ext(extensionString);
std::string str;
while (ext >> str)
result.insert(str);
return result;
}
#ifndef GLES
if (FFlag::GraphicsGL3 && GLAD_GL_VERSION_3_0)
{
int extensionCount = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount);
for (int i = 0; i < extensionCount; ++i)
result.insert(reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i)));
}
#endif
return result;
}
#ifdef GLES
static DeviceCapsGL createDeviceCaps(ContextGL* context, const std::set<std::string>& extensions)
{
const char* renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
const char* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
bool version3 = FFlag::GraphicsGL3 && strncmp(version, "OpenGL ES ", 10) == 0 && version[10] >= '3';
DeviceCapsGL caps;
GLint texSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
GLint stencilBits;
glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
caps.supportsFramebuffer = true;
caps.supportsShaders = true;
caps.supportsFFP = false;
caps.supportsStencil = stencilBits >= 8;
caps.supportsIndex32 = version3 || extensions.count("GL_OES_element_index_uint");
caps.supportsTextureDXT = false;
caps.supportsTexturePVR = extensions.count("GL_IMG_texture_compression_pvrtc");
caps.supportsTextureHalfFloat = version3 || extensions.count("GL_OES_texture_half_float");
caps.supportsTexture3D = version3;
caps.supportsTextureNPOT = version3;
caps.supportsTextureETC1 = extensions.count("GL_OES_compressed_ETC1_RGB8_texture");
caps.supportsTexturePartialMipChain =
version3 || extensions.count("GL_APPLE_texture_max_level") || (!FFlag::GraphicsGL3 && strstr(version, "OpenGL ES 3"));
caps.maxDrawBuffers = 1;
if (version3)
{
GLint samples = 1;
glGetIntegerv(GL_MAX_SAMPLES, &samples);
caps.maxSamples = samples;
}
else
{
caps.maxSamples = 1;
}
caps.maxTextureSize = texSize;
caps.maxTextureUnits = version3 ? 16 : 8;
caps.colorOrderBGR = false;
caps.needsHalfPixelOffset = false;
caps.requiresRenderTargetFlipping = true;
caps.retina = context->isMainFramebufferRetina();
caps.ext3 = version3;
caps.extVertexArrayObject = version3 || (extensions.count("GL_OES_vertex_array_object") && !strstr(renderer, "Adreno"));
caps.extTextureStorage = version3 || extensions.count("GL_EXT_texture_storage");
caps.extMapBuffer = version3 || extensions.count("GL_OES_mapbuffer");
caps.extMapBufferRange = version3 || extensions.count("GL_EXT_map_buffer_range");
caps.extTimerQuery = false;
caps.extDebugMarkers = extensions.count("GL_EXT_debug_marker");
caps.extSync = version3;
return caps;
}
#else
static DeviceCapsGL createDeviceCapsOld(ContextGL* context)
{
DeviceCapsGL caps;
GLint texSize = 0;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
GLint stencilBits = 0;
glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
caps.supportsFramebuffer = GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_framebuffer_object || GLAD_GL_EXT_framebuffer_object;
caps.supportsShaders = GLAD_GL_VERSION_2_0 || (GLAD_GL_ARB_shading_language_100 && GLAD_GL_ARB_shader_objects && GLAD_GL_ARB_fragment_shader &&
GLAD_GL_ARB_vertex_shader);
caps.supportsFFP = false;
caps.supportsStencil = GLAD_GL_VERSION_2_0 && stencilBits >= 8; // we need full two-sided stencil support
caps.supportsIndex32 = true;
caps.supportsTextureDXT = (GLAD_GL_VERSION_1_3 || GLAD_GL_ARB_texture_compression) && GLAD_GL_EXT_texture_compression_s3tc;
caps.supportsTexturePVR = false;
caps.supportsTextureHalfFloat = !!GLAD_GL_ARB_half_float_pixel;
caps.supportsTexture3D = GLAD_GL_VERSION_1_2 || GLAD_GL_EXT_texture3D;
caps.supportsTextureETC1 = false;
caps.supportsTexturePartialMipChain = true;
// According to http://aras-p.info/blog/2012/10/17/non-power-of-two-textures/, GL extensions lie
caps.supportsTextureNPOT = GLAD_GL_ARB_texture_non_power_of_two && texSize >= 8192;
if (caps.supportsFramebuffer && (GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_draw_buffers || GLAD_GL_ATI_draw_buffers))
{
GLint drawBuffers = 0;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &drawBuffers);
caps.maxDrawBuffers = drawBuffers;
}
else
{
caps.maxDrawBuffers = 1;
}
if (caps.supportsFramebuffer && (GLAD_GL_VERSION_3_3 || GLAD_GL_EXT_framebuffer_multisample))
{
GLint samples = 0;
glGetIntegerv(GL_MAX_SAMPLES, &samples);
caps.maxSamples = samples;
}
else
{
caps.maxSamples = 1;
}
caps.maxTextureSize = texSize;
caps.maxTextureUnits = 16;
caps.colorOrderBGR = false;
caps.needsHalfPixelOffset = false;
caps.requiresRenderTargetFlipping = true;
caps.retina = context->isMainFramebufferRetina();
caps.ext3 = false;
caps.extVertexArrayObject = (GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_vertex_array_object || GLAD_GL_APPLE_vertex_array_object);
caps.extTextureStorage = GLAD_GL_ARB_texture_storage;
caps.extMapBuffer = true;
caps.extMapBufferRange = (GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_map_buffer_range);
caps.extTimerQuery = !!GLAD_GL_EXT_timer_query;
caps.extDebugMarkers = false;
caps.extSync = (GLAD_GL_VERSION_3_2 || GLAD_GL_ARB_sync);
#ifdef _WIN32
const char* vendorString = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
if (strstr(vendorString, "Intel"))
{
// Intel drivers don't store IB state as part of VAO (http://stackoverflow.com/questions/8973690/vao-and-element-array-buffer-state)
caps.extVertexArrayObject = false;
}
if (strstr(vendorString, "ATI Technologies"))
{
// Some AMD drivers can't create cubemaps with TS and can create 3D textures that they can't update afterwards...
caps.extTextureStorage = false;
}
#endif
return caps;
}
static DeviceCapsGL createDeviceCaps(ContextGL* context, const std::set<std::string>& extensions)
{
// if (!FFlag::GraphicsGL3)
// return createDeviceCapsOld(context);
const char* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
bool version3 = isdigit(version[0]) && version[0] >= '3';
DeviceCapsGL caps;
GLint texSize = 0;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
GLint stencilBits = 0;
glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
caps.supportsFramebuffer = version3 || (extensions.count("GL_ARB_framebuffer_object") || extensions.count("GL_EXT_framebuffer_object"));
caps.supportsShaders = version3 || GLAD_GL_VERSION_2_0 ||
// need this for Mac OpenGL 1.4 :-/
(extensions.count("GL_ARB_shading_language_100") && extensions.count("GL_ARB_shader_objects") &&
extensions.count("GL_ARB_fragment_shader") && extensions.count("GL_ARB_vertex_shader"));
caps.supportsFFP = false;
caps.supportsStencil = GLAD_GL_VERSION_2_0 && stencilBits >= 8; // we need full two-sided stencil support
caps.supportsIndex32 = true;
caps.supportsTextureDXT = !!extensions.count("GL_EXT_texture_compression_s3tc");
caps.supportsTexturePVR = false;
caps.supportsTextureHalfFloat = version3;
caps.supportsTexture3D = true;
caps.supportsTextureETC1 = false;
caps.supportsTexturePartialMipChain = true;
caps.supportsTextureNPOT = version3;
if (version3)
{
GLint drawBuffers = 0;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &drawBuffers);
GLint samples = 0;
glGetIntegerv(GL_MAX_SAMPLES, &samples);
caps.maxDrawBuffers = drawBuffers;
caps.maxSamples = samples;
}
else
{
caps.maxDrawBuffers = 1;
caps.maxSamples = 1;
}
caps.maxTextureSize = texSize;
caps.maxTextureUnits = 16;
caps.colorOrderBGR = false;
caps.needsHalfPixelOffset = false;
caps.requiresRenderTargetFlipping = true;
caps.retina = context->isMainFramebufferRetina();
caps.ext3 = version3;
caps.extVertexArrayObject = version3;
caps.extTextureStorage = GLAD_GL_ARB_texture_storage || (version3 && extensions.count("GL_ARB_texture_storage"));
caps.extMapBuffer = true;
caps.extMapBufferRange = version3;
caps.extTimerQuery = !!GLAD_GL_VERSION_3_3;
caps.extDebugMarkers = false;
caps.extSync = !!GLAD_GL_VERSION_3_2;
return caps;
}
static void GLAPIENTRY debugOutputGLARB(
GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const GLvoid* userParam)
{
FASTLOGS(FLog::Graphics, "GL Debug: %s", message);
}
#endif
DeviceGL::DeviceGL(void* windowHandle, void* display, int w, int h)
: frameTimeQueryId(0)
, frameTimeQueryIssued(false)
, frameEventQueryId(0)
, frameEventQueryIssued(false)
, gpuTime(0)
{
glContext.reset(ContextGL::create(windowHandle, display, w, h));
std::set<std::string> extensions = getExtensions();
caps = createDeviceCaps(glContext.get(), extensions);
FASTLOGS(FLog::Graphics, "GL Renderer: %s", reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
FASTLOGS(FLog::Graphics, "GL Version: %s", reinterpret_cast<const char*>(glGetString(GL_VERSION)));
FASTLOGS(FLog::Graphics, "GL Vendor: %s", reinterpret_cast<const char*>(glGetString(GL_VENDOR)));
if (caps.supportsShaders)
FASTLOGS(FLog::Graphics, "GLSL version: %s", reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION)));
std::string extensionString;
for (auto& e : extensions)
{
extensionString += " ";
extensionString += e;
}
while (!extensionString.empty())
{
std::string::size_type space = extensionString.find_first_of(' ', 128);
FASTLOGS(FLog::Graphics, "Ext:%s", extensionString.substr(0, space));
extensionString.erase(0, space);
}
caps.dumpToFLog(FLog::Graphics);
FASTLOG1(FLog::Graphics, "Caps: GL3 %d", caps.ext3);
FASTLOG5(FLog::Graphics, "Caps: VAO %d TexStorage %d MapBuffer %d MapBufferRange %d TimerQuery %d", caps.extVertexArrayObject,
caps.extTextureStorage, caps.extMapBuffer, caps.extMapBufferRange, caps.extTimerQuery);
FASTLOG2(FLog::Graphics, "Caps: DebugMarkers %d Sync %d", caps.extDebugMarkers, caps.extSync);
immediateContext.reset(new DeviceContextGL(this));
mainFramebuffer.reset(new FramebufferGL(this, glContext->getMainFramebufferId()));
std::pair<unsigned int, unsigned int> dimensions = glContext->updateMainFramebuffer(0, 0);
mainFramebuffer->updateDimensions(dimensions.first, dimensions.second);
#ifndef GLES
if (caps.extTimerQuery)
{
glGenQueries(1, &frameTimeQueryId);
AYAASSERT(frameTimeQueryId);
}
#endif
#if defined(_WIN32) || defined(__linux__)
Profiler::gpuInit(0);
#endif
ImGui::gpuInit();
}
DeviceGL::~DeviceGL()
{
glFinish();
glContext.reset();
#if defined(_WIN32) || defined(__linux__)
Profiler::gpuShutdown();
#endif
ImGui::gpuShutdown();
immediateContext.reset();
mainFramebuffer.reset();
}
void DeviceGL::resize(int w, int h)
{
glContext->resizeWindow(w, h);
}
std::string DeviceGL::getFeatureLevel()
{
std::string glString = reinterpret_cast<const char*>(glGetString(GL_VERSION));
std::string featureLevel = "OpenGL ";
if (!glString.empty())
{
size_t dotId = glString.find('.');
// this is based on GLEW implementation of determining GL version. Does it look unsafe? Dont worry, GLEW version is even worse;)
if (dotId > 0 && dotId < (glString.length() - 1) && isdigit(glString[dotId - 1]) && isdigit(glString[dotId + 1]))
{
featureLevel += glString[dotId - 1];
featureLevel += '.';
featureLevel += glString[dotId + 1];
return featureLevel;
}
}
featureLevel += "unknown";
return featureLevel;
}
bool DeviceGL::validate()
{
glContext->setCurrent();
std::pair<unsigned int, unsigned int> dimensions = glContext->updateMainFramebuffer(mainFramebuffer->getWidth(), mainFramebuffer->getHeight());
mainFramebuffer->updateDimensions(dimensions.first, dimensions.second);
return true;
}
DeviceContext* DeviceGL::beginFrame()
{
glContext->setCurrent();
#ifndef GLES
if (frameTimeQueryId && !frameTimeQueryIssued)
{
glBeginQuery(GL_TIME_ELAPSED, frameTimeQueryId);
}
#endif
immediateContext->bindFramebuffer(mainFramebuffer.get());
immediateContext->clearStates();
return immediateContext.get();
}
void DeviceGL::endFrame()
{
#ifndef GLES
if (frameTimeQueryId)
{
if (!frameTimeQueryIssued)
{
glEndQuery(GL_TIME_ELAPSED);
frameTimeQueryIssued = true;
}
else
{
int available = 0;
glGetQueryObjectiv(frameTimeQueryId, GL_QUERY_RESULT_AVAILABLE, &available);
if (available)
{
GLuint64EXT elapsed = 0;
if (FFlag::GraphicsGL3)
glGetQueryObjectui64v(frameTimeQueryId, GL_QUERY_RESULT, &elapsed);
else
glGetQueryObjectui64vEXT(frameTimeQueryId, GL_QUERY_RESULT, &elapsed);
gpuTime = static_cast<float>(elapsed) / 1e6f;
frameTimeQueryIssued = false;
}
}
}
#endif
if (FFlag::GraphicsGLReduceLatency && caps.extSync)
{
// Wait for last frame to finish on GPU
if (frameEventQueryIssued)
{
int rc = glClientWaitSync(frameEventQueryId, GL_SYNC_FLUSH_COMMANDS_BIT, GLuint64(5e9));
AYAASSERT(rc == GL_CONDITION_SATISFIED || rc == GL_ALREADY_SIGNALED);
glDeleteSync(frameEventQueryId);
frameEventQueryId = 0;
frameEventQueryIssued = false;
}
// Submit new query for frame wait
if (!frameEventQueryIssued)
{
frameEventQueryId = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
AYAASSERT(frameEventQueryId);
frameEventQueryIssued = true;
}
}
glContext->swapBuffers();
}
Framebuffer* DeviceGL::getMainFramebuffer()
{
return mainFramebuffer.get();
}
void DeviceGL::defineGlobalConstants(size_t dataSize, const std::vector<ShaderGlobalConstant>& constants)
{
AYAASSERT(globalConstants.empty());
AYAASSERT(!constants.empty());
globalConstants = constants;
immediateContext->defineGlobalConstants(dataSize);
}
std::string DeviceGL::getShadingLanguage()
{
#ifdef GLES
return caps.ext3 ? "glsles3" : "glsles";
#else
return caps.ext3 ? "glsl3" : "glsl3";
#endif
}
std::string DeviceGL::createShaderSource(
const std::string& path, const std::string& defines, boost::function<std::string(const std::string&)> fileCallback)
{
// No preprocessor support
return fileCallback(path);
}
std::vector<char> DeviceGL::createShaderBytecode(const std::string& source, const std::string& target, const std::string& entrypoint)
{
// No bytecode support
AYAASSERT(entrypoint == "main");
return std::vector<char>(source.begin(), source.end());
}
shared_ptr<VertexShader> DeviceGL::createVertexShader(const std::vector<char>& bytecode)
{
if (!caps.supportsShaders)
throw Aya::runtime_error("No shader support");
std::string source(bytecode.begin(), bytecode.end());
return shared_ptr<VertexShader>(new VertexShaderGL(this, source));
}
shared_ptr<FragmentShader> DeviceGL::createFragmentShader(const std::vector<char>& bytecode)
{
if (!caps.supportsShaders)
throw Aya::runtime_error("No shader support");
std::string source(bytecode.begin(), bytecode.end());
return shared_ptr<FragmentShader>(new FragmentShaderGL(this, source));
}
shared_ptr<ShaderProgram> DeviceGL::createShaderProgram(
const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader)
{
if (!caps.supportsShaders)
throw Aya::runtime_error("No shader support");
return shared_ptr<ShaderProgram>(new ShaderProgramGL(this, vertexShader, fragmentShader));
}
shared_ptr<ShaderProgram> DeviceGL::createShaderProgramFFP()
{
throw Aya::runtime_error("No FFP support");
}
shared_ptr<VertexBuffer> DeviceGL::createVertexBuffer(size_t elementSize, size_t elementCount, VertexBuffer::Usage usage)
{
return shared_ptr<VertexBuffer>(new VertexBufferGL(this, elementSize, elementCount, usage));
}
shared_ptr<IndexBuffer> DeviceGL::createIndexBuffer(size_t elementSize, size_t elementCount, VertexBuffer::Usage usage)
{
return shared_ptr<IndexBuffer>(new IndexBufferGL(this, elementSize, elementCount, usage));
}
shared_ptr<VertexLayout> DeviceGL::createVertexLayout(const std::vector<VertexLayout::Element>& elements)
{
return shared_ptr<VertexLayout>(new VertexLayoutGL(this, elements));
}
shared_ptr<Texture> DeviceGL::createTexture(Texture::Type type, Texture::Format format, unsigned int width, unsigned int height, unsigned int depth,
unsigned int mipLevels, Texture::Usage usage)
{
return shared_ptr<Texture>(new TextureGL(this, type, format, width, height, depth, mipLevels, usage));
}
shared_ptr<Renderbuffer> DeviceGL::createRenderbuffer(Texture::Format format, unsigned int width, unsigned int height, unsigned int samples)
{
return shared_ptr<Renderbuffer>(new RenderbufferGL(this, format, width, height, samples));
}
shared_ptr<Geometry> DeviceGL::createGeometryImpl(const shared_ptr<VertexLayout>& layout, const std::vector<shared_ptr<VertexBuffer>>& vertexBuffers,
const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex)
{
return shared_ptr<Geometry>(new GeometryGL(this, layout, vertexBuffers, indexBuffer, baseVertexIndex));
}
shared_ptr<Framebuffer> DeviceGL::createFramebufferImpl(const std::vector<shared_ptr<Renderbuffer>>& color, const shared_ptr<Renderbuffer>& depth)
{
return shared_ptr<Framebuffer>(new FramebufferGL(this, color, depth));
}
DeviceStats DeviceGL::getStatistics() const
{
DeviceStats result = {};
result.gpuFrameTime = gpuTime;
return result;
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,178 @@
#pragma once
#include "Core/Device.hpp"
#include "Core/States.hpp"
typedef struct __GLsync* GLsync;
namespace Aya
{
namespace Graphics
{
class FramebufferGL;
class ShaderProgramGL;
class TextureGL;
class ContextGL;
class DeviceGL;
struct DeviceCapsGL : DeviceCaps
{
bool ext3;
bool extVertexArrayObject;
bool extTextureStorage;
bool extMapBuffer;
bool extMapBufferRange;
bool extTimerQuery;
bool extDebugMarkers;
bool extSync;
};
class DeviceContextGL : public DeviceContext
{
public:
DeviceContextGL(DeviceGL* dev);
~DeviceContextGL();
void defineGlobalConstants(size_t dataSize);
void clearStates();
void invalidateCachedProgram();
void invalidateCachedTexture(Texture* texture);
void invalidateCachedTextureStage(unsigned int stage);
virtual void setDefaultAnisotropy(unsigned int value);
virtual void updateGlobalConstants(const void* data, size_t dataSize);
virtual void bindFramebuffer(Framebuffer* buffer);
virtual void clearFramebuffer(unsigned int mask, const float color[4], float depth, unsigned int stencil);
virtual void copyFramebuffer(Framebuffer* buffer, Texture* texture, int xOffset, int yOffset);
virtual void resolveFramebuffer(Framebuffer* msaaBuffer, Framebuffer* buffer, unsigned int mask);
virtual void discardFramebuffer(Framebuffer* buffer, unsigned int mask);
virtual void bindProgram(ShaderProgram* program);
virtual void setWorldTransforms4x3(const float* data, size_t matrixCount);
virtual void setConstant(int handle, const float* data, size_t vectorCount);
virtual void bindTexture(unsigned int stage, Texture* texture, const SamplerState& state);
virtual void setRasterizerState(const RasterizerState& state);
virtual void setBlendState(const BlendState& state);
virtual void setDepthState(const DepthState& state);
virtual void drawImpl(Geometry* geometry, Geometry::Primitive primitive, unsigned int offset, unsigned int count, unsigned int indexRangeBegin,
unsigned int indexRangeEnd);
virtual void pushDebugMarkerGroup(const char* text);
virtual void popDebugMarkerGroup();
virtual void setDebugMarker(const char* text);
private:
std::vector<char> globalData;
unsigned int globalDataVersion;
unsigned int defaultAnisotropy;
ShaderProgramGL* cachedProgram;
TextureGL* cachedTextures[16];
RasterizerState cachedRasterizerState;
BlendState cachedBlendState;
DepthState cachedDepthState;
DeviceGL* device;
};
class DeviceGL : public Device
{
public:
DeviceGL(void* windowHandle, void* display, int w, int h);
~DeviceGL();
virtual bool validate();
virtual void resize(int w, int h);
virtual DeviceContext* beginFrame();
virtual void endFrame();
virtual Framebuffer* getMainFramebuffer();
virtual void defineGlobalConstants(size_t dataSize, const std::vector<ShaderGlobalConstant>& constants);
virtual std::string getAPIName()
{
return "OpenGL";
}
virtual std::string getFeatureLevel();
virtual std::string getShadingLanguage();
virtual std::string createShaderSource(
const std::string& path, const std::string& defines, boost::function<std::string(const std::string&)> fileCallback);
virtual std::vector<char> createShaderBytecode(const std::string& source, const std::string& target, const std::string& entrypoint);
virtual shared_ptr<VertexShader> createVertexShader(const std::vector<char>& bytecode);
virtual shared_ptr<FragmentShader> createFragmentShader(const std::vector<char>& bytecode);
virtual shared_ptr<ShaderProgram> createShaderProgram(
const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader);
virtual shared_ptr<ShaderProgram> createShaderProgramFFP();
virtual shared_ptr<VertexBuffer> createVertexBuffer(size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage);
virtual shared_ptr<IndexBuffer> createIndexBuffer(size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage);
virtual shared_ptr<VertexLayout> createVertexLayout(const std::vector<VertexLayout::Element>& elements);
virtual shared_ptr<Texture> createTexture(Texture::Type type, Texture::Format format, unsigned int width, unsigned int height, unsigned int depth,
unsigned int mipLevels, Texture::Usage usage);
virtual shared_ptr<Renderbuffer> createRenderbuffer(Texture::Format format, unsigned int width, unsigned int height, unsigned int samples);
virtual shared_ptr<Geometry> createGeometryImpl(const shared_ptr<VertexLayout>& layout,
const std::vector<shared_ptr<VertexBuffer>>& vertexBuffers, const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex);
virtual shared_ptr<Framebuffer> createFramebufferImpl(const std::vector<shared_ptr<Renderbuffer>>& color, const shared_ptr<Renderbuffer>& depth);
virtual const DeviceCaps& getCaps() const
{
return caps;
}
virtual DeviceStats getStatistics() const;
DeviceContextGL* getImmediateContextGL()
{
return immediateContext.get();
}
const DeviceCapsGL& getCapsGL() const
{
return caps;
}
const std::vector<ShaderGlobalConstant>& getGlobalConstants() const
{
return globalConstants;
}
private:
DeviceCapsGL caps;
scoped_ptr<DeviceContextGL> immediateContext;
scoped_ptr<FramebufferGL> mainFramebuffer;
std::vector<ShaderGlobalConstant> globalConstants;
unsigned int frameTimeQueryId;
bool frameTimeQueryIssued;
GLsync frameEventQueryId;
bool frameEventQueryIssued;
float gpuTime;
scoped_ptr<ContextGL> glContext;
};
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,163 @@
#include "FramebufferGL.hpp"
#include "TextureGL.hpp"
#include "DeviceGL.hpp"
#include "HeadersGL.hpp"
namespace Aya
{
namespace Graphics
{
RenderbufferGL::RenderbufferGL(Device* device, const shared_ptr<TextureGL>& container, unsigned int target, unsigned int samples)
: Renderbuffer(device, container->getFormat(), container->getWidth(), container->getHeight(), samples)
, owner(container)
, target(target)
, bufferId(0)
{
}
RenderbufferGL::RenderbufferGL(Device* device, Texture::Format format, unsigned int width, unsigned int height, unsigned int samples)
: Renderbuffer(device, format, width, height, samples)
, target(-1)
, bufferId(0)
{
AYAASSERT(samples);
if (samples > device->getCaps().maxSamples)
throw Aya::runtime_error("Unsupported renderbuffer: too many samples (%d)", samples);
glGenRenderbuffers(1, &bufferId);
glBindRenderbuffer(GL_RENDERBUFFER, bufferId);
if (samples > 1)
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, TextureGL::getInternalFormat(format), width, height);
else
glRenderbufferStorage(GL_RENDERBUFFER, TextureGL::getInternalFormat(format), width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
RenderbufferGL::~RenderbufferGL()
{
if (bufferId)
glDeleteRenderbuffers(1, &bufferId);
}
FramebufferGL::FramebufferGL(Device* device, unsigned int id)
: Framebuffer(device, 0, 0, 1)
, id(id)
{
}
FramebufferGL::FramebufferGL(Device* device, const std::vector<shared_ptr<Renderbuffer>>& color, const shared_ptr<Renderbuffer>& depth)
: Framebuffer(device, 0, 0, 0)
, id(0)
, color(color)
, depth(depth)
{
AYAASSERT(!color.empty());
if (color.size() > device->getCaps().maxDrawBuffers)
throw Aya::runtime_error("Unsupported framebuffer configuration: too many buffers (%d)", (int)color.size());
glGenFramebuffers(1, &id);
glBindFramebuffer(GL_FRAMEBUFFER, id);
for (size_t i = 0; i < color.size(); ++i)
{
RenderbufferGL* buffer = static_cast<RenderbufferGL*>(color[i].get());
AYAASSERT(buffer);
AYAASSERT(!Texture::isFormatDepth(buffer->getFormat()));
if (buffer->getTextureId())
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, buffer->getTarget(), buffer->getTextureId(), 0);
else
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, buffer->getBufferId());
if (i == 0)
{
width = buffer->getWidth();
height = buffer->getHeight();
samples = buffer->getSamples();
}
else
{
AYAASSERT(width == buffer->getWidth());
AYAASSERT(height == buffer->getHeight());
AYAASSERT(samples == buffer->getSamples());
}
}
if (depth)
{
RenderbufferGL* buffer = static_cast<RenderbufferGL*>(depth.get());
AYAASSERT(buffer->getTextureId() == 0);
AYAASSERT(Texture::isFormatDepth(buffer->getFormat()));
AYAASSERT(width == buffer->getWidth());
AYAASSERT(height == buffer->getHeight());
AYAASSERT(samples == buffer->getSamples());
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, buffer->getBufferId());
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer->getBufferId());
}
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
glDeleteFramebuffers(1, &id);
throw Aya::runtime_error("Unsupported framebuffer configuration: error %x", status);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
FramebufferGL::~FramebufferGL()
{
if (id)
glDeleteFramebuffers(1, &id);
}
void FramebufferGL::download(void* data, unsigned int size)
{
AYAASSERT(size == width * height * 4);
GLint oldfb = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb);
glBindFramebuffer(GL_FRAMEBUFFER, id);
#ifndef GLES
glReadBuffer(id == 0 ? GL_BACK : GL_COLOR_ATTACHMENT0);
#endif
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
glBindFramebuffer(GL_FRAMEBUFFER, oldfb);
std::vector<char> tempRow(width * 4);
for (unsigned int y = 0; y < height / 2; ++y)
{
char* dataRow = static_cast<char*>(data) + y * width * 4;
char* dataOppositeRow = static_cast<char*>(data) + (height - 1 - y) * width * 4;
memcpy(&tempRow[0], dataRow, width * 4);
memcpy(dataRow, dataOppositeRow, width * 4);
memcpy(dataOppositeRow, &tempRow[0], width * 4);
}
}
void FramebufferGL::updateDimensions(unsigned int width, unsigned int height)
{
AYAASSERT(color.empty() && !depth);
this->width = width;
this->height = height;
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,67 @@
#pragma once
#include "Core/Framebuffer.hpp"
#include "TextureGL.hpp"
#include <vector>
namespace Aya
{
namespace Graphics
{
class RenderbufferGL : public Renderbuffer
{
public:
RenderbufferGL(Device* device, const shared_ptr<TextureGL>& owner, unsigned int target, unsigned int samples = 1);
RenderbufferGL(Device* device, Texture::Format format, unsigned int width, unsigned int height, unsigned int samples);
~RenderbufferGL();
unsigned int getTextureId() const
{
return owner ? owner->getId() : 0;
}
unsigned int getTarget() const
{
return target;
}
unsigned int getBufferId() const
{
return bufferId;
}
private:
unsigned int target; // TEXTURE_2D or TEXTURE_CUBE_MAP_POSITIVE_X, ...
unsigned int bufferId;
shared_ptr<TextureGL> owner;
};
class FramebufferGL : public Framebuffer
{
public:
FramebufferGL(Device* device, unsigned int id);
FramebufferGL(Device* device, const std::vector<shared_ptr<Renderbuffer>>& color, const shared_ptr<Renderbuffer>& depth);
~FramebufferGL();
virtual void download(void* data, unsigned int size);
void updateDimensions(unsigned int width, unsigned int height);
unsigned int getId() const
{
return id;
}
unsigned int getDrawBuffers() const
{
return color.size();
}
private:
unsigned int id;
std::vector<shared_ptr<Renderbuffer>> color;
shared_ptr<Renderbuffer> depth;
};
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,339 @@
#include "DataModel/GameBasicSettings.hpp"
#include "GeometryGL.hpp"
#include "DeviceGL.hpp"
#include "HeadersGL.hpp"
DYNAMIC_FASTFLAGVARIABLE(FreakyModeEnabled, false)
namespace Aya
{
namespace Graphics
{
static const GLenum gBufferUsageGL[GeometryBuffer::Usage_Count] = {GL_STATIC_DRAW, GL_DYNAMIC_DRAW};
static const GLenum gBufferLockGL[GeometryBuffer::Lock_Count] = {GL_MAP_WRITE_BIT, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT};
struct VertexFormatGL
{
int size;
GLenum type;
bool normalized;
};
static const VertexFormatGL gVertexFormatGL[VertexLayout::Format_Count] = {
{1, GL_FLOAT, false},
{2, GL_FLOAT, false},
{3, GL_FLOAT, false},
{4, GL_FLOAT, false},
{2, GL_SHORT, false},
{4, GL_SHORT, false},
{4, GL_UNSIGNED_BYTE, false},
{4, GL_UNSIGNED_BYTE, true},
};
static const GLenum gGeometryPrimitiveGL[Geometry::Primitive_Count] = {GL_TRIANGLES, GL_LINES, GL_POINTS, GL_TRIANGLE_STRIP};
static unsigned int getVertexAttributeGL(VertexLayout::Semantic semantic, unsigned int index)
{
switch (semantic)
{
case VertexLayout::Semantic_Position:
AYAASSERT(index == 0);
return 0;
case VertexLayout::Semantic_Normal:
AYAASSERT(index == 0);
return 1;
case VertexLayout::Semantic_Color:
AYAASSERT(index < 2);
return 2 + index;
case VertexLayout::Semantic_Texture:
AYAASSERT(index < 8);
return 4 + index;
default:
AYAASSERT(false);
return -1;
}
}
const char* VertexLayoutGL::getShaderAttributeName(unsigned int id)
{
static const char* table[] = {
"vertex",
"normal",
"colour",
"secondary_colour",
"uv0",
"uv1",
"uv2",
"uv3",
"uv4",
"uv5",
"uv6",
"uv7",
};
return (id < ARRAYSIZE(table)) ? table[id] : NULL;
}
VertexLayoutGL::VertexLayoutGL(Device* device, const std::vector<Element>& elements)
: VertexLayout(device, elements)
{
}
VertexLayoutGL::~VertexLayoutGL() {}
template<typename Base>
GeometryBufferGL<Base>::GeometryBufferGL(Device* device, size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage, unsigned int target)
: Base(device, elementSize, elementCount, usage)
, target(target)
, id(0)
, locked(0)
{
}
template<typename Base>
void GeometryBufferGL<Base>::create()
{
glGenBuffers(1, &id);
AYAASSERT(id);
glBindBuffer(target, id);
glBufferData(target, this->elementSize * this->elementCount, NULL, gBufferUsageGL[this->usage]);
}
template<typename Base>
GeometryBufferGL<Base>::~GeometryBufferGL()
{
AYAASSERT(!locked);
glDeleteBuffers(1, &id);
}
template<typename Base>
void* GeometryBufferGL<Base>::lock(GeometryBuffer::LockMode mode)
{
AYAASSERT(!locked);
unsigned int size = this->elementSize * this->elementCount;
const DeviceCapsGL& caps = static_cast<DeviceGL*>(this->device)->getCapsGL();
if (caps.extMapBuffer)
{
glBindBuffer(target, id);
if (caps.extMapBufferRange)
{
locked = glMapBufferRange(target, 0, size, gBufferLockGL[mode]);
}
else
{
if (mode == GeometryBuffer::Lock_Discard)
glBufferData(target, size, NULL, gBufferUsageGL[this->usage]);
locked = glMapBuffer(target, GL_WRITE_ONLY);
}
}
else
{
locked = new char[size];
}
AYAASSERT(locked);
return locked;
}
template<typename Base>
void GeometryBufferGL<Base>::unlock()
{
AYAASSERT(locked);
const DeviceCapsGL& caps = static_cast<DeviceGL*>(this->device)->getCapsGL();
if (caps.extMapBuffer)
{
glBindBuffer(target, id);
glUnmapBuffer(target);
}
else
{
glBindBuffer(target, id);
glBufferSubData(target, 0, this->elementSize * this->elementCount, locked);
delete[] static_cast<char*>(locked);
}
locked = NULL;
}
template<typename Base>
void GeometryBufferGL<Base>::upload(unsigned int offset, const void* data, unsigned int size)
{
AYAASSERT(!locked);
AYAASSERT(offset + size <= this->elementSize * this->elementCount);
glBindBuffer(target, id);
glBufferSubData(target, offset, size, data);
}
VertexBufferGL::VertexBufferGL(Device* device, size_t elementSize, size_t elementCount, Usage usage)
: GeometryBufferGL<VertexBuffer>(device, elementSize, elementCount, usage, GL_ARRAY_BUFFER)
{
create();
}
VertexBufferGL::~VertexBufferGL() {}
IndexBufferGL::IndexBufferGL(Device* device, size_t elementSize, size_t elementCount, Usage usage)
: GeometryBufferGL<IndexBuffer>(device, elementSize, elementCount, usage, GL_ELEMENT_ARRAY_BUFFER)
{
const DeviceCapsGL& caps = static_cast<DeviceGL*>(device)->getCapsGL();
if (elementSize != 2 && elementSize != 4)
throw Aya::runtime_error("Invalid element size: %d", (int)elementSize);
if (elementSize == 4 && !caps.supportsIndex32)
throw Aya::runtime_error("Unsupported element size: %d", (int)elementSize);
create();
}
IndexBufferGL::~IndexBufferGL() {}
GeometryGL::GeometryGL(Device* device, const shared_ptr<VertexLayout>& layout, const std::vector<shared_ptr<VertexBuffer>>& vertexBuffers,
const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex)
: Geometry(device, layout, vertexBuffers, indexBuffer, baseVertexIndex)
, id(0)
, indexElementSize(0)
{
const DeviceCapsGL& caps = static_cast<DeviceGL*>(device)->getCapsGL();
if (caps.extVertexArrayObject)
{
glGenVertexArrays(1, &id);
AYAASSERT(id);
glBindVertexArray(id);
bindArrays();
glBindVertexArray(0);
}
if (indexBuffer)
{
// Cache indexElementSize to reduce cache misses in case we're using VAO
indexElementSize = indexBuffer->getElementSize();
}
}
GeometryGL::~GeometryGL()
{
if (id)
{
glDeleteVertexArrays(1, &id);
}
}
void GeometryGL::draw(Primitive primitive, unsigned int offset, unsigned int count)
{
unsigned int mask = 0;
// Setup vertex/index buffers
if (id)
glBindVertexArray(id);
else
mask = bindArrays();
// Perform draw call
if (indexBuffer)
{
if (mask == 0)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, static_cast<IndexBufferGL*>(indexBuffer.get())->getId());
}
GLenum indexElementType = indexElementSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
glDrawElements(Aya::GameBasicSettings::singleton().getWireframeRendering() ? GL_LINES : gGeometryPrimitiveGL[primitive], count,
indexElementType, reinterpret_cast<void*>(offset * indexElementSize));
}
else
glDrawArrays(gGeometryPrimitiveGL[primitive], offset, count);
if (id)
glBindVertexArray(0);
else
unbindArrays(mask);
}
unsigned int GeometryGL::bindArrays()
{
unsigned int mask = 0;
unsigned int vbId = 0;
const std::vector<VertexLayout::Element>& elements = layout->getElements();
for (size_t i = 0; i < elements.size(); ++i)
{
const VertexLayout::Element& e = elements[i];
int index = getVertexAttributeGL(e.semantic, e.semanticIndex);
AYAASSERT(index >= 0);
AYAASSERT(e.stream < vertexBuffers.size());
VertexBufferGL* vb = static_cast<VertexBufferGL*>(vertexBuffers[e.stream].get());
AYAASSERT(e.offset < vb->getElementSize());
size_t stride = vb->getElementSize();
size_t offset = e.offset + stride * baseVertexIndex;
const VertexFormatGL& formatGl = gVertexFormatGL[e.format];
if (vbId != vb->getId())
{
vbId = vb->getId();
glBindBuffer(GL_ARRAY_BUFFER, vbId);
}
glEnableVertexAttribArray(index);
glVertexAttribPointer(index, formatGl.size, formatGl.type, formatGl.normalized, stride, reinterpret_cast<void*>(offset));
mask |= 1 << index;
}
if (indexBuffer)
{
IndexBufferGL* ib = static_cast<IndexBufferGL*>(indexBuffer.get());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->getId());
}
return mask;
}
void GeometryGL::unbindArrays(unsigned int mask)
{
for (int i = 0; i < 16; ++i)
if (mask & (1 << i))
glDisableVertexAttribArray(i);
}
// Instantiate GeometryBufferGL template
template class GeometryBufferGL<VertexBuffer>;
template class GeometryBufferGL<IndexBuffer>;
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,83 @@
#pragma once
#include "Core/Geometry.hpp"
namespace Aya
{
namespace Graphics
{
class VertexLayoutGL : public VertexLayout
{
public:
static const char* getShaderAttributeName(unsigned int id);
VertexLayoutGL(Device* device, const std::vector<Element>& elements);
~VertexLayoutGL();
};
template<typename Base>
class GeometryBufferGL : public Base
{
public:
GeometryBufferGL(Device* device, size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage, unsigned int target);
~GeometryBufferGL();
virtual void* lock(GeometryBuffer::LockMode mode);
virtual void unlock();
virtual void upload(unsigned int offset, const void* data, unsigned int size);
unsigned int getId() const
{
return id;
}
protected:
void create();
private:
unsigned int target;
unsigned int id;
void* locked;
};
class VertexBufferGL : public GeometryBufferGL<VertexBuffer>
{
public:
VertexBufferGL(Device* device, size_t elementSize, size_t elementCount, Usage usage);
~VertexBufferGL();
};
class IndexBufferGL : public GeometryBufferGL<IndexBuffer>
{
public:
IndexBufferGL(Device* device, size_t elementSize, size_t elementCount, Usage usage);
~IndexBufferGL();
};
class GeometryGL : public Geometry
{
public:
GeometryGL(Device* device, const shared_ptr<VertexLayout>& layout, const std::vector<shared_ptr<VertexBuffer>>& vertexBuffers,
const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex);
~GeometryGL();
void draw(Primitive primitive, unsigned int offset, unsigned int count);
unsigned int getId() const
{
return id;
}
private:
unsigned int id;
unsigned int indexElementSize;
unsigned int bindArrays();
void unbindArrays(unsigned int mask);
};
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,137 @@
#pragma once
#ifdef RBX_PLATFORM_IOS
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#ifdef __OBJC__
#include <OpenGLES/EAGL.h>
#endif
#define GLES
#elif defined(__ANDROID__)
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#define GLES
#else
#include <glad/gl.h>
#endif
#ifdef __ANDROID__
typedef struct __GLsync* GLsync;
typedef uint64_t GLuint64;
#endif
#ifdef GLES
// Core GLES
#define glClearDepth glClearDepthf
// OES_vertex_array_object
GLvoid glBindVertexArray(GLuint array);
GLvoid glDeleteVertexArrays(GLsizei n, const GLuint* arrays);
GLvoid glGenVertexArrays(GLsizei n, GLuint* arrays);
// OES_mapbuffer
#define GL_WRITE_ONLY 0x88B9
GLvoid* glMapBuffer(GLenum target, GLenum access);
GLboolean glUnmapBuffer(GLenum target);
// EXT_map_buffer_range
GLvoid* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
#define GL_MAP_READ_BIT 0x0001
#define GL_MAP_WRITE_BIT 0x0002
#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
// EXT_texture_storage
GLvoid glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
#define GL_LUMINANCE8 0x8040
#define GL_LUMINANCE8_ALPHA8 0x8045
// GL_OES_packed_depth_stencil
#define GL_DEPTH_STENCIL 0x84F9
#define GL_UNSIGNED_INT_24_8 0x84FA
#define GL_DEPTH24_STENCIL8 0x88F0
// OES_rgb8_rgba8
#define GL_RGBA8 0x8058
// OES_texture_half_float
#define GL_HALF_FLOAT 0x8D61
// EXT_color_buffer_half_float
#define GL_RGBA16F 0x881A
// OES_texture_3D
#define GL_TEXTURE_3D 0x806F
GLvoid glTexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format,
GLenum type, const GLvoid* pixels);
GLvoid glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const GLvoid* pixels);
GLvoid glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
// GLES 3.0 formats
#define GL_RED 0x1903
#define GL_RG 0x8227
#define GL_R8 0x8229
#define GL_RG8 0x822B
#define GL_RG16 0x822C
// GLES 3.0 buffer objects
#define GL_DYNAMIC_COPY 0x88EA
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
// GLES 3.0 sync objects
#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
#define GL_ALREADY_SIGNALED 0x911A
#define GL_TIMEOUT_EXPIRED 0x911B
#define GL_CONDITION_SATISFIED 0x911C
#define GL_WAIT_FAILED 0x911D
#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
GLsync glFenceSync(GLenum condition, GLbitfield flags);
void glDeleteSync(GLsync sync);
GLenum glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
void glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
// GLES 3.0 MSAA
#define GL_READ_FRAMEBUFFER 0x8CA8
#define GL_DRAW_FRAMEBUFFER 0x8CA9
#define GL_MAX_SAMPLES 0x8D57
GLvoid glBlitFramebuffer(
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
GLvoid glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
// GLES 3.0 invalidate FBO
GLvoid glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments);
#endif
// EXT_texture_compression_s3tc
#ifndef GL_EXT_texture_compression_s3tc
#define GL_EXT_texture_compression_s3tc 1
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#endif
// IMG_texture_compression_pvrtc
#ifndef GL_IMG_texture_compression_pvrtc
#define GL_IMG_texture_compression_pvrtc 1
#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
#endif
#ifndef GL_ETC1_RGB8_OES
#define GL_ETC1_RGB8_OES (0x8D64)
#endif
// APPLE_texture_max_level, GLES 3.0
#ifndef GL_TEXTURE_MAX_LEVEL
#define GL_TEXTURE_MAX_LEVEL 0x813D
#endif

View File

@@ -0,0 +1,563 @@
#include "ShaderGL.hpp"
#include "GeometryGL.hpp"
#include "DeviceGL.hpp"
#include "HeadersGL.hpp"
#include <set>
#include <map>
LOGGROUP(Graphics)
namespace Aya
{
namespace Graphics
{
static int getShaderParameter(GLuint shader, GLenum pname)
{
GLint result;
glGetShaderiv(shader, pname, &result);
return result;
}
static int getProgramParameter(GLuint program, GLenum pname)
{
GLint result;
glGetProgramiv(program, pname, &result);
return result;
}
template<typename GetParameter, typename GetLog>
static std::string getInfoLog(unsigned int id, GetParameter getParameter, GetLog getLog)
{
int infoLength = getParameter(id, GL_INFO_LOG_LENGTH);
if (infoLength > 0)
{
std::vector<char> buffer(infoLength);
getLog(id, infoLength, NULL, &buffer[0]);
return std::string(&buffer[0]);
}
else
{
return "";
}
}
template<typename GetParameter, typename GetLog>
static void dumpInfoLog(unsigned int id, GetParameter getParameter, GetLog getLog)
{
std::string log = getInfoLog(id, getParameter, getLog);
// Intel and AMD drivers like to say "No errors" for every shader.
if (strstr(log.c_str(), "warn") || strstr(log.c_str(), "Warn") || strstr(log.c_str(), "WARN"))
{
FASTLOG2(FLog::Graphics, "Shader %d has a non-empty infolog (length %d)", id, log.length());
ShaderProgram::dumpToFLog(log, FLog::Graphics);
}
}
static unsigned int compileShader(const std::string& source, GLenum type)
{
unsigned int id = glCreateShader(type);
AYAASSERT(id);
int length = source.length();
const char* data = source.c_str();
glShaderSource(id, 1, &data, &length);
glCompileShader(id);
if (getShaderParameter(id, GL_COMPILE_STATUS) != 1)
{
std::string infoLog = getInfoLog(id, getShaderParameter, glGetShaderInfoLog);
glDeleteShader(id);
throw std::runtime_error(infoLog);
}
dumpInfoLog(id, getShaderParameter, glGetShaderInfoLog);
return id;
}
static unsigned int parseAttribs(const std::string& source, const char* prefix)
{
std::set<std::string> attribs;
size_t offset = 0;
while (offset < source.length())
{
std::string::size_type start = source.find(prefix, offset);
if (start == std::string::npos)
break;
std::string::size_type eol = source.find('\n', start);
if (eol == std::string::npos)
break;
offset = eol;
std::string::size_type semi = source.find(';', start);
std::string::size_type space = source.find_last_of(' ', eol);
if ((start == 0 || source[start - 1] == '\n') && semi != std::string::npos && space != std::string::npos && space < semi)
attribs.insert(source.substr(space + 1, semi - space - 1));
}
unsigned int result = 0;
for (unsigned int attr = 0; attr < 16; ++attr)
{
const char* name = VertexLayoutGL::getShaderAttributeName(attr);
if (name && attribs.count(name))
result |= 1 << attr;
}
return result;
}
static void applyAttribs(unsigned int id, unsigned int attribMask)
{
for (unsigned int attr = 0; attr < 16; ++attr)
if (attribMask & (1 << attr))
{
const char* name = VertexLayoutGL::getShaderAttributeName(attr);
AYAASSERT(name);
glBindAttribLocation(id, attr, name);
}
}
static std::vector<FragmentShaderGL::Sampler> parseSamplers(const std::string& source)
{
std::vector<FragmentShaderGL::Sampler> result;
size_t offset = 0;
while (offset < source.length())
{
std::string::size_type start = source.find("//$$", offset);
if (start == std::string::npos)
return result;
std::string::size_type equals = source.find('=', start);
if (equals == std::string::npos)
return result;
std::string::size_type end = source.find('\n', equals);
if (end == std::string::npos)
return result;
std::string name(source.begin() + start + 4, source.begin() + equals);
std::string value(source.begin() + equals + 1, source.begin() + end);
if (!value.empty() && value[0] == 's')
{
FragmentShaderGL::Sampler entry = {name, atoi(value.c_str() + 1)};
result.push_back(entry);
}
offset = end;
}
return result;
}
static int getSamplerLocation(unsigned int id, const std::string& name)
{
int location;
if ((location = glGetUniformLocation(id, name.c_str())) >= 0)
return location;
if ((location = glGetUniformLocation(id, ("xlu_" + name).c_str())) >= 0)
return location;
return -1;
}
static unsigned int applySamplers(unsigned int id, const std::vector<FragmentShaderGL::Sampler>& samplers)
{
unsigned int mask = 0;
glUseProgram(id);
for (size_t i = 0; i < samplers.size(); ++i)
{
int location = getSamplerLocation(id, samplers[i].name);
if (location >= 0)
{
glUniform1i(location, samplers[i].slot);
mask |= 1 << samplers[i].slot;
}
}
glUseProgram(0);
return mask;
}
static ShaderProgramGL::Uniform::Type getUniformType(GLenum type)
{
switch (type)
{
case GL_FLOAT:
return ShaderProgramGL::Uniform::Type_Float;
case GL_FLOAT_VEC2:
return ShaderProgramGL::Uniform::Type_Float2;
case GL_FLOAT_VEC3:
return ShaderProgramGL::Uniform::Type_Float3;
case GL_FLOAT_VEC4:
return ShaderProgramGL::Uniform::Type_Float4;
case GL_FLOAT_MAT4:
return ShaderProgramGL::Uniform::Type_Float4x4;
default:
return ShaderProgramGL::Uniform::Type_Unknown;
}
}
typedef std::map<std::string, ShaderProgramGL::Uniform> UniformTable;
static UniformTable extractUniforms(unsigned int id)
{
int uniformCount = getProgramParameter(id, GL_ACTIVE_UNIFORMS);
int uniformMaxLength = getProgramParameter(id, GL_ACTIVE_UNIFORM_MAX_LENGTH);
std::vector<char> uniformName(uniformMaxLength + 1);
UniformTable result;
for (int i = 0; i < uniformCount; ++i)
{
GLint size;
GLenum type;
glGetActiveUniform(id, i, uniformMaxLength, NULL, &size, &type, &uniformName[0]);
ShaderProgramGL::Uniform::Type uniformType = getUniformType(type);
int location = glGetUniformLocation(id, &uniformName[0]);
if (location >= 0 && uniformType != ShaderProgramGL::Uniform::Type_Unknown)
{
ShaderProgramGL::Uniform uniform = {location, uniformType, (unsigned int)size, 0};
std::string name(&uniformName[0]);
// Remove xlu_ prefix for entrypoint-local uniforms
if (name.compare(0, 4, "xlu_") == 0)
name.erase(name.begin(), name.begin() + 4);
// Remove [0] from arrays
std::string::size_type index = name.find('[');
if (index != std::string::npos)
name.erase(name.begin() + index, name.end());
result[name] = uniform;
}
}
return result;
}
static const ShaderProgramGL::Uniform* findUniform(const UniformTable& ctab, const std::string& name)
{
UniformTable::const_iterator it = ctab.find(name);
return (it == ctab.end()) ? NULL : &it->second;
}
static inline void transposeMatrix(float* dest, const float* source, const float* lastColumn)
{
dest[0] = source[0];
dest[1] = source[4];
dest[2] = source[8];
dest[3] = lastColumn[0];
dest[4] = source[1];
dest[5] = source[5];
dest[6] = source[9];
dest[7] = lastColumn[1];
dest[8] = source[2];
dest[9] = source[6];
dest[10] = source[10];
dest[11] = lastColumn[2];
dest[12] = source[3];
dest[13] = source[7];
dest[14] = source[11];
dest[15] = lastColumn[3];
}
VertexShaderGL::VertexShaderGL(Device* device, const std::string& source)
: VertexShader(device)
, id(0)
, attribMask(0)
{
id = compileShader(source, GL_VERTEX_SHADER);
attribMask = parseAttribs(source, static_cast<DeviceGL*>(device)->getCapsGL().ext3 ? "in " : "attribute ");
}
VertexShaderGL::~VertexShaderGL()
{
glDeleteShader(id);
}
void VertexShaderGL::reloadBytecode(const std::vector<char>& bytecode)
{
throw std::runtime_error("Bytecode reloading is not supported");
}
FragmentShaderGL::FragmentShaderGL(Device* device, const std::string& source)
: FragmentShader(device)
, id(0)
{
id = compileShader(source, GL_FRAGMENT_SHADER);
samplers = parseSamplers(source);
}
FragmentShaderGL::~FragmentShaderGL()
{
glDeleteShader(id);
}
void FragmentShaderGL::reloadBytecode(const std::vector<char>& bytecode)
{
throw std::runtime_error("Bytecode reloading is not supported");
}
ShaderProgramGL::ShaderProgramGL(Device* device, const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader)
: ShaderProgram(device, vertexShader, fragmentShader)
, id(0)
, uniformWorldMatrix(-1)
, uniformWorldMatrixArray(-1)
, cachedGlobalVersion(0)
, maxWorldTransforms(0)
, samplerMask(0)
{
id = glCreateProgram();
AYAASSERT(id);
glAttachShader(id, static_cast<VertexShaderGL*>(vertexShader.get())->getId());
glAttachShader(id, static_cast<FragmentShaderGL*>(fragmentShader.get())->getId());
// Setup attribute locations
applyAttribs(id, static_cast<VertexShaderGL*>(vertexShader.get())->getAttribMask());
glLinkProgram(id);
if (getProgramParameter(id, GL_LINK_STATUS) != 1)
{
std::string infoLog = getInfoLog(id, getProgramParameter, glGetProgramInfoLog);
glDeleteProgram(id);
throw std::runtime_error(infoLog);
}
dumpInfoLog(id, getProgramParameter, glGetProgramInfoLog);
// Make sure the program uses correct sampler slot assignments
// Note: this resets current program to 0!
static_cast<DeviceGL*>(device)->getImmediateContextGL()->invalidateCachedProgram();
samplerMask = applySamplers(id, static_cast<FragmentShaderGL*>(fragmentShader.get())->getSamplers());
// Populate constant tables
const std::vector<ShaderGlobalConstant>& globalConstants = static_cast<DeviceGL*>(device)->getGlobalConstants();
UniformTable ctab = extractUniforms(id);
for (size_t i = 0; i < globalConstants.size(); ++i)
if (const Uniform* uniform = findUniform(ctab, globalConstants[i].name))
{
Uniform u = *uniform;
u.offset = globalConstants[i].offset;
globalUniforms.push_back(u);
ctab.erase(globalConstants[i].name);
}
// Populate world matrix information
if (const Uniform* uniform = findUniform(ctab, "WorldMatrix"))
{
AYAASSERT(uniform->type == Uniform::Type_Float4x4);
uniformWorldMatrix = uniform->location;
maxWorldTransforms = 1;
ctab.erase("WorldMatrix");
}
if (const Uniform* uniform = findUniform(ctab, "WorldMatrixArray"))
{
AYAASSERT(uniform->type == Uniform::Type_Float4);
AYAASSERT(uniform->size % 3 == 0);
uniformWorldMatrixArray = uniform->location;
maxWorldTransforms = uniform->size / 3;
ctab.erase("WorldMatrixArray");
}
// Populate uniform information
for (UniformTable::iterator it = ctab.begin(); it != ctab.end(); ++it)
{
uniforms.push_back(std::make_pair(it->first, it->second));
}
}
ShaderProgramGL::~ShaderProgramGL()
{
glDeleteProgram(id);
// Shader program destruction invalidates currently bound program id
static_cast<DeviceGL*>(device)->getImmediateContextGL()->invalidateCachedProgram();
}
int ShaderProgramGL::getConstantHandle(const char* name) const
{
for (size_t i = 0; i < uniforms.size(); ++i)
if (uniforms[i].first == name)
return i;
return -1;
}
unsigned int ShaderProgramGL::getMaxWorldTransforms() const
{
return maxWorldTransforms;
}
unsigned int ShaderProgramGL::getSamplerMask() const
{
return samplerMask;
}
void ShaderProgramGL::bind(const void* globalData, unsigned int globalVersion, ShaderProgramGL** cache)
{
if (*cache != this)
{
*cache = this;
glUseProgram(id);
}
if (cachedGlobalVersion != globalVersion)
{
cachedGlobalVersion = globalVersion;
for (size_t i = 0; i < globalUniforms.size(); ++i)
{
const Uniform& u = globalUniforms[i];
const float* data = reinterpret_cast<const float*>(static_cast<const char*>(globalData) + u.offset);
switch (u.type)
{
case Uniform::Type_Float:
glUniform1fv(u.location, 1, data);
break;
case Uniform::Type_Float2:
glUniform2fv(u.location, 1, data);
break;
case Uniform::Type_Float3:
glUniform3fv(u.location, 1, data);
break;
case Uniform::Type_Float4:
glUniform4fv(u.location, 1, data);
break;
case Uniform::Type_Float4x4:
{
float matrix[16];
transposeMatrix(matrix, data, data + 12);
glUniformMatrix4fv(u.location, 1, false, matrix);
break;
}
default:
break;
}
}
}
}
void ShaderProgramGL::setWorldTransforms4x3(const float* data, size_t matrixCount)
{
if (matrixCount == 0)
return;
if (uniformWorldMatrix >= 0)
{
static const float lastColumn[] = {0, 0, 0, 1};
float matrix[16];
transposeMatrix(matrix, data, lastColumn);
glUniformMatrix4fv(uniformWorldMatrix, 1, false, matrix);
}
if (uniformWorldMatrixArray >= 0)
{
AYAASSERT(matrixCount <= maxWorldTransforms);
glUniform4fv(uniformWorldMatrixArray, matrixCount * 3, data);
}
}
void ShaderProgramGL::setConstant(int handle, const float* data, size_t vectorCount)
{
if (handle < 0)
return;
AYAASSERT(static_cast<size_t>(handle) < uniforms.size());
const Uniform& u = uniforms[handle].second;
switch (u.type)
{
case Uniform::Type_Float:
AYAASSERT(vectorCount == 1);
glUniform1fv(u.location, 1, data);
break;
case Uniform::Type_Float2:
AYAASSERT(vectorCount == 1);
glUniform2fv(u.location, 1, data);
break;
case Uniform::Type_Float3:
AYAASSERT(vectorCount == 1);
glUniform3fv(u.location, 1, data);
break;
case Uniform::Type_Float4:
AYAASSERT(vectorCount > 0 && vectorCount <= u.size);
glUniform4fv(u.location, vectorCount, data);
break;
default:
AYAASSERT(false);
}
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,123 @@
#pragma once
#include "Core/Shader.hpp"
#include <vector>
namespace Aya
{
namespace Graphics
{
class VertexShaderGL : public VertexShader
{
public:
VertexShaderGL(Device* device, const std::string& source);
~VertexShaderGL();
virtual void reloadBytecode(const std::vector<char>& bytecode);
unsigned int getId() const
{
return id;
}
unsigned int getAttribMask() const
{
return attribMask;
}
private:
unsigned int id;
unsigned int attribMask;
};
class FragmentShaderGL : public FragmentShader
{
public:
struct Sampler
{
std::string name;
int slot;
};
FragmentShaderGL(Device* device, const std::string& source);
~FragmentShaderGL();
virtual void reloadBytecode(const std::vector<char>& bytecode);
unsigned int getId() const
{
return id;
}
const std::vector<Sampler>& getSamplers() const
{
return samplers;
}
private:
unsigned int id;
std::vector<Sampler> samplers;
};
class ShaderProgramGL : public ShaderProgram
{
public:
struct Uniform
{
enum Type
{
Type_Unknown,
Type_Float,
Type_Float2,
Type_Float3,
Type_Float4,
Type_Float4x4,
Type_Count
};
int location;
Type type;
unsigned int size;
unsigned int offset;
};
ShaderProgramGL(Device* device, const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader);
~ShaderProgramGL();
virtual int getConstantHandle(const char* name) const;
virtual unsigned int getMaxWorldTransforms() const;
virtual unsigned int getSamplerMask() const;
void bind(const void* globalData, unsigned int globalVersion, ShaderProgramGL** cache);
void setWorldTransforms4x3(const float* data, size_t matrixCount);
void setConstant(int handle, const float* data, size_t vectorCount);
unsigned int getId() const
{
return id;
}
private:
unsigned int id;
int uniformWorldMatrix;
int uniformWorldMatrixArray;
unsigned int cachedGlobalVersion;
std::vector<Uniform> globalUniforms;
std::vector<std::pair<std::string, Uniform>> uniforms;
unsigned int maxWorldTransforms;
unsigned int samplerMask;
};
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,545 @@
#include "TextureGL.hpp"
#include "DeviceGL.hpp"
#include "FramebufferGL.hpp"
#include "HeadersGL.hpp"
LOGGROUP(Graphics)
FASTFLAG(GraphicsTextureCommitChanges)
namespace Aya
{
namespace Graphics
{
static const GLenum gTextureTargetGL[Texture::Type_Count] = {GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP};
struct TextureFormatGL
{
GLenum internalFormat;
GLenum dataFormat;
GLenum dataType;
};
static const TextureFormatGL gTextureFormatGL[Texture::Format_Count] = {
{GL_R8, GL_RED, GL_UNSIGNED_BYTE},
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE},
{GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1},
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE},
{GL_RG16, GL_RG, GL_UNSIGNED_SHORT},
{GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT},
{GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0, 0},
{GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0, 0},
{GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0, 0},
{GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, 0, 0},
{GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, 0, 0},
{GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 0, 0},
{GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 0, 0},
{GL_ETC1_RGB8_OES, 0, 0},
{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT},
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8},
};
const TextureFormatGL& getTextureFormatGL(Texture::Format format, bool ext3)
{
if (!ext3 && format == Texture::Format_L8)
{
static const TextureFormatGL result = {GL_LUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE};
return result;
}
if (!ext3 && format == Texture::Format_LA8)
{
static const TextureFormatGL result = {GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE};
return result;
}
return gTextureFormatGL[format];
}
static const GLenum gSamplerFilterMinGL[SamplerState::Filter_Count][2] = {
{GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST}, {GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR}, {GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR}};
static const GLenum gSamplerFilterMagGL[SamplerState::Filter_Count] = {GL_NEAREST, GL_LINEAR, GL_LINEAR};
static const GLenum gSamplerAddressGL[SamplerState::Address_Count] = {GL_REPEAT, GL_CLAMP_TO_EDGE};
static bool doesFormatSupportPartialUpload(Texture::Format format)
{
return format != Texture::Format_ETC1;
}
static unsigned int createTexture(Texture::Type type, Texture::Format format, unsigned int width, unsigned int height, unsigned int depth,
unsigned int mipLevels, const DeviceCapsGL& caps)
{
GLenum target = gTextureTargetGL[type];
const TextureFormatGL& formatGl = getTextureFormatGL(format, caps.ext3);
unsigned int id = 0;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &id);
glBindTexture(target, id);
if (caps.extTextureStorage)
{
if (type == Texture::Type_3D)
{
glTexStorage3D(target, mipLevels, formatGl.internalFormat, width, height, depth);
}
else if (type == Texture::Type_2DMultisampled)
{
glTexStorage2DMultisample(target, 4, formatGl.internalFormat, width, height, GL_TRUE);
}
else
{
glTexStorage2D(target, mipLevels, formatGl.internalFormat, width, height);
}
}
else
{
// Is this correct? There's a subtle difference here between desktop GL and GLES
#ifdef GLES
GLenum internalFormat = formatGl.dataFormat;
#else
GLenum internalFormat = formatGl.internalFormat;
#endif
unsigned int faces = (type == Texture::Type_Cube) ? 6 : 1;
for (unsigned int index = 0; index < faces; ++index)
{
GLenum faceTarget = (type == Texture::Type_Cube) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + index : target;
for (unsigned int mip = 0; mip < mipLevels; ++mip)
{
unsigned int mipWidth = Texture::getMipSide(width, mip);
unsigned int mipHeight = Texture::getMipSide(height, mip);
unsigned int mipDepth = Texture::getMipSide(depth, mip);
if (type == Texture::Type_3D)
{
glTexImage3D(faceTarget, mip, internalFormat, mipWidth, mipHeight, mipDepth, 0, formatGl.dataFormat, formatGl.dataType, NULL);
}
else if (Texture::isFormatCompressed(format))
{
unsigned int size = Texture::getImageSize(format, mipWidth, mipHeight);
// glCompressedTexImage does not accept NULL as a valid pointer
std::vector<char> data(size);
glCompressedTexImage2D(faceTarget, mip, formatGl.internalFormat, mipWidth, mipHeight, 0, size, &data[0]);
}
else
{
glTexImage2D(faceTarget, mip, internalFormat, mipWidth, mipHeight, 0, formatGl.dataFormat, formatGl.dataType, NULL);
}
}
}
}
if (caps.supportsTexturePartialMipChain)
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, mipLevels - 1);
else
AYAASSERT(mipLevels == 1 || mipLevels == Texture::getMaxMipCount(width, height, depth));
glBindTexture(target, 0);
return id;
}
static void uploadTexture(unsigned int id, Texture::Type type, Texture::Format format, unsigned int index, unsigned int mip,
const TextureRegion& region, bool entireRegion, const void* data, const DeviceCapsGL& caps)
{
GLenum target = gTextureTargetGL[type];
GLenum faceTarget = (type == Texture::Type_Cube) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + index : target;
const TextureFormatGL& formatGl = getTextureFormatGL(format, caps.ext3);
glActiveTexture(GL_TEXTURE0);
glBindTexture(target, id);
bool needsCustomAlignment = (!Texture::isFormatCompressed(format) && Texture::getFormatBits(format) < 32);
glPixelStorei(GL_UNPACK_ALIGNMENT, needsCustomAlignment ? 1 : 4);
if (type == Texture::Type_3D)
{
glTexSubImage3D(
faceTarget, mip, region.x, region.y, region.z, region.width, region.height, region.depth, formatGl.dataFormat, formatGl.dataType, data);
}
else
{
if (Texture::isFormatCompressed(format))
{
unsigned int size = Texture::getImageSize(format, region.width, region.height) * region.depth;
if (entireRegion && !doesFormatSupportPartialUpload(format) && !caps.extTextureStorage)
{
glCompressedTexImage2D(faceTarget, mip, formatGl.internalFormat, region.width, region.height, 0, size, data);
}
else
{
glCompressedTexSubImage2D(faceTarget, mip, region.x, region.y, region.width, region.height, formatGl.internalFormat, size, data);
}
}
else if (type == Texture::Type_2DMultisampled)
{
glTexStorage2DMultisample(faceTarget, 4, formatGl.internalFormat, region.width, region.height, GL_TRUE);
}
else
{
glTexSubImage2D(faceTarget, mip, region.x, region.y, region.width, region.height, formatGl.dataFormat, formatGl.dataType, data);
}
}
glBindTexture(target, 0);
}
TextureGL::TextureGL(
Device* device, Type type, Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels, Usage usage)
: Texture(device, type, format, width, height, depth, mipLevels, usage)
, id(0)
, cachedState(SamplerState::Filter_Count) // initialize state to invalid value to force a cache miss on the next setup
, external(false)
, scratchId(0)
, scratchOffset(0)
, scratchSize(0)
{
const DeviceCapsGL& caps = static_cast<DeviceGL*>(device)->getCapsGL();
const TextureFormatGL& formatGl = getTextureFormatGL(format, caps.ext3);
if (!formatGl.internalFormat)
throw Aya::runtime_error("Unsupported format: %d (platform)", format);
if ((format == Format_RGBA16F) && !caps.supportsTextureHalfFloat)
throw Aya::runtime_error("Unsupported format: %d (caps)", format);
if ((format == Format_BC1 || format == Format_BC2 || format == Format_BC3) && !caps.supportsTextureDXT)
throw Aya::runtime_error("Unsupported format: %d (caps)", format);
if ((format == Format_PVRTC_RGB2 || format == Format_PVRTC_RGBA2 || format == Format_PVRTC_RGB4 || format == Format_PVRTC_RGBA4) &&
!caps.supportsTexturePVR)
throw Aya::runtime_error("Unsupported format: %d (caps)", format);
if (format == Format_ETC1 && !caps.supportsTextureETC1)
throw Aya::runtime_error("Unsupported format: %d (capse)", format);
if (!caps.supportsTextureNPOT && ((width & (width - 1)) || (height & (height - 1)) || (depth & (depth - 1))) &&
(usage != Usage_Renderbuffer || mipLevels > 1))
throw Aya::runtime_error("Unsupported dimensions: %dx%dx%d (NPOT)", width, height, depth);
if (!caps.supportsTexture3D && type == Type_3D)
throw Aya::runtime_error("Unsupported type: 3D");
if (FFlag::GraphicsTextureCommitChanges && usage == Usage_Dynamic && isFormatCompressed(format))
throw Aya::runtime_error("Unsupported format: compressed formats are not supported for dynamic textures");
// createTexture poisons the binding on the first stage
static_cast<DeviceGL*>(device)->getImmediateContextGL()->invalidateCachedTextureStage(0);
id = createTexture(type, format, width, height, depth, mipLevels, caps);
if (FFlag::GraphicsTextureCommitChanges && usage == Usage_Dynamic && caps.ext3)
{
scratchSize = getTextureSize(type, format, width, height, depth, mipLevels);
glGenBuffers(1, &scratchId);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, scratchId);
glBufferData(GL_PIXEL_UNPACK_BUFFER, scratchSize, NULL, GL_DYNAMIC_COPY);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
}
TextureGL::TextureGL(Device* device, Type type, Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels,
Usage usage, unsigned int id)
: Texture(device, type, format, width, height, depth, mipLevels, usage)
, cachedState(SamplerState::Filter_Count) // initialize state to invalid value to force a cache miss on the next setup
, id(id)
, external(true)
, scratchId(0)
, scratchOffset(0)
, scratchSize(0)
{
}
TextureGL::~TextureGL()
{
static_cast<DeviceGL*>(device)->getImmediateContextGL()->invalidateCachedTexture(this);
if (scratchId)
glDeleteBuffers(1, &scratchId);
if (!external)
glDeleteTextures(1, &id);
}
void TextureGL::upload(unsigned int index, unsigned int mip, const TextureRegion& region, const void* data, unsigned int size)
{
const DeviceCapsGL& caps = static_cast<DeviceGL*>(device)->getCapsGL();
AYAASSERT(index < (type == Type_Cube ? 6u : 1u));
unsigned int mipWidth = getMipSide(width, mip);
unsigned int mipHeight = getMipSide(height, mip);
unsigned int mipDepth = getMipSide(depth, mip);
AYAASSERT(mip < mipLevels);
AYAASSERT(region.x + region.width <= mipWidth);
AYAASSERT(region.y + region.height <= mipHeight);
AYAASSERT(region.z + region.depth <= mipDepth);
AYAASSERT(size == getImageSize(format, region.width, region.height) * region.depth);
if (supportsLocking())
{
unsigned int bpp = getFormatBits(format) / 8;
LockResult lr = lock(index, mip, region);
for (unsigned int z = 0; z < region.depth; ++z)
for (unsigned int y = 0; y < region.height; ++y)
{
unsigned int sourceOffset = (region.width * region.height * z + region.width * y) * bpp;
unsigned int targetOffset = lr.slicePitch * z + lr.rowPitch * y;
memcpy(static_cast<char*>(lr.data) + targetOffset, static_cast<const char*>(data) + sourceOffset, region.width * bpp);
}
unlock(index, mip);
}
else
{
// uploadTexture poisons the binding on the first stage
static_cast<DeviceGL*>(device)->getImmediateContextGL()->invalidateCachedTextureStage(0);
bool entireRegion = (region.x == 0 && region.y == 0 && region.width == mipWidth && region.height == mipHeight);
uploadTexture(id, type, format, index, mip, region, entireRegion, data, caps);
}
}
#ifdef GLES
bool TextureGL::download(unsigned int index, unsigned int mip, void* data, unsigned int size)
{
return false;
}
#else
bool TextureGL::download(unsigned int index, unsigned int mip, void* data, unsigned int size)
{
const DeviceCapsGL& caps = static_cast<DeviceGL*>(device)->getCapsGL();
GLenum target = gTextureTargetGL[type];
const TextureFormatGL& formatGl = getTextureFormatGL(format, caps.ext3);
AYAASSERT(index < (type == Type_Cube ? 6u : 1u));
GLenum faceTarget = (type == Type_Cube) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + index : target;
unsigned int mipWidth = getMipSide(width, mip);
unsigned int mipHeight = getMipSide(height, mip);
unsigned int mipDepth = getMipSide(depth, mip);
AYAASSERT(mip < mipLevels);
AYAASSERT(size == getImageSize(format, mipWidth, mipHeight) * mipDepth);
static_cast<DeviceGL*>(device)->getImmediateContextGL()->invalidateCachedTextureStage(0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(target, id);
bool needsCustomAlignment = (!isFormatCompressed(format) && getFormatBits(format) < 32);
glPixelStorei(GL_PACK_ALIGNMENT, needsCustomAlignment ? 1 : 4);
if (isFormatCompressed(format))
glGetCompressedTexImage(faceTarget, mip, data);
else
glGetTexImage(faceTarget, mip, formatGl.dataFormat, formatGl.dataType, data);
glBindTexture(target, 0);
return true;
}
#endif
bool TextureGL::supportsLocking() const
{
if (FFlag::GraphicsTextureCommitChanges)
return scratchId != 0;
return false;
}
Texture::LockResult TextureGL::lock(unsigned int index, unsigned int mip, const TextureRegion& region)
{
if (!scratchId)
{
Texture::LockResult result = {0, 0, 0};
return result;
}
AYAASSERT(index < (type == Type_Cube ? 6u : 1u));
unsigned int mipWidth = getMipSide(width, mip);
unsigned int mipHeight = getMipSide(height, mip);
unsigned int mipDepth = getMipSide(depth, mip);
AYAASSERT(mip < mipLevels);
AYAASSERT(region.x + region.width <= mipWidth);
AYAASSERT(region.y + region.height <= mipHeight);
AYAASSERT(region.z + region.depth <= mipDepth);
unsigned int size = getImageSize(format, region.width, region.height) * region.depth;
unsigned int flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
if (scratchOffset + size > scratchSize)
{
commitChanges();
scratchOffset = 0;
flags = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT;
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, scratchId);
void* data = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, scratchOffset, size, flags);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
Change change = {index, mip, region, scratchOffset};
scratchOffset += size;
pendingChanges.push_back(change);
Texture::LockResult result = {data, getImageSize(format, region.width, 1), getImageSize(format, region.width, region.height)};
return result;
}
void TextureGL::unlock(unsigned int index, unsigned int mip)
{
if (!scratchId)
return;
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, scratchId);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
shared_ptr<Renderbuffer> TextureGL::getRenderbuffer(unsigned int index, unsigned int mip)
{
AYAASSERT(usage == Usage_Renderbuffer);
AYAASSERT(mip == 0);
AYAASSERT(index < (type == Type_Cube ? 6u : 1u));
weak_ptr<Renderbuffer>& slot = renderBuffers[std::make_pair(index, mip)];
shared_ptr<Renderbuffer> rb = slot.lock();
if (!rb)
{
GLenum target = (type == Texture::Type_Cube) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + index : gTextureTargetGL[type];
rb.reset(new RenderbufferGL(device, shared_from_this(), target, getType() == Texture::Type_2DMultisampled ? 4 : 1));
slot = rb;
}
return rb;
}
void TextureGL::commitChanges()
{
if (!FFlag::GraphicsTextureCommitChanges)
return;
const DeviceCapsGL& caps = static_cast<DeviceGL*>(device)->getCapsGL();
if (pendingChanges.empty())
return;
// uploadTexture poisons the binding on the first stage
static_cast<DeviceGL*>(device)->getImmediateContextGL()->invalidateCachedTextureStage(0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, scratchId);
for (auto& change : pendingChanges)
{
AYAASSERT(change.scratchOffset < scratchOffset);
bool entireRegion = false; // this is only important for compressed formats that we don't support
uploadTexture(id, type, format, change.index, change.mip, change.region, entireRegion, reinterpret_cast<void*>(change.scratchOffset), caps);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
pendingChanges.clear();
}
void TextureGL::generateMipmaps()
{
AYAASSERT(usage != Usage_Dynamic);
if (mipLevels <= 1)
return;
static_cast<DeviceGL*>(device)->getImmediateContextGL()->invalidateCachedTextureStage(0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(gTextureTargetGL[type], id);
glGenerateMipmap(gTextureTargetGL[type]);
glBindTexture(gTextureTargetGL[type], 0);
}
void TextureGL::bind(unsigned int stage, const SamplerState& state, TextureGL** cache)
{
if (*cache != this || cachedState != state)
{
glActiveTexture(GL_TEXTURE0 + stage);
GLenum target = gTextureTargetGL[type];
if (*cache != this)
{
*cache = this;
glBindTexture(target, id);
}
if (cachedState != state)
{
cachedState = state;
bool hasMips = mipLevels > 1;
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, gSamplerFilterMinGL[state.getFilter()][hasMips]);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, gSamplerFilterMagGL[state.getFilter()]);
glTexParameteri(target, GL_TEXTURE_WRAP_S, gSamplerAddressGL[state.getAddress()]);
glTexParameteri(target, GL_TEXTURE_WRAP_T, gSamplerAddressGL[state.getAddress()]);
#ifndef GLES
int anisotropy = state.getFilter() == SamplerState::Filter_Anisotropic ? state.getAnisotropy() : 1;
glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast<float>(anisotropy));
#endif
}
}
}
unsigned int TextureGL::getTarget() const
{
return gTextureTargetGL[type];
}
unsigned int TextureGL::getInternalFormat(Format format)
{
return gTextureFormatGL[format].internalFormat;
}
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,75 @@
#pragma once
#include "Core/Texture.hpp"
#include "Core/States.hpp"
#include <boost/enable_shared_from_this.hpp>
#include <map>
#include <vector>
namespace Aya
{
namespace Graphics
{
class TextureGL
: public Texture
, public boost::enable_shared_from_this<TextureGL>
{
public:
TextureGL(
Device* device, Type type, Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels, Usage usage);
TextureGL(Device* device, Type type, Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels,
Usage usage, unsigned int id);
~TextureGL();
virtual void upload(unsigned int index, unsigned int mip, const TextureRegion& region, const void* data, unsigned int size);
virtual bool download(unsigned int index, unsigned int mip, void* data, unsigned int size);
virtual bool supportsLocking() const;
virtual LockResult lock(unsigned int index, unsigned int mip, const TextureRegion& region);
virtual void unlock(unsigned int index, unsigned int mip);
virtual shared_ptr<Renderbuffer> getRenderbuffer(unsigned int index, unsigned int mip);
virtual void commitChanges();
virtual void generateMipmaps();
void bind(unsigned int stage, const SamplerState& state, TextureGL** cache);
unsigned int getId() const
{
return id;
}
unsigned int getTarget() const;
static unsigned int getInternalFormat(Format format);
private:
struct Change
{
unsigned int index;
unsigned int mip;
TextureRegion region;
unsigned int scratchOffset;
};
unsigned int id;
SamplerState cachedState;
bool external;
unsigned int scratchId;
unsigned int scratchOffset;
unsigned int scratchSize;
std::vector<Change> pendingChanges;
typedef std::map<std::pair<unsigned, unsigned>, weak_ptr<Renderbuffer>> RenderBufferMap;
RenderBufferMap renderBuffers;
};
} // namespace Graphics
} // namespace Aya

View File

@@ -0,0 +1,175 @@
#ifndef __eglplatform_h_
#define __eglplatform_h_
/*
** Copyright 2007-2020 The Khronos Group Inc.
** SPDX-License-Identifier: Apache-2.0
*/
/* Platform-specific types and definitions for egl.h
*
* Adopters may modify khrplatform.h and this file to suit their platform.
* You are encouraged to submit all modifications to the Khronos group so that
* they can be included in future versions of this file. Please submit changes
* by filing an issue or pull request on the public Khronos EGL Registry, at
* https://www.github.com/KhronosGroup/EGL-Registry/
*/
#include <KHR/khrplatform.h>
/* Macros used in EGL function prototype declarations.
*
* EGL functions should be prototyped as:
*
* EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
* typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
*
* KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
*/
#ifndef EGLAPI
#define EGLAPI KHRONOS_APICALL
#endif
#ifndef EGLAPIENTRY
#define EGLAPIENTRY KHRONOS_APIENTRY
#endif
#define EGLAPIENTRYP EGLAPIENTRY*
/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
* are aliases of window-system-dependent types, such as X Display * or
* Windows Device Context. They must be defined in platform-specific
* code below. The EGL-prefixed versions of Native*Type are the same
* types, renamed in EGL 1.3 so all types in the API start with "EGL".
*
* Khronos STRONGLY RECOMMENDS that you use the default definitions
* provided below, since these changes affect both binary and source
* portability of applications using EGL running on different EGL
* implementations.
*/
#if defined(EGL_NO_PLATFORM_SPECIFIC_TYPES)
typedef void *EGLNativeDisplayType;
typedef void *EGLNativePixmapType;
typedef void *EGLNativeWindowType;
#elif defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
typedef HDC EGLNativeDisplayType;
typedef HBITMAP EGLNativePixmapType;
typedef HWND EGLNativeWindowType;
#elif defined(__QNX__)
typedef khronos_uintptr_t EGLNativeDisplayType;
typedef struct _screen_pixmap* EGLNativePixmapType; /* screen_pixmap_t */
typedef struct _screen_window* EGLNativeWindowType; /* screen_window_t */
#elif defined(__EMSCRIPTEN__)
typedef int EGLNativeDisplayType;
typedef int EGLNativePixmapType;
typedef int EGLNativeWindowType;
#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
typedef int EGLNativeDisplayType;
typedef void *EGLNativePixmapType;
typedef void *EGLNativeWindowType;
#elif defined(WL_EGL_PLATFORM)
typedef struct wl_display *EGLNativeDisplayType;
typedef struct wl_egl_pixmap *EGLNativePixmapType;
typedef struct wl_egl_window *EGLNativeWindowType;
#elif defined(__GBM__)
typedef struct gbm_device *EGLNativeDisplayType;
typedef struct gbm_bo *EGLNativePixmapType;
typedef void *EGLNativeWindowType;
#elif defined(__ANDROID__) || defined(ANDROID)
struct ANativeWindow;
struct egl_native_pixmap_t;
typedef void* EGLNativeDisplayType;
typedef struct egl_native_pixmap_t* EGLNativePixmapType;
typedef struct ANativeWindow* EGLNativeWindowType;
#elif defined(USE_OZONE)
typedef intptr_t EGLNativeDisplayType;
typedef intptr_t EGLNativePixmapType;
typedef intptr_t EGLNativeWindowType;
#elif defined(USE_X11)
/* X11 (tentative) */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
typedef Display *EGLNativeDisplayType;
typedef Pixmap EGLNativePixmapType;
typedef Window EGLNativeWindowType;
#elif defined(__unix__)
typedef void *EGLNativeDisplayType;
typedef khronos_uintptr_t EGLNativePixmapType;
typedef khronos_uintptr_t EGLNativeWindowType;
#elif defined(__APPLE__)
typedef int EGLNativeDisplayType;
typedef void *EGLNativePixmapType;
typedef void *EGLNativeWindowType;
#elif defined(__HAIKU__)
#include <kernel/image.h>
typedef void *EGLNativeDisplayType;
typedef khronos_uintptr_t EGLNativePixmapType;
typedef khronos_uintptr_t EGLNativeWindowType;
#elif defined(__Fuchsia__)
typedef void *EGLNativeDisplayType;
typedef khronos_uintptr_t EGLNativePixmapType;
typedef khronos_uintptr_t EGLNativeWindowType;
#else
#error "Platform not recognized"
#endif
/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
typedef EGLNativeDisplayType NativeDisplayType;
typedef EGLNativePixmapType NativePixmapType;
typedef EGLNativeWindowType NativeWindowType;
/* Define EGLint. This must be a signed integral type large enough to contain
* all legal attribute names and values passed into and out of EGL, whether
* their type is boolean, bitmask, enumerant (symbolic constant), integer,
* handle, or other. While in general a 32-bit integer will suffice, if
* handles are 64 bit types, then EGLint should be defined as a signed 64-bit
* integer type.
*/
typedef khronos_int32_t EGLint;
/* C++ / C typecast macros for special EGL handle values */
#if defined(__cplusplus)
#define EGL_CAST(type, value) (static_cast<type>(value))
#else
#define EGL_CAST(type, value) ((type) (value))
#endif
#endif /* __eglplatform_h */

View File

@@ -0,0 +1,311 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are 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 Materials.
**
** THE MATERIALS ARE 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
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* The master copy of khrplatform.h is maintained in the Khronos EGL
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
* The last semantic modification to khrplatform.h was at commit ID:
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by filing pull requests or issues on
* the EGL Registry repository linked above.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,798 @@
/**
* SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glad/glx.h>
#ifndef GLAD_IMPL_UTIL_C_
#define GLAD_IMPL_UTIL_C_
#ifdef _MSC_VER
#define GLAD_IMPL_UTIL_SSCANF sscanf_s
#else
#define GLAD_IMPL_UTIL_SSCANF sscanf
#endif
#endif /* GLAD_IMPL_UTIL_C_ */
#ifdef __cplusplus
extern "C" {
#endif
int GLAD_GLX_VERSION_1_0 = 0;
int GLAD_GLX_VERSION_1_1 = 0;
int GLAD_GLX_VERSION_1_2 = 0;
int GLAD_GLX_VERSION_1_3 = 0;
int GLAD_GLX_VERSION_1_4 = 0;
int GLAD_GLX_3DFX_multisample = 0;
int GLAD_GLX_AMD_gpu_association = 0;
int GLAD_GLX_ARB_context_flush_control = 0;
int GLAD_GLX_ARB_create_context = 0;
int GLAD_GLX_ARB_create_context_no_error = 0;
int GLAD_GLX_ARB_create_context_profile = 0;
int GLAD_GLX_ARB_create_context_robustness = 0;
int GLAD_GLX_ARB_fbconfig_float = 0;
int GLAD_GLX_ARB_framebuffer_sRGB = 0;
int GLAD_GLX_ARB_get_proc_address = 0;
int GLAD_GLX_ARB_multisample = 0;
int GLAD_GLX_ARB_robustness_application_isolation = 0;
int GLAD_GLX_ARB_robustness_share_group_isolation = 0;
int GLAD_GLX_ARB_vertex_buffer_object = 0;
int GLAD_GLX_EXT_buffer_age = 0;
int GLAD_GLX_EXT_context_priority = 0;
int GLAD_GLX_EXT_create_context_es2_profile = 0;
int GLAD_GLX_EXT_create_context_es_profile = 0;
int GLAD_GLX_EXT_fbconfig_packed_float = 0;
int GLAD_GLX_EXT_framebuffer_sRGB = 0;
int GLAD_GLX_EXT_get_drawable_type = 0;
int GLAD_GLX_EXT_import_context = 0;
int GLAD_GLX_EXT_libglvnd = 0;
int GLAD_GLX_EXT_no_config_context = 0;
int GLAD_GLX_EXT_stereo_tree = 0;
int GLAD_GLX_EXT_swap_control = 0;
int GLAD_GLX_EXT_swap_control_tear = 0;
int GLAD_GLX_EXT_texture_from_pixmap = 0;
int GLAD_GLX_EXT_visual_info = 0;
int GLAD_GLX_EXT_visual_rating = 0;
int GLAD_GLX_INTEL_swap_event = 0;
int GLAD_GLX_MESA_agp_offset = 0;
int GLAD_GLX_MESA_copy_sub_buffer = 0;
int GLAD_GLX_MESA_pixmap_colormap = 0;
int GLAD_GLX_MESA_query_renderer = 0;
int GLAD_GLX_MESA_release_buffers = 0;
int GLAD_GLX_MESA_set_3dfx_mode = 0;
int GLAD_GLX_MESA_swap_control = 0;
int GLAD_GLX_NV_copy_buffer = 0;
int GLAD_GLX_NV_copy_image = 0;
int GLAD_GLX_NV_delay_before_swap = 0;
int GLAD_GLX_NV_float_buffer = 0;
int GLAD_GLX_NV_multigpu_context = 0;
int GLAD_GLX_NV_multisample_coverage = 0;
int GLAD_GLX_NV_present_video = 0;
int GLAD_GLX_NV_robustness_video_memory_purge = 0;
int GLAD_GLX_NV_swap_group = 0;
int GLAD_GLX_NV_video_capture = 0;
int GLAD_GLX_NV_video_out = 0;
int GLAD_GLX_OML_swap_method = 0;
int GLAD_GLX_OML_sync_control = 0;
int GLAD_GLX_SGIS_blended_overlay = 0;
int GLAD_GLX_SGIS_multisample = 0;
int GLAD_GLX_SGIS_shared_multisample = 0;
int GLAD_GLX_SGIX_fbconfig = 0;
int GLAD_GLX_SGIX_hyperpipe = 0;
int GLAD_GLX_SGIX_pbuffer = 0;
int GLAD_GLX_SGIX_swap_barrier = 0;
int GLAD_GLX_SGIX_swap_group = 0;
int GLAD_GLX_SGIX_video_resize = 0;
int GLAD_GLX_SGIX_visual_select_group = 0;
int GLAD_GLX_SGI_cushion = 0;
int GLAD_GLX_SGI_make_current_read = 0;
int GLAD_GLX_SGI_swap_control = 0;
int GLAD_GLX_SGI_video_sync = 0;
int GLAD_GLX_SUN_get_transparent_index = 0;
PFNGLXBINDCHANNELTOWINDOWSGIXPROC glad_glXBindChannelToWindowSGIX = NULL;
PFNGLXBINDHYPERPIPESGIXPROC glad_glXBindHyperpipeSGIX = NULL;
PFNGLXBINDSWAPBARRIERNVPROC glad_glXBindSwapBarrierNV = NULL;
PFNGLXBINDSWAPBARRIERSGIXPROC glad_glXBindSwapBarrierSGIX = NULL;
PFNGLXBINDTEXIMAGEEXTPROC glad_glXBindTexImageEXT = NULL;
PFNGLXBINDVIDEOCAPTUREDEVICENVPROC glad_glXBindVideoCaptureDeviceNV = NULL;
PFNGLXBINDVIDEODEVICENVPROC glad_glXBindVideoDeviceNV = NULL;
PFNGLXBINDVIDEOIMAGENVPROC glad_glXBindVideoImageNV = NULL;
PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC glad_glXBlitContextFramebufferAMD = NULL;
PFNGLXCHANNELRECTSGIXPROC glad_glXChannelRectSGIX = NULL;
PFNGLXCHANNELRECTSYNCSGIXPROC glad_glXChannelRectSyncSGIX = NULL;
PFNGLXCHOOSEFBCONFIGPROC glad_glXChooseFBConfig = NULL;
PFNGLXCHOOSEFBCONFIGSGIXPROC glad_glXChooseFBConfigSGIX = NULL;
PFNGLXCHOOSEVISUALPROC glad_glXChooseVisual = NULL;
PFNGLXCOPYBUFFERSUBDATANVPROC glad_glXCopyBufferSubDataNV = NULL;
PFNGLXCOPYCONTEXTPROC glad_glXCopyContext = NULL;
PFNGLXCOPYIMAGESUBDATANVPROC glad_glXCopyImageSubDataNV = NULL;
PFNGLXCOPYSUBBUFFERMESAPROC glad_glXCopySubBufferMESA = NULL;
PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC glad_glXCreateAssociatedContextAMD = NULL;
PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC glad_glXCreateAssociatedContextAttribsAMD = NULL;
PFNGLXCREATECONTEXTPROC glad_glXCreateContext = NULL;
PFNGLXCREATECONTEXTATTRIBSARBPROC glad_glXCreateContextAttribsARB = NULL;
PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC glad_glXCreateContextWithConfigSGIX = NULL;
PFNGLXCREATEGLXPBUFFERSGIXPROC glad_glXCreateGLXPbufferSGIX = NULL;
PFNGLXCREATEGLXPIXMAPPROC glad_glXCreateGLXPixmap = NULL;
PFNGLXCREATEGLXPIXMAPMESAPROC glad_glXCreateGLXPixmapMESA = NULL;
PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC glad_glXCreateGLXPixmapWithConfigSGIX = NULL;
PFNGLXCREATENEWCONTEXTPROC glad_glXCreateNewContext = NULL;
PFNGLXCREATEPBUFFERPROC glad_glXCreatePbuffer = NULL;
PFNGLXCREATEPIXMAPPROC glad_glXCreatePixmap = NULL;
PFNGLXCREATEWINDOWPROC glad_glXCreateWindow = NULL;
PFNGLXCUSHIONSGIPROC glad_glXCushionSGI = NULL;
PFNGLXDELAYBEFORESWAPNVPROC glad_glXDelayBeforeSwapNV = NULL;
PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC glad_glXDeleteAssociatedContextAMD = NULL;
PFNGLXDESTROYCONTEXTPROC glad_glXDestroyContext = NULL;
PFNGLXDESTROYGLXPBUFFERSGIXPROC glad_glXDestroyGLXPbufferSGIX = NULL;
PFNGLXDESTROYGLXPIXMAPPROC glad_glXDestroyGLXPixmap = NULL;
PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC glad_glXDestroyHyperpipeConfigSGIX = NULL;
PFNGLXDESTROYPBUFFERPROC glad_glXDestroyPbuffer = NULL;
PFNGLXDESTROYPIXMAPPROC glad_glXDestroyPixmap = NULL;
PFNGLXDESTROYWINDOWPROC glad_glXDestroyWindow = NULL;
PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC glad_glXEnumerateVideoCaptureDevicesNV = NULL;
PFNGLXENUMERATEVIDEODEVICESNVPROC glad_glXEnumerateVideoDevicesNV = NULL;
PFNGLXFREECONTEXTEXTPROC glad_glXFreeContextEXT = NULL;
PFNGLXGETAGPOFFSETMESAPROC glad_glXGetAGPOffsetMESA = NULL;
PFNGLXGETCLIENTSTRINGPROC glad_glXGetClientString = NULL;
PFNGLXGETCONFIGPROC glad_glXGetConfig = NULL;
PFNGLXGETCONTEXTGPUIDAMDPROC glad_glXGetContextGPUIDAMD = NULL;
PFNGLXGETCONTEXTIDEXTPROC glad_glXGetContextIDEXT = NULL;
PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC glad_glXGetCurrentAssociatedContextAMD = NULL;
PFNGLXGETCURRENTCONTEXTPROC glad_glXGetCurrentContext = NULL;
PFNGLXGETCURRENTDISPLAYPROC glad_glXGetCurrentDisplay = NULL;
PFNGLXGETCURRENTDISPLAYEXTPROC glad_glXGetCurrentDisplayEXT = NULL;
PFNGLXGETCURRENTDRAWABLEPROC glad_glXGetCurrentDrawable = NULL;
PFNGLXGETCURRENTREADDRAWABLEPROC glad_glXGetCurrentReadDrawable = NULL;
PFNGLXGETCURRENTREADDRAWABLESGIPROC glad_glXGetCurrentReadDrawableSGI = NULL;
PFNGLXGETFBCONFIGATTRIBPROC glad_glXGetFBConfigAttrib = NULL;
PFNGLXGETFBCONFIGATTRIBSGIXPROC glad_glXGetFBConfigAttribSGIX = NULL;
PFNGLXGETFBCONFIGFROMVISUALSGIXPROC glad_glXGetFBConfigFromVisualSGIX = NULL;
PFNGLXGETFBCONFIGSPROC glad_glXGetFBConfigs = NULL;
PFNGLXGETGPUIDSAMDPROC glad_glXGetGPUIDsAMD = NULL;
PFNGLXGETGPUINFOAMDPROC glad_glXGetGPUInfoAMD = NULL;
PFNGLXGETMSCRATEOMLPROC glad_glXGetMscRateOML = NULL;
PFNGLXGETPROCADDRESSPROC glad_glXGetProcAddress = NULL;
PFNGLXGETPROCADDRESSARBPROC glad_glXGetProcAddressARB = NULL;
PFNGLXGETSELECTEDEVENTPROC glad_glXGetSelectedEvent = NULL;
PFNGLXGETSELECTEDEVENTSGIXPROC glad_glXGetSelectedEventSGIX = NULL;
PFNGLXGETSWAPINTERVALMESAPROC glad_glXGetSwapIntervalMESA = NULL;
PFNGLXGETSYNCVALUESOMLPROC glad_glXGetSyncValuesOML = NULL;
PFNGLXGETTRANSPARENTINDEXSUNPROC glad_glXGetTransparentIndexSUN = NULL;
PFNGLXGETVIDEODEVICENVPROC glad_glXGetVideoDeviceNV = NULL;
PFNGLXGETVIDEOINFONVPROC glad_glXGetVideoInfoNV = NULL;
PFNGLXGETVIDEOSYNCSGIPROC glad_glXGetVideoSyncSGI = NULL;
PFNGLXGETVISUALFROMFBCONFIGPROC glad_glXGetVisualFromFBConfig = NULL;
PFNGLXGETVISUALFROMFBCONFIGSGIXPROC glad_glXGetVisualFromFBConfigSGIX = NULL;
PFNGLXHYPERPIPEATTRIBSGIXPROC glad_glXHyperpipeAttribSGIX = NULL;
PFNGLXHYPERPIPECONFIGSGIXPROC glad_glXHyperpipeConfigSGIX = NULL;
PFNGLXIMPORTCONTEXTEXTPROC glad_glXImportContextEXT = NULL;
PFNGLXISDIRECTPROC glad_glXIsDirect = NULL;
PFNGLXJOINSWAPGROUPNVPROC glad_glXJoinSwapGroupNV = NULL;
PFNGLXJOINSWAPGROUPSGIXPROC glad_glXJoinSwapGroupSGIX = NULL;
PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC glad_glXLockVideoCaptureDeviceNV = NULL;
PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC glad_glXMakeAssociatedContextCurrentAMD = NULL;
PFNGLXMAKECONTEXTCURRENTPROC glad_glXMakeContextCurrent = NULL;
PFNGLXMAKECURRENTPROC glad_glXMakeCurrent = NULL;
PFNGLXMAKECURRENTREADSGIPROC glad_glXMakeCurrentReadSGI = NULL;
PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC glad_glXNamedCopyBufferSubDataNV = NULL;
PFNGLXQUERYCHANNELDELTASSGIXPROC glad_glXQueryChannelDeltasSGIX = NULL;
PFNGLXQUERYCHANNELRECTSGIXPROC glad_glXQueryChannelRectSGIX = NULL;
PFNGLXQUERYCONTEXTPROC glad_glXQueryContext = NULL;
PFNGLXQUERYCONTEXTINFOEXTPROC glad_glXQueryContextInfoEXT = NULL;
PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC glad_glXQueryCurrentRendererIntegerMESA = NULL;
PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC glad_glXQueryCurrentRendererStringMESA = NULL;
PFNGLXQUERYDRAWABLEPROC glad_glXQueryDrawable = NULL;
PFNGLXQUERYEXTENSIONPROC glad_glXQueryExtension = NULL;
PFNGLXQUERYEXTENSIONSSTRINGPROC glad_glXQueryExtensionsString = NULL;
PFNGLXQUERYFRAMECOUNTNVPROC glad_glXQueryFrameCountNV = NULL;
PFNGLXQUERYGLXPBUFFERSGIXPROC glad_glXQueryGLXPbufferSGIX = NULL;
PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC glad_glXQueryHyperpipeAttribSGIX = NULL;
PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC glad_glXQueryHyperpipeBestAttribSGIX = NULL;
PFNGLXQUERYHYPERPIPECONFIGSGIXPROC glad_glXQueryHyperpipeConfigSGIX = NULL;
PFNGLXQUERYHYPERPIPENETWORKSGIXPROC glad_glXQueryHyperpipeNetworkSGIX = NULL;
PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC glad_glXQueryMaxSwapBarriersSGIX = NULL;
PFNGLXQUERYMAXSWAPGROUPSNVPROC glad_glXQueryMaxSwapGroupsNV = NULL;
PFNGLXQUERYRENDERERINTEGERMESAPROC glad_glXQueryRendererIntegerMESA = NULL;
PFNGLXQUERYRENDERERSTRINGMESAPROC glad_glXQueryRendererStringMESA = NULL;
PFNGLXQUERYSERVERSTRINGPROC glad_glXQueryServerString = NULL;
PFNGLXQUERYSWAPGROUPNVPROC glad_glXQuerySwapGroupNV = NULL;
PFNGLXQUERYVERSIONPROC glad_glXQueryVersion = NULL;
PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC glad_glXQueryVideoCaptureDeviceNV = NULL;
PFNGLXRELEASEBUFFERSMESAPROC glad_glXReleaseBuffersMESA = NULL;
PFNGLXRELEASETEXIMAGEEXTPROC glad_glXReleaseTexImageEXT = NULL;
PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC glad_glXReleaseVideoCaptureDeviceNV = NULL;
PFNGLXRELEASEVIDEODEVICENVPROC glad_glXReleaseVideoDeviceNV = NULL;
PFNGLXRELEASEVIDEOIMAGENVPROC glad_glXReleaseVideoImageNV = NULL;
PFNGLXRESETFRAMECOUNTNVPROC glad_glXResetFrameCountNV = NULL;
PFNGLXSELECTEVENTPROC glad_glXSelectEvent = NULL;
PFNGLXSELECTEVENTSGIXPROC glad_glXSelectEventSGIX = NULL;
PFNGLXSENDPBUFFERTOVIDEONVPROC glad_glXSendPbufferToVideoNV = NULL;
PFNGLXSET3DFXMODEMESAPROC glad_glXSet3DfxModeMESA = NULL;
PFNGLXSWAPBUFFERSPROC glad_glXSwapBuffers = NULL;
PFNGLXSWAPBUFFERSMSCOMLPROC glad_glXSwapBuffersMscOML = NULL;
PFNGLXSWAPINTERVALEXTPROC glad_glXSwapIntervalEXT = NULL;
PFNGLXSWAPINTERVALMESAPROC glad_glXSwapIntervalMESA = NULL;
PFNGLXSWAPINTERVALSGIPROC glad_glXSwapIntervalSGI = NULL;
PFNGLXUSEXFONTPROC glad_glXUseXFont = NULL;
PFNGLXWAITFORMSCOMLPROC glad_glXWaitForMscOML = NULL;
PFNGLXWAITFORSBCOMLPROC glad_glXWaitForSbcOML = NULL;
PFNGLXWAITGLPROC glad_glXWaitGL = NULL;
PFNGLXWAITVIDEOSYNCSGIPROC glad_glXWaitVideoSyncSGI = NULL;
PFNGLXWAITXPROC glad_glXWaitX = NULL;
static void glad_glx_load_GLX_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_VERSION_1_0) return;
glad_glXChooseVisual = (PFNGLXCHOOSEVISUALPROC) load(userptr, "glXChooseVisual");
glad_glXCopyContext = (PFNGLXCOPYCONTEXTPROC) load(userptr, "glXCopyContext");
glad_glXCreateContext = (PFNGLXCREATECONTEXTPROC) load(userptr, "glXCreateContext");
glad_glXCreateGLXPixmap = (PFNGLXCREATEGLXPIXMAPPROC) load(userptr, "glXCreateGLXPixmap");
glad_glXDestroyContext = (PFNGLXDESTROYCONTEXTPROC) load(userptr, "glXDestroyContext");
glad_glXDestroyGLXPixmap = (PFNGLXDESTROYGLXPIXMAPPROC) load(userptr, "glXDestroyGLXPixmap");
glad_glXGetConfig = (PFNGLXGETCONFIGPROC) load(userptr, "glXGetConfig");
glad_glXGetCurrentContext = (PFNGLXGETCURRENTCONTEXTPROC) load(userptr, "glXGetCurrentContext");
glad_glXGetCurrentDrawable = (PFNGLXGETCURRENTDRAWABLEPROC) load(userptr, "glXGetCurrentDrawable");
glad_glXIsDirect = (PFNGLXISDIRECTPROC) load(userptr, "glXIsDirect");
glad_glXMakeCurrent = (PFNGLXMAKECURRENTPROC) load(userptr, "glXMakeCurrent");
glad_glXQueryExtension = (PFNGLXQUERYEXTENSIONPROC) load(userptr, "glXQueryExtension");
glad_glXQueryVersion = (PFNGLXQUERYVERSIONPROC) load(userptr, "glXQueryVersion");
glad_glXSwapBuffers = (PFNGLXSWAPBUFFERSPROC) load(userptr, "glXSwapBuffers");
glad_glXUseXFont = (PFNGLXUSEXFONTPROC) load(userptr, "glXUseXFont");
glad_glXWaitGL = (PFNGLXWAITGLPROC) load(userptr, "glXWaitGL");
glad_glXWaitX = (PFNGLXWAITXPROC) load(userptr, "glXWaitX");
}
static void glad_glx_load_GLX_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_VERSION_1_1) return;
glad_glXGetClientString = (PFNGLXGETCLIENTSTRINGPROC) load(userptr, "glXGetClientString");
glad_glXQueryExtensionsString = (PFNGLXQUERYEXTENSIONSSTRINGPROC) load(userptr, "glXQueryExtensionsString");
glad_glXQueryServerString = (PFNGLXQUERYSERVERSTRINGPROC) load(userptr, "glXQueryServerString");
}
static void glad_glx_load_GLX_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_VERSION_1_2) return;
glad_glXGetCurrentDisplay = (PFNGLXGETCURRENTDISPLAYPROC) load(userptr, "glXGetCurrentDisplay");
}
static void glad_glx_load_GLX_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_VERSION_1_3) return;
glad_glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC) load(userptr, "glXChooseFBConfig");
glad_glXCreateNewContext = (PFNGLXCREATENEWCONTEXTPROC) load(userptr, "glXCreateNewContext");
glad_glXCreatePbuffer = (PFNGLXCREATEPBUFFERPROC) load(userptr, "glXCreatePbuffer");
glad_glXCreatePixmap = (PFNGLXCREATEPIXMAPPROC) load(userptr, "glXCreatePixmap");
glad_glXCreateWindow = (PFNGLXCREATEWINDOWPROC) load(userptr, "glXCreateWindow");
glad_glXDestroyPbuffer = (PFNGLXDESTROYPBUFFERPROC) load(userptr, "glXDestroyPbuffer");
glad_glXDestroyPixmap = (PFNGLXDESTROYPIXMAPPROC) load(userptr, "glXDestroyPixmap");
glad_glXDestroyWindow = (PFNGLXDESTROYWINDOWPROC) load(userptr, "glXDestroyWindow");
glad_glXGetCurrentReadDrawable = (PFNGLXGETCURRENTREADDRAWABLEPROC) load(userptr, "glXGetCurrentReadDrawable");
glad_glXGetFBConfigAttrib = (PFNGLXGETFBCONFIGATTRIBPROC) load(userptr, "glXGetFBConfigAttrib");
glad_glXGetFBConfigs = (PFNGLXGETFBCONFIGSPROC) load(userptr, "glXGetFBConfigs");
glad_glXGetSelectedEvent = (PFNGLXGETSELECTEDEVENTPROC) load(userptr, "glXGetSelectedEvent");
glad_glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC) load(userptr, "glXGetVisualFromFBConfig");
glad_glXMakeContextCurrent = (PFNGLXMAKECONTEXTCURRENTPROC) load(userptr, "glXMakeContextCurrent");
glad_glXQueryContext = (PFNGLXQUERYCONTEXTPROC) load(userptr, "glXQueryContext");
glad_glXQueryDrawable = (PFNGLXQUERYDRAWABLEPROC) load(userptr, "glXQueryDrawable");
glad_glXSelectEvent = (PFNGLXSELECTEVENTPROC) load(userptr, "glXSelectEvent");
}
static void glad_glx_load_GLX_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_VERSION_1_4) return;
glad_glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC) load(userptr, "glXGetProcAddress");
}
static void glad_glx_load_GLX_AMD_gpu_association( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_AMD_gpu_association) return;
glad_glXBlitContextFramebufferAMD = (PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC) load(userptr, "glXBlitContextFramebufferAMD");
glad_glXCreateAssociatedContextAMD = (PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC) load(userptr, "glXCreateAssociatedContextAMD");
glad_glXCreateAssociatedContextAttribsAMD = (PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) load(userptr, "glXCreateAssociatedContextAttribsAMD");
glad_glXDeleteAssociatedContextAMD = (PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC) load(userptr, "glXDeleteAssociatedContextAMD");
glad_glXGetContextGPUIDAMD = (PFNGLXGETCONTEXTGPUIDAMDPROC) load(userptr, "glXGetContextGPUIDAMD");
glad_glXGetCurrentAssociatedContextAMD = (PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC) load(userptr, "glXGetCurrentAssociatedContextAMD");
glad_glXGetGPUIDsAMD = (PFNGLXGETGPUIDSAMDPROC) load(userptr, "glXGetGPUIDsAMD");
glad_glXGetGPUInfoAMD = (PFNGLXGETGPUINFOAMDPROC) load(userptr, "glXGetGPUInfoAMD");
glad_glXMakeAssociatedContextCurrentAMD = (PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) load(userptr, "glXMakeAssociatedContextCurrentAMD");
}
static void glad_glx_load_GLX_ARB_create_context( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_ARB_create_context) return;
glad_glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) load(userptr, "glXCreateContextAttribsARB");
}
static void glad_glx_load_GLX_ARB_get_proc_address( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_ARB_get_proc_address) return;
glad_glXGetProcAddressARB = (PFNGLXGETPROCADDRESSARBPROC) load(userptr, "glXGetProcAddressARB");
}
static void glad_glx_load_GLX_EXT_import_context( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_EXT_import_context) return;
glad_glXFreeContextEXT = (PFNGLXFREECONTEXTEXTPROC) load(userptr, "glXFreeContextEXT");
glad_glXGetContextIDEXT = (PFNGLXGETCONTEXTIDEXTPROC) load(userptr, "glXGetContextIDEXT");
glad_glXGetCurrentDisplayEXT = (PFNGLXGETCURRENTDISPLAYEXTPROC) load(userptr, "glXGetCurrentDisplayEXT");
glad_glXImportContextEXT = (PFNGLXIMPORTCONTEXTEXTPROC) load(userptr, "glXImportContextEXT");
glad_glXQueryContextInfoEXT = (PFNGLXQUERYCONTEXTINFOEXTPROC) load(userptr, "glXQueryContextInfoEXT");
}
static void glad_glx_load_GLX_EXT_swap_control( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_EXT_swap_control) return;
glad_glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) load(userptr, "glXSwapIntervalEXT");
}
static void glad_glx_load_GLX_EXT_texture_from_pixmap( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_EXT_texture_from_pixmap) return;
glad_glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC) load(userptr, "glXBindTexImageEXT");
glad_glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC) load(userptr, "glXReleaseTexImageEXT");
}
static void glad_glx_load_GLX_MESA_agp_offset( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_MESA_agp_offset) return;
glad_glXGetAGPOffsetMESA = (PFNGLXGETAGPOFFSETMESAPROC) load(userptr, "glXGetAGPOffsetMESA");
}
static void glad_glx_load_GLX_MESA_copy_sub_buffer( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_MESA_copy_sub_buffer) return;
glad_glXCopySubBufferMESA = (PFNGLXCOPYSUBBUFFERMESAPROC) load(userptr, "glXCopySubBufferMESA");
}
static void glad_glx_load_GLX_MESA_pixmap_colormap( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_MESA_pixmap_colormap) return;
glad_glXCreateGLXPixmapMESA = (PFNGLXCREATEGLXPIXMAPMESAPROC) load(userptr, "glXCreateGLXPixmapMESA");
}
static void glad_glx_load_GLX_MESA_query_renderer( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_MESA_query_renderer) return;
glad_glXQueryCurrentRendererIntegerMESA = (PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) load(userptr, "glXQueryCurrentRendererIntegerMESA");
glad_glXQueryCurrentRendererStringMESA = (PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC) load(userptr, "glXQueryCurrentRendererStringMESA");
glad_glXQueryRendererIntegerMESA = (PFNGLXQUERYRENDERERINTEGERMESAPROC) load(userptr, "glXQueryRendererIntegerMESA");
glad_glXQueryRendererStringMESA = (PFNGLXQUERYRENDERERSTRINGMESAPROC) load(userptr, "glXQueryRendererStringMESA");
}
static void glad_glx_load_GLX_MESA_release_buffers( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_MESA_release_buffers) return;
glad_glXReleaseBuffersMESA = (PFNGLXRELEASEBUFFERSMESAPROC) load(userptr, "glXReleaseBuffersMESA");
}
static void glad_glx_load_GLX_MESA_set_3dfx_mode( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_MESA_set_3dfx_mode) return;
glad_glXSet3DfxModeMESA = (PFNGLXSET3DFXMODEMESAPROC) load(userptr, "glXSet3DfxModeMESA");
}
static void glad_glx_load_GLX_MESA_swap_control( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_MESA_swap_control) return;
glad_glXGetSwapIntervalMESA = (PFNGLXGETSWAPINTERVALMESAPROC) load(userptr, "glXGetSwapIntervalMESA");
glad_glXSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) load(userptr, "glXSwapIntervalMESA");
}
static void glad_glx_load_GLX_NV_copy_buffer( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_NV_copy_buffer) return;
glad_glXCopyBufferSubDataNV = (PFNGLXCOPYBUFFERSUBDATANVPROC) load(userptr, "glXCopyBufferSubDataNV");
glad_glXNamedCopyBufferSubDataNV = (PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC) load(userptr, "glXNamedCopyBufferSubDataNV");
}
static void glad_glx_load_GLX_NV_copy_image( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_NV_copy_image) return;
glad_glXCopyImageSubDataNV = (PFNGLXCOPYIMAGESUBDATANVPROC) load(userptr, "glXCopyImageSubDataNV");
}
static void glad_glx_load_GLX_NV_delay_before_swap( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_NV_delay_before_swap) return;
glad_glXDelayBeforeSwapNV = (PFNGLXDELAYBEFORESWAPNVPROC) load(userptr, "glXDelayBeforeSwapNV");
}
static void glad_glx_load_GLX_NV_present_video( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_NV_present_video) return;
glad_glXBindVideoDeviceNV = (PFNGLXBINDVIDEODEVICENVPROC) load(userptr, "glXBindVideoDeviceNV");
glad_glXEnumerateVideoDevicesNV = (PFNGLXENUMERATEVIDEODEVICESNVPROC) load(userptr, "glXEnumerateVideoDevicesNV");
}
static void glad_glx_load_GLX_NV_swap_group( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_NV_swap_group) return;
glad_glXBindSwapBarrierNV = (PFNGLXBINDSWAPBARRIERNVPROC) load(userptr, "glXBindSwapBarrierNV");
glad_glXJoinSwapGroupNV = (PFNGLXJOINSWAPGROUPNVPROC) load(userptr, "glXJoinSwapGroupNV");
glad_glXQueryFrameCountNV = (PFNGLXQUERYFRAMECOUNTNVPROC) load(userptr, "glXQueryFrameCountNV");
glad_glXQueryMaxSwapGroupsNV = (PFNGLXQUERYMAXSWAPGROUPSNVPROC) load(userptr, "glXQueryMaxSwapGroupsNV");
glad_glXQuerySwapGroupNV = (PFNGLXQUERYSWAPGROUPNVPROC) load(userptr, "glXQuerySwapGroupNV");
glad_glXResetFrameCountNV = (PFNGLXRESETFRAMECOUNTNVPROC) load(userptr, "glXResetFrameCountNV");
}
static void glad_glx_load_GLX_NV_video_capture( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_NV_video_capture) return;
glad_glXBindVideoCaptureDeviceNV = (PFNGLXBINDVIDEOCAPTUREDEVICENVPROC) load(userptr, "glXBindVideoCaptureDeviceNV");
glad_glXEnumerateVideoCaptureDevicesNV = (PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC) load(userptr, "glXEnumerateVideoCaptureDevicesNV");
glad_glXLockVideoCaptureDeviceNV = (PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC) load(userptr, "glXLockVideoCaptureDeviceNV");
glad_glXQueryVideoCaptureDeviceNV = (PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC) load(userptr, "glXQueryVideoCaptureDeviceNV");
glad_glXReleaseVideoCaptureDeviceNV = (PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) load(userptr, "glXReleaseVideoCaptureDeviceNV");
}
static void glad_glx_load_GLX_NV_video_out( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_NV_video_out) return;
glad_glXBindVideoImageNV = (PFNGLXBINDVIDEOIMAGENVPROC) load(userptr, "glXBindVideoImageNV");
glad_glXGetVideoDeviceNV = (PFNGLXGETVIDEODEVICENVPROC) load(userptr, "glXGetVideoDeviceNV");
glad_glXGetVideoInfoNV = (PFNGLXGETVIDEOINFONVPROC) load(userptr, "glXGetVideoInfoNV");
glad_glXReleaseVideoDeviceNV = (PFNGLXRELEASEVIDEODEVICENVPROC) load(userptr, "glXReleaseVideoDeviceNV");
glad_glXReleaseVideoImageNV = (PFNGLXRELEASEVIDEOIMAGENVPROC) load(userptr, "glXReleaseVideoImageNV");
glad_glXSendPbufferToVideoNV = (PFNGLXSENDPBUFFERTOVIDEONVPROC) load(userptr, "glXSendPbufferToVideoNV");
}
static void glad_glx_load_GLX_OML_sync_control( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_OML_sync_control) return;
glad_glXGetMscRateOML = (PFNGLXGETMSCRATEOMLPROC) load(userptr, "glXGetMscRateOML");
glad_glXGetSyncValuesOML = (PFNGLXGETSYNCVALUESOMLPROC) load(userptr, "glXGetSyncValuesOML");
glad_glXSwapBuffersMscOML = (PFNGLXSWAPBUFFERSMSCOMLPROC) load(userptr, "glXSwapBuffersMscOML");
glad_glXWaitForMscOML = (PFNGLXWAITFORMSCOMLPROC) load(userptr, "glXWaitForMscOML");
glad_glXWaitForSbcOML = (PFNGLXWAITFORSBCOMLPROC) load(userptr, "glXWaitForSbcOML");
}
static void glad_glx_load_GLX_SGIX_fbconfig( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_SGIX_fbconfig) return;
glad_glXChooseFBConfigSGIX = (PFNGLXCHOOSEFBCONFIGSGIXPROC) load(userptr, "glXChooseFBConfigSGIX");
glad_glXCreateContextWithConfigSGIX = (PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) load(userptr, "glXCreateContextWithConfigSGIX");
glad_glXCreateGLXPixmapWithConfigSGIX = (PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC) load(userptr, "glXCreateGLXPixmapWithConfigSGIX");
glad_glXGetFBConfigAttribSGIX = (PFNGLXGETFBCONFIGATTRIBSGIXPROC) load(userptr, "glXGetFBConfigAttribSGIX");
glad_glXGetFBConfigFromVisualSGIX = (PFNGLXGETFBCONFIGFROMVISUALSGIXPROC) load(userptr, "glXGetFBConfigFromVisualSGIX");
glad_glXGetVisualFromFBConfigSGIX = (PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) load(userptr, "glXGetVisualFromFBConfigSGIX");
}
static void glad_glx_load_GLX_SGIX_hyperpipe( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_SGIX_hyperpipe) return;
glad_glXBindHyperpipeSGIX = (PFNGLXBINDHYPERPIPESGIXPROC) load(userptr, "glXBindHyperpipeSGIX");
glad_glXDestroyHyperpipeConfigSGIX = (PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC) load(userptr, "glXDestroyHyperpipeConfigSGIX");
glad_glXHyperpipeAttribSGIX = (PFNGLXHYPERPIPEATTRIBSGIXPROC) load(userptr, "glXHyperpipeAttribSGIX");
glad_glXHyperpipeConfigSGIX = (PFNGLXHYPERPIPECONFIGSGIXPROC) load(userptr, "glXHyperpipeConfigSGIX");
glad_glXQueryHyperpipeAttribSGIX = (PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC) load(userptr, "glXQueryHyperpipeAttribSGIX");
glad_glXQueryHyperpipeBestAttribSGIX = (PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC) load(userptr, "glXQueryHyperpipeBestAttribSGIX");
glad_glXQueryHyperpipeConfigSGIX = (PFNGLXQUERYHYPERPIPECONFIGSGIXPROC) load(userptr, "glXQueryHyperpipeConfigSGIX");
glad_glXQueryHyperpipeNetworkSGIX = (PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) load(userptr, "glXQueryHyperpipeNetworkSGIX");
}
static void glad_glx_load_GLX_SGIX_pbuffer( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_SGIX_pbuffer) return;
glad_glXCreateGLXPbufferSGIX = (PFNGLXCREATEGLXPBUFFERSGIXPROC) load(userptr, "glXCreateGLXPbufferSGIX");
glad_glXDestroyGLXPbufferSGIX = (PFNGLXDESTROYGLXPBUFFERSGIXPROC) load(userptr, "glXDestroyGLXPbufferSGIX");
glad_glXGetSelectedEventSGIX = (PFNGLXGETSELECTEDEVENTSGIXPROC) load(userptr, "glXGetSelectedEventSGIX");
glad_glXQueryGLXPbufferSGIX = (PFNGLXQUERYGLXPBUFFERSGIXPROC) load(userptr, "glXQueryGLXPbufferSGIX");
glad_glXSelectEventSGIX = (PFNGLXSELECTEVENTSGIXPROC) load(userptr, "glXSelectEventSGIX");
}
static void glad_glx_load_GLX_SGIX_swap_barrier( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_SGIX_swap_barrier) return;
glad_glXBindSwapBarrierSGIX = (PFNGLXBINDSWAPBARRIERSGIXPROC) load(userptr, "glXBindSwapBarrierSGIX");
glad_glXQueryMaxSwapBarriersSGIX = (PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) load(userptr, "glXQueryMaxSwapBarriersSGIX");
}
static void glad_glx_load_GLX_SGIX_swap_group( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_SGIX_swap_group) return;
glad_glXJoinSwapGroupSGIX = (PFNGLXJOINSWAPGROUPSGIXPROC) load(userptr, "glXJoinSwapGroupSGIX");
}
static void glad_glx_load_GLX_SGIX_video_resize( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_SGIX_video_resize) return;
glad_glXBindChannelToWindowSGIX = (PFNGLXBINDCHANNELTOWINDOWSGIXPROC) load(userptr, "glXBindChannelToWindowSGIX");
glad_glXChannelRectSGIX = (PFNGLXCHANNELRECTSGIXPROC) load(userptr, "glXChannelRectSGIX");
glad_glXChannelRectSyncSGIX = (PFNGLXCHANNELRECTSYNCSGIXPROC) load(userptr, "glXChannelRectSyncSGIX");
glad_glXQueryChannelDeltasSGIX = (PFNGLXQUERYCHANNELDELTASSGIXPROC) load(userptr, "glXQueryChannelDeltasSGIX");
glad_glXQueryChannelRectSGIX = (PFNGLXQUERYCHANNELRECTSGIXPROC) load(userptr, "glXQueryChannelRectSGIX");
}
static void glad_glx_load_GLX_SGI_cushion( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_SGI_cushion) return;
glad_glXCushionSGI = (PFNGLXCUSHIONSGIPROC) load(userptr, "glXCushionSGI");
}
static void glad_glx_load_GLX_SGI_make_current_read( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_SGI_make_current_read) return;
glad_glXGetCurrentReadDrawableSGI = (PFNGLXGETCURRENTREADDRAWABLESGIPROC) load(userptr, "glXGetCurrentReadDrawableSGI");
glad_glXMakeCurrentReadSGI = (PFNGLXMAKECURRENTREADSGIPROC) load(userptr, "glXMakeCurrentReadSGI");
}
static void glad_glx_load_GLX_SGI_swap_control( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_SGI_swap_control) return;
glad_glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) load(userptr, "glXSwapIntervalSGI");
}
static void glad_glx_load_GLX_SGI_video_sync( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_SGI_video_sync) return;
glad_glXGetVideoSyncSGI = (PFNGLXGETVIDEOSYNCSGIPROC) load(userptr, "glXGetVideoSyncSGI");
glad_glXWaitVideoSyncSGI = (PFNGLXWAITVIDEOSYNCSGIPROC) load(userptr, "glXWaitVideoSyncSGI");
}
static void glad_glx_load_GLX_SUN_get_transparent_index( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GLX_SUN_get_transparent_index) return;
glad_glXGetTransparentIndexSUN = (PFNGLXGETTRANSPARENTINDEXSUNPROC) load(userptr, "glXGetTransparentIndexSUN");
}
static void glad_glx_resolve_aliases(void) {
}
static int glad_glx_has_extension(Display *display, int screen, const char *ext) {
#ifndef GLX_VERSION_1_1
GLAD_UNUSED(display);
GLAD_UNUSED(screen);
GLAD_UNUSED(ext);
#else
const char *terminator;
const char *loc;
const char *extensions;
if (glXQueryExtensionsString == NULL) {
return 0;
}
extensions = glXQueryExtensionsString(display, screen);
if(extensions == NULL || ext == NULL) {
return 0;
}
while(1) {
loc = strstr(extensions, ext);
if(loc == NULL)
break;
terminator = loc + strlen(ext);
if((loc == extensions || *(loc - 1) == ' ') &&
(*terminator == ' ' || *terminator == '\0')) {
return 1;
}
extensions = terminator;
}
#endif
return 0;
}
static GLADapiproc glad_glx_get_proc_from_userptr(void *userptr, const char* name) {
return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);
}
static int glad_glx_find_extensions(Display *display, int screen) {
GLAD_GLX_3DFX_multisample = glad_glx_has_extension(display, screen, "GLX_3DFX_multisample");
GLAD_GLX_AMD_gpu_association = glad_glx_has_extension(display, screen, "GLX_AMD_gpu_association");
GLAD_GLX_ARB_context_flush_control = glad_glx_has_extension(display, screen, "GLX_ARB_context_flush_control");
GLAD_GLX_ARB_create_context = glad_glx_has_extension(display, screen, "GLX_ARB_create_context");
GLAD_GLX_ARB_create_context_no_error = glad_glx_has_extension(display, screen, "GLX_ARB_create_context_no_error");
GLAD_GLX_ARB_create_context_profile = glad_glx_has_extension(display, screen, "GLX_ARB_create_context_profile");
GLAD_GLX_ARB_create_context_robustness = glad_glx_has_extension(display, screen, "GLX_ARB_create_context_robustness");
GLAD_GLX_ARB_fbconfig_float = glad_glx_has_extension(display, screen, "GLX_ARB_fbconfig_float");
GLAD_GLX_ARB_framebuffer_sRGB = glad_glx_has_extension(display, screen, "GLX_ARB_framebuffer_sRGB");
GLAD_GLX_ARB_get_proc_address = glad_glx_has_extension(display, screen, "GLX_ARB_get_proc_address");
GLAD_GLX_ARB_multisample = glad_glx_has_extension(display, screen, "GLX_ARB_multisample");
GLAD_GLX_ARB_robustness_application_isolation = glad_glx_has_extension(display, screen, "GLX_ARB_robustness_application_isolation");
GLAD_GLX_ARB_robustness_share_group_isolation = glad_glx_has_extension(display, screen, "GLX_ARB_robustness_share_group_isolation");
GLAD_GLX_ARB_vertex_buffer_object = glad_glx_has_extension(display, screen, "GLX_ARB_vertex_buffer_object");
GLAD_GLX_EXT_buffer_age = glad_glx_has_extension(display, screen, "GLX_EXT_buffer_age");
GLAD_GLX_EXT_context_priority = glad_glx_has_extension(display, screen, "GLX_EXT_context_priority");
GLAD_GLX_EXT_create_context_es2_profile = glad_glx_has_extension(display, screen, "GLX_EXT_create_context_es2_profile");
GLAD_GLX_EXT_create_context_es_profile = glad_glx_has_extension(display, screen, "GLX_EXT_create_context_es_profile");
GLAD_GLX_EXT_fbconfig_packed_float = glad_glx_has_extension(display, screen, "GLX_EXT_fbconfig_packed_float");
GLAD_GLX_EXT_framebuffer_sRGB = glad_glx_has_extension(display, screen, "GLX_EXT_framebuffer_sRGB");
GLAD_GLX_EXT_get_drawable_type = glad_glx_has_extension(display, screen, "GLX_EXT_get_drawable_type");
GLAD_GLX_EXT_import_context = glad_glx_has_extension(display, screen, "GLX_EXT_import_context");
GLAD_GLX_EXT_libglvnd = glad_glx_has_extension(display, screen, "GLX_EXT_libglvnd");
GLAD_GLX_EXT_no_config_context = glad_glx_has_extension(display, screen, "GLX_EXT_no_config_context");
GLAD_GLX_EXT_stereo_tree = glad_glx_has_extension(display, screen, "GLX_EXT_stereo_tree");
GLAD_GLX_EXT_swap_control = glad_glx_has_extension(display, screen, "GLX_EXT_swap_control");
GLAD_GLX_EXT_swap_control_tear = glad_glx_has_extension(display, screen, "GLX_EXT_swap_control_tear");
GLAD_GLX_EXT_texture_from_pixmap = glad_glx_has_extension(display, screen, "GLX_EXT_texture_from_pixmap");
GLAD_GLX_EXT_visual_info = glad_glx_has_extension(display, screen, "GLX_EXT_visual_info");
GLAD_GLX_EXT_visual_rating = glad_glx_has_extension(display, screen, "GLX_EXT_visual_rating");
GLAD_GLX_INTEL_swap_event = glad_glx_has_extension(display, screen, "GLX_INTEL_swap_event");
GLAD_GLX_MESA_agp_offset = glad_glx_has_extension(display, screen, "GLX_MESA_agp_offset");
GLAD_GLX_MESA_copy_sub_buffer = glad_glx_has_extension(display, screen, "GLX_MESA_copy_sub_buffer");
GLAD_GLX_MESA_pixmap_colormap = glad_glx_has_extension(display, screen, "GLX_MESA_pixmap_colormap");
GLAD_GLX_MESA_query_renderer = glad_glx_has_extension(display, screen, "GLX_MESA_query_renderer");
GLAD_GLX_MESA_release_buffers = glad_glx_has_extension(display, screen, "GLX_MESA_release_buffers");
GLAD_GLX_MESA_set_3dfx_mode = glad_glx_has_extension(display, screen, "GLX_MESA_set_3dfx_mode");
GLAD_GLX_MESA_swap_control = glad_glx_has_extension(display, screen, "GLX_MESA_swap_control");
GLAD_GLX_NV_copy_buffer = glad_glx_has_extension(display, screen, "GLX_NV_copy_buffer");
GLAD_GLX_NV_copy_image = glad_glx_has_extension(display, screen, "GLX_NV_copy_image");
GLAD_GLX_NV_delay_before_swap = glad_glx_has_extension(display, screen, "GLX_NV_delay_before_swap");
GLAD_GLX_NV_float_buffer = glad_glx_has_extension(display, screen, "GLX_NV_float_buffer");
GLAD_GLX_NV_multigpu_context = glad_glx_has_extension(display, screen, "GLX_NV_multigpu_context");
GLAD_GLX_NV_multisample_coverage = glad_glx_has_extension(display, screen, "GLX_NV_multisample_coverage");
GLAD_GLX_NV_present_video = glad_glx_has_extension(display, screen, "GLX_NV_present_video");
GLAD_GLX_NV_robustness_video_memory_purge = glad_glx_has_extension(display, screen, "GLX_NV_robustness_video_memory_purge");
GLAD_GLX_NV_swap_group = glad_glx_has_extension(display, screen, "GLX_NV_swap_group");
GLAD_GLX_NV_video_capture = glad_glx_has_extension(display, screen, "GLX_NV_video_capture");
GLAD_GLX_NV_video_out = glad_glx_has_extension(display, screen, "GLX_NV_video_out");
GLAD_GLX_OML_swap_method = glad_glx_has_extension(display, screen, "GLX_OML_swap_method");
GLAD_GLX_OML_sync_control = glad_glx_has_extension(display, screen, "GLX_OML_sync_control");
GLAD_GLX_SGIS_blended_overlay = glad_glx_has_extension(display, screen, "GLX_SGIS_blended_overlay");
GLAD_GLX_SGIS_multisample = glad_glx_has_extension(display, screen, "GLX_SGIS_multisample");
GLAD_GLX_SGIS_shared_multisample = glad_glx_has_extension(display, screen, "GLX_SGIS_shared_multisample");
GLAD_GLX_SGIX_fbconfig = glad_glx_has_extension(display, screen, "GLX_SGIX_fbconfig");
GLAD_GLX_SGIX_hyperpipe = glad_glx_has_extension(display, screen, "GLX_SGIX_hyperpipe");
GLAD_GLX_SGIX_pbuffer = glad_glx_has_extension(display, screen, "GLX_SGIX_pbuffer");
GLAD_GLX_SGIX_swap_barrier = glad_glx_has_extension(display, screen, "GLX_SGIX_swap_barrier");
GLAD_GLX_SGIX_swap_group = glad_glx_has_extension(display, screen, "GLX_SGIX_swap_group");
GLAD_GLX_SGIX_video_resize = glad_glx_has_extension(display, screen, "GLX_SGIX_video_resize");
GLAD_GLX_SGIX_visual_select_group = glad_glx_has_extension(display, screen, "GLX_SGIX_visual_select_group");
GLAD_GLX_SGI_cushion = glad_glx_has_extension(display, screen, "GLX_SGI_cushion");
GLAD_GLX_SGI_make_current_read = glad_glx_has_extension(display, screen, "GLX_SGI_make_current_read");
GLAD_GLX_SGI_swap_control = glad_glx_has_extension(display, screen, "GLX_SGI_swap_control");
GLAD_GLX_SGI_video_sync = glad_glx_has_extension(display, screen, "GLX_SGI_video_sync");
GLAD_GLX_SUN_get_transparent_index = glad_glx_has_extension(display, screen, "GLX_SUN_get_transparent_index");
return 1;
}
static int glad_glx_find_core_glx(Display **display, int *screen) {
int major = 0, minor = 0;
if(*display == NULL) {
#ifdef GLAD_GLX_NO_X11
GLAD_UNUSED(screen);
return 0;
#else
*display = XOpenDisplay(0);
if (*display == NULL) {
return 0;
}
*screen = XScreenNumberOfScreen(XDefaultScreenOfDisplay(*display));
#endif
}
glXQueryVersion(*display, &major, &minor);
GLAD_GLX_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
GLAD_GLX_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
GLAD_GLX_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;
GLAD_GLX_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;
GLAD_GLX_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;
return GLAD_MAKE_VERSION(major, minor);
}
int gladLoadGLXUserPtr(Display *display, int screen, GLADuserptrloadfunc load, void *userptr) {
int version;
glXQueryVersion = (PFNGLXQUERYVERSIONPROC) load(userptr, "glXQueryVersion");
if(glXQueryVersion == NULL) return 0;
version = glad_glx_find_core_glx(&display, &screen);
glad_glx_load_GLX_VERSION_1_0(load, userptr);
glad_glx_load_GLX_VERSION_1_1(load, userptr);
glad_glx_load_GLX_VERSION_1_2(load, userptr);
glad_glx_load_GLX_VERSION_1_3(load, userptr);
glad_glx_load_GLX_VERSION_1_4(load, userptr);
if (!glad_glx_find_extensions(display, screen)) return 0;
glad_glx_load_GLX_AMD_gpu_association(load, userptr);
glad_glx_load_GLX_ARB_create_context(load, userptr);
glad_glx_load_GLX_ARB_get_proc_address(load, userptr);
glad_glx_load_GLX_EXT_import_context(load, userptr);
glad_glx_load_GLX_EXT_swap_control(load, userptr);
glad_glx_load_GLX_EXT_texture_from_pixmap(load, userptr);
glad_glx_load_GLX_MESA_agp_offset(load, userptr);
glad_glx_load_GLX_MESA_copy_sub_buffer(load, userptr);
glad_glx_load_GLX_MESA_pixmap_colormap(load, userptr);
glad_glx_load_GLX_MESA_query_renderer(load, userptr);
glad_glx_load_GLX_MESA_release_buffers(load, userptr);
glad_glx_load_GLX_MESA_set_3dfx_mode(load, userptr);
glad_glx_load_GLX_MESA_swap_control(load, userptr);
glad_glx_load_GLX_NV_copy_buffer(load, userptr);
glad_glx_load_GLX_NV_copy_image(load, userptr);
glad_glx_load_GLX_NV_delay_before_swap(load, userptr);
glad_glx_load_GLX_NV_present_video(load, userptr);
glad_glx_load_GLX_NV_swap_group(load, userptr);
glad_glx_load_GLX_NV_video_capture(load, userptr);
glad_glx_load_GLX_NV_video_out(load, userptr);
glad_glx_load_GLX_OML_sync_control(load, userptr);
glad_glx_load_GLX_SGIX_fbconfig(load, userptr);
glad_glx_load_GLX_SGIX_hyperpipe(load, userptr);
glad_glx_load_GLX_SGIX_pbuffer(load, userptr);
glad_glx_load_GLX_SGIX_swap_barrier(load, userptr);
glad_glx_load_GLX_SGIX_swap_group(load, userptr);
glad_glx_load_GLX_SGIX_video_resize(load, userptr);
glad_glx_load_GLX_SGI_cushion(load, userptr);
glad_glx_load_GLX_SGI_make_current_read(load, userptr);
glad_glx_load_GLX_SGI_swap_control(load, userptr);
glad_glx_load_GLX_SGI_video_sync(load, userptr);
glad_glx_load_GLX_SUN_get_transparent_index(load, userptr);
glad_glx_resolve_aliases();
return version;
}
int gladLoadGLX(Display *display, int screen, GLADloadfunc load) {
return gladLoadGLXUserPtr(display, screen, glad_glx_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
}
#ifdef GLAD_GLX
#ifndef GLAD_LOADER_LIBRARY_C_
#define GLAD_LOADER_LIBRARY_C_
#include <stddef.h>
#include <stdlib.h>
#if GLAD_PLATFORM_WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
static void* glad_get_dlopen_handle(const char *lib_names[], int length) {
void *handle = NULL;
int i;
for (i = 0; i < length; ++i) {
#if GLAD_PLATFORM_WIN32
#if GLAD_PLATFORM_UWP
size_t buffer_size = (strlen(lib_names[i]) + 1) * sizeof(WCHAR);
LPWSTR buffer = (LPWSTR) malloc(buffer_size);
if (buffer != NULL) {
int ret = MultiByteToWideChar(CP_ACP, 0, lib_names[i], -1, buffer, buffer_size);
if (ret != 0) {
handle = (void*) LoadPackagedLibrary(buffer, 0);
}
free((void*) buffer);
}
#else
handle = (void*) LoadLibraryA(lib_names[i]);
#endif
#else
handle = dlopen(lib_names[i], RTLD_LAZY | RTLD_LOCAL);
#endif
if (handle != NULL) {
return handle;
}
}
return NULL;
}
static void glad_close_dlopen_handle(void* handle) {
if (handle != NULL) {
#if GLAD_PLATFORM_WIN32
FreeLibrary((HMODULE) handle);
#else
dlclose(handle);
#endif
}
}
static GLADapiproc glad_dlsym_handle(void* handle, const char *name) {
if (handle == NULL) {
return NULL;
}
#if GLAD_PLATFORM_WIN32
return (GLADapiproc) GetProcAddress((HMODULE) handle, name);
#else
return GLAD_GNUC_EXTENSION (GLADapiproc) dlsym(handle, name);
#endif
}
#endif /* GLAD_LOADER_LIBRARY_C_ */
typedef void* (GLAD_API_PTR *GLADglxprocaddrfunc)(const char*);
static GLADapiproc glad_glx_get_proc(void *userptr, const char *name) {
return GLAD_GNUC_EXTENSION ((GLADapiproc (*)(const char *name)) userptr)(name);
}
static void* _glx_handle;
static void* glad_glx_dlopen_handle(void) {
static const char *NAMES[] = {
#if defined __CYGWIN__
"libGL-1.so",
#endif
"libGL.so.1",
"libGL.so"
};
if (_glx_handle == NULL) {
_glx_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));
}
return _glx_handle;
}
int gladLoaderLoadGLX(Display *display, int screen) {
int version = 0;
void *handle = NULL;
int did_load = 0;
GLADglxprocaddrfunc loader;
did_load = _glx_handle == NULL;
handle = glad_glx_dlopen_handle();
if (handle != NULL) {
loader = (GLADglxprocaddrfunc) glad_dlsym_handle(handle, "glXGetProcAddressARB");
if (loader != NULL) {
version = gladLoadGLXUserPtr(display, screen, glad_glx_get_proc, GLAD_GNUC_EXTENSION (void*) loader);
}
if (!version && did_load) {
gladLoaderUnloadGLX();
}
}
return version;
}
void gladLoaderUnloadGLX() {
if (_glx_handle != NULL) {
glad_close_dlopen_handle(_glx_handle);
_glx_handle = NULL;
}
}
#endif /* GLAD_GLX */
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,596 @@
/**
* SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glad/wgl.h>
#ifndef GLAD_IMPL_UTIL_C_
#define GLAD_IMPL_UTIL_C_
#ifdef _MSC_VER
#define GLAD_IMPL_UTIL_SSCANF sscanf_s
#else
#define GLAD_IMPL_UTIL_SSCANF sscanf
#endif
#endif /* GLAD_IMPL_UTIL_C_ */
#ifdef __cplusplus
extern "C" {
#endif
int GLAD_WGL_VERSION_1_0 = 0;
int GLAD_WGL_3DFX_multisample = 0;
int GLAD_WGL_3DL_stereo_control = 0;
int GLAD_WGL_AMD_gpu_association = 0;
int GLAD_WGL_ARB_buffer_region = 0;
int GLAD_WGL_ARB_context_flush_control = 0;
int GLAD_WGL_ARB_create_context = 0;
int GLAD_WGL_ARB_create_context_no_error = 0;
int GLAD_WGL_ARB_create_context_profile = 0;
int GLAD_WGL_ARB_create_context_robustness = 0;
int GLAD_WGL_ARB_extensions_string = 0;
int GLAD_WGL_ARB_framebuffer_sRGB = 0;
int GLAD_WGL_ARB_make_current_read = 0;
int GLAD_WGL_ARB_multisample = 0;
int GLAD_WGL_ARB_pbuffer = 0;
int GLAD_WGL_ARB_pixel_format = 0;
int GLAD_WGL_ARB_pixel_format_float = 0;
int GLAD_WGL_ARB_render_texture = 0;
int GLAD_WGL_ARB_robustness_application_isolation = 0;
int GLAD_WGL_ARB_robustness_share_group_isolation = 0;
int GLAD_WGL_ATI_pixel_format_float = 0;
int GLAD_WGL_ATI_render_texture_rectangle = 0;
int GLAD_WGL_EXT_colorspace = 0;
int GLAD_WGL_EXT_create_context_es2_profile = 0;
int GLAD_WGL_EXT_create_context_es_profile = 0;
int GLAD_WGL_EXT_depth_float = 0;
int GLAD_WGL_EXT_display_color_table = 0;
int GLAD_WGL_EXT_extensions_string = 0;
int GLAD_WGL_EXT_framebuffer_sRGB = 0;
int GLAD_WGL_EXT_make_current_read = 0;
int GLAD_WGL_EXT_multisample = 0;
int GLAD_WGL_EXT_pbuffer = 0;
int GLAD_WGL_EXT_pixel_format = 0;
int GLAD_WGL_EXT_pixel_format_packed_float = 0;
int GLAD_WGL_EXT_swap_control = 0;
int GLAD_WGL_EXT_swap_control_tear = 0;
int GLAD_WGL_I3D_digital_video_control = 0;
int GLAD_WGL_I3D_gamma = 0;
int GLAD_WGL_I3D_genlock = 0;
int GLAD_WGL_I3D_image_buffer = 0;
int GLAD_WGL_I3D_swap_frame_lock = 0;
int GLAD_WGL_I3D_swap_frame_usage = 0;
int GLAD_WGL_NV_DX_interop = 0;
int GLAD_WGL_NV_DX_interop2 = 0;
int GLAD_WGL_NV_copy_image = 0;
int GLAD_WGL_NV_delay_before_swap = 0;
int GLAD_WGL_NV_float_buffer = 0;
int GLAD_WGL_NV_gpu_affinity = 0;
int GLAD_WGL_NV_multigpu_context = 0;
int GLAD_WGL_NV_multisample_coverage = 0;
int GLAD_WGL_NV_present_video = 0;
int GLAD_WGL_NV_render_depth_texture = 0;
int GLAD_WGL_NV_render_texture_rectangle = 0;
int GLAD_WGL_NV_swap_group = 0;
int GLAD_WGL_NV_vertex_array_range = 0;
int GLAD_WGL_NV_video_capture = 0;
int GLAD_WGL_NV_video_output = 0;
int GLAD_WGL_OML_sync_control = 0;
PFNWGLALLOCATEMEMORYNVPROC glad_wglAllocateMemoryNV = NULL;
PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC glad_wglAssociateImageBufferEventsI3D = NULL;
PFNWGLBEGINFRAMETRACKINGI3DPROC glad_wglBeginFrameTrackingI3D = NULL;
PFNWGLBINDDISPLAYCOLORTABLEEXTPROC glad_wglBindDisplayColorTableEXT = NULL;
PFNWGLBINDSWAPBARRIERNVPROC glad_wglBindSwapBarrierNV = NULL;
PFNWGLBINDTEXIMAGEARBPROC glad_wglBindTexImageARB = NULL;
PFNWGLBINDVIDEOCAPTUREDEVICENVPROC glad_wglBindVideoCaptureDeviceNV = NULL;
PFNWGLBINDVIDEODEVICENVPROC glad_wglBindVideoDeviceNV = NULL;
PFNWGLBINDVIDEOIMAGENVPROC glad_wglBindVideoImageNV = NULL;
PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC glad_wglBlitContextFramebufferAMD = NULL;
PFNWGLCHOOSEPIXELFORMATARBPROC glad_wglChoosePixelFormatARB = NULL;
PFNWGLCHOOSEPIXELFORMATEXTPROC glad_wglChoosePixelFormatEXT = NULL;
PFNWGLCOPYIMAGESUBDATANVPROC glad_wglCopyImageSubDataNV = NULL;
PFNWGLCREATEAFFINITYDCNVPROC glad_wglCreateAffinityDCNV = NULL;
PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC glad_wglCreateAssociatedContextAMD = NULL;
PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC glad_wglCreateAssociatedContextAttribsAMD = NULL;
PFNWGLCREATEBUFFERREGIONARBPROC glad_wglCreateBufferRegionARB = NULL;
PFNWGLCREATECONTEXTATTRIBSARBPROC glad_wglCreateContextAttribsARB = NULL;
PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC glad_wglCreateDisplayColorTableEXT = NULL;
PFNWGLCREATEIMAGEBUFFERI3DPROC glad_wglCreateImageBufferI3D = NULL;
PFNWGLCREATEPBUFFERARBPROC glad_wglCreatePbufferARB = NULL;
PFNWGLCREATEPBUFFEREXTPROC glad_wglCreatePbufferEXT = NULL;
PFNWGLDXCLOSEDEVICENVPROC glad_wglDXCloseDeviceNV = NULL;
PFNWGLDXLOCKOBJECTSNVPROC glad_wglDXLockObjectsNV = NULL;
PFNWGLDXOBJECTACCESSNVPROC glad_wglDXObjectAccessNV = NULL;
PFNWGLDXOPENDEVICENVPROC glad_wglDXOpenDeviceNV = NULL;
PFNWGLDXREGISTEROBJECTNVPROC glad_wglDXRegisterObjectNV = NULL;
PFNWGLDXSETRESOURCESHAREHANDLENVPROC glad_wglDXSetResourceShareHandleNV = NULL;
PFNWGLDXUNLOCKOBJECTSNVPROC glad_wglDXUnlockObjectsNV = NULL;
PFNWGLDXUNREGISTEROBJECTNVPROC glad_wglDXUnregisterObjectNV = NULL;
PFNWGLDELAYBEFORESWAPNVPROC glad_wglDelayBeforeSwapNV = NULL;
PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC glad_wglDeleteAssociatedContextAMD = NULL;
PFNWGLDELETEBUFFERREGIONARBPROC glad_wglDeleteBufferRegionARB = NULL;
PFNWGLDELETEDCNVPROC glad_wglDeleteDCNV = NULL;
PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC glad_wglDestroyDisplayColorTableEXT = NULL;
PFNWGLDESTROYIMAGEBUFFERI3DPROC glad_wglDestroyImageBufferI3D = NULL;
PFNWGLDESTROYPBUFFERARBPROC glad_wglDestroyPbufferARB = NULL;
PFNWGLDESTROYPBUFFEREXTPROC glad_wglDestroyPbufferEXT = NULL;
PFNWGLDISABLEFRAMELOCKI3DPROC glad_wglDisableFrameLockI3D = NULL;
PFNWGLDISABLEGENLOCKI3DPROC glad_wglDisableGenlockI3D = NULL;
PFNWGLENABLEFRAMELOCKI3DPROC glad_wglEnableFrameLockI3D = NULL;
PFNWGLENABLEGENLOCKI3DPROC glad_wglEnableGenlockI3D = NULL;
PFNWGLENDFRAMETRACKINGI3DPROC glad_wglEndFrameTrackingI3D = NULL;
PFNWGLENUMGPUDEVICESNVPROC glad_wglEnumGpuDevicesNV = NULL;
PFNWGLENUMGPUSFROMAFFINITYDCNVPROC glad_wglEnumGpusFromAffinityDCNV = NULL;
PFNWGLENUMGPUSNVPROC glad_wglEnumGpusNV = NULL;
PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC glad_wglEnumerateVideoCaptureDevicesNV = NULL;
PFNWGLENUMERATEVIDEODEVICESNVPROC glad_wglEnumerateVideoDevicesNV = NULL;
PFNWGLFREEMEMORYNVPROC glad_wglFreeMemoryNV = NULL;
PFNWGLGENLOCKSAMPLERATEI3DPROC glad_wglGenlockSampleRateI3D = NULL;
PFNWGLGENLOCKSOURCEDELAYI3DPROC glad_wglGenlockSourceDelayI3D = NULL;
PFNWGLGENLOCKSOURCEEDGEI3DPROC glad_wglGenlockSourceEdgeI3D = NULL;
PFNWGLGENLOCKSOURCEI3DPROC glad_wglGenlockSourceI3D = NULL;
PFNWGLGETCONTEXTGPUIDAMDPROC glad_wglGetContextGPUIDAMD = NULL;
PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC glad_wglGetCurrentAssociatedContextAMD = NULL;
PFNWGLGETCURRENTREADDCARBPROC glad_wglGetCurrentReadDCARB = NULL;
PFNWGLGETCURRENTREADDCEXTPROC glad_wglGetCurrentReadDCEXT = NULL;
PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC glad_wglGetDigitalVideoParametersI3D = NULL;
PFNWGLGETEXTENSIONSSTRINGARBPROC glad_wglGetExtensionsStringARB = NULL;
PFNWGLGETEXTENSIONSSTRINGEXTPROC glad_wglGetExtensionsStringEXT = NULL;
PFNWGLGETFRAMEUSAGEI3DPROC glad_wglGetFrameUsageI3D = NULL;
PFNWGLGETGPUIDSAMDPROC glad_wglGetGPUIDsAMD = NULL;
PFNWGLGETGPUINFOAMDPROC glad_wglGetGPUInfoAMD = NULL;
PFNWGLGETGAMMATABLEI3DPROC glad_wglGetGammaTableI3D = NULL;
PFNWGLGETGAMMATABLEPARAMETERSI3DPROC glad_wglGetGammaTableParametersI3D = NULL;
PFNWGLGETGENLOCKSAMPLERATEI3DPROC glad_wglGetGenlockSampleRateI3D = NULL;
PFNWGLGETGENLOCKSOURCEDELAYI3DPROC glad_wglGetGenlockSourceDelayI3D = NULL;
PFNWGLGETGENLOCKSOURCEEDGEI3DPROC glad_wglGetGenlockSourceEdgeI3D = NULL;
PFNWGLGETGENLOCKSOURCEI3DPROC glad_wglGetGenlockSourceI3D = NULL;
PFNWGLGETMSCRATEOMLPROC glad_wglGetMscRateOML = NULL;
PFNWGLGETPBUFFERDCARBPROC glad_wglGetPbufferDCARB = NULL;
PFNWGLGETPBUFFERDCEXTPROC glad_wglGetPbufferDCEXT = NULL;
PFNWGLGETPIXELFORMATATTRIBFVARBPROC glad_wglGetPixelFormatAttribfvARB = NULL;
PFNWGLGETPIXELFORMATATTRIBFVEXTPROC glad_wglGetPixelFormatAttribfvEXT = NULL;
PFNWGLGETPIXELFORMATATTRIBIVARBPROC glad_wglGetPixelFormatAttribivARB = NULL;
PFNWGLGETPIXELFORMATATTRIBIVEXTPROC glad_wglGetPixelFormatAttribivEXT = NULL;
PFNWGLGETSWAPINTERVALEXTPROC glad_wglGetSwapIntervalEXT = NULL;
PFNWGLGETSYNCVALUESOMLPROC glad_wglGetSyncValuesOML = NULL;
PFNWGLGETVIDEODEVICENVPROC glad_wglGetVideoDeviceNV = NULL;
PFNWGLGETVIDEOINFONVPROC glad_wglGetVideoInfoNV = NULL;
PFNWGLISENABLEDFRAMELOCKI3DPROC glad_wglIsEnabledFrameLockI3D = NULL;
PFNWGLISENABLEDGENLOCKI3DPROC glad_wglIsEnabledGenlockI3D = NULL;
PFNWGLJOINSWAPGROUPNVPROC glad_wglJoinSwapGroupNV = NULL;
PFNWGLLOADDISPLAYCOLORTABLEEXTPROC glad_wglLoadDisplayColorTableEXT = NULL;
PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC glad_wglLockVideoCaptureDeviceNV = NULL;
PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC glad_wglMakeAssociatedContextCurrentAMD = NULL;
PFNWGLMAKECONTEXTCURRENTARBPROC glad_wglMakeContextCurrentARB = NULL;
PFNWGLMAKECONTEXTCURRENTEXTPROC glad_wglMakeContextCurrentEXT = NULL;
PFNWGLQUERYCURRENTCONTEXTNVPROC glad_wglQueryCurrentContextNV = NULL;
PFNWGLQUERYFRAMECOUNTNVPROC glad_wglQueryFrameCountNV = NULL;
PFNWGLQUERYFRAMELOCKMASTERI3DPROC glad_wglQueryFrameLockMasterI3D = NULL;
PFNWGLQUERYFRAMETRACKINGI3DPROC glad_wglQueryFrameTrackingI3D = NULL;
PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC glad_wglQueryGenlockMaxSourceDelayI3D = NULL;
PFNWGLQUERYMAXSWAPGROUPSNVPROC glad_wglQueryMaxSwapGroupsNV = NULL;
PFNWGLQUERYPBUFFERARBPROC glad_wglQueryPbufferARB = NULL;
PFNWGLQUERYPBUFFEREXTPROC glad_wglQueryPbufferEXT = NULL;
PFNWGLQUERYSWAPGROUPNVPROC glad_wglQuerySwapGroupNV = NULL;
PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC glad_wglQueryVideoCaptureDeviceNV = NULL;
PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC glad_wglReleaseImageBufferEventsI3D = NULL;
PFNWGLRELEASEPBUFFERDCARBPROC glad_wglReleasePbufferDCARB = NULL;
PFNWGLRELEASEPBUFFERDCEXTPROC glad_wglReleasePbufferDCEXT = NULL;
PFNWGLRELEASETEXIMAGEARBPROC glad_wglReleaseTexImageARB = NULL;
PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC glad_wglReleaseVideoCaptureDeviceNV = NULL;
PFNWGLRELEASEVIDEODEVICENVPROC glad_wglReleaseVideoDeviceNV = NULL;
PFNWGLRELEASEVIDEOIMAGENVPROC glad_wglReleaseVideoImageNV = NULL;
PFNWGLRESETFRAMECOUNTNVPROC glad_wglResetFrameCountNV = NULL;
PFNWGLRESTOREBUFFERREGIONARBPROC glad_wglRestoreBufferRegionARB = NULL;
PFNWGLSAVEBUFFERREGIONARBPROC glad_wglSaveBufferRegionARB = NULL;
PFNWGLSENDPBUFFERTOVIDEONVPROC glad_wglSendPbufferToVideoNV = NULL;
PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC glad_wglSetDigitalVideoParametersI3D = NULL;
PFNWGLSETGAMMATABLEI3DPROC glad_wglSetGammaTableI3D = NULL;
PFNWGLSETGAMMATABLEPARAMETERSI3DPROC glad_wglSetGammaTableParametersI3D = NULL;
PFNWGLSETPBUFFERATTRIBARBPROC glad_wglSetPbufferAttribARB = NULL;
PFNWGLSETSTEREOEMITTERSTATE3DLPROC glad_wglSetStereoEmitterState3DL = NULL;
PFNWGLSWAPBUFFERSMSCOMLPROC glad_wglSwapBuffersMscOML = NULL;
PFNWGLSWAPINTERVALEXTPROC glad_wglSwapIntervalEXT = NULL;
PFNWGLSWAPLAYERBUFFERSMSCOMLPROC glad_wglSwapLayerBuffersMscOML = NULL;
PFNWGLWAITFORMSCOMLPROC glad_wglWaitForMscOML = NULL;
PFNWGLWAITFORSBCOMLPROC glad_wglWaitForSbcOML = NULL;
static void glad_wgl_load_WGL_3DL_stereo_control(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_3DL_stereo_control) return;
glad_wglSetStereoEmitterState3DL = (PFNWGLSETSTEREOEMITTERSTATE3DLPROC) load(userptr, "wglSetStereoEmitterState3DL");
}
static void glad_wgl_load_WGL_AMD_gpu_association(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_AMD_gpu_association) return;
glad_wglBlitContextFramebufferAMD = (PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) load(userptr, "wglBlitContextFramebufferAMD");
glad_wglCreateAssociatedContextAMD = (PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) load(userptr, "wglCreateAssociatedContextAMD");
glad_wglCreateAssociatedContextAttribsAMD = (PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) load(userptr, "wglCreateAssociatedContextAttribsAMD");
glad_wglDeleteAssociatedContextAMD = (PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC) load(userptr, "wglDeleteAssociatedContextAMD");
glad_wglGetContextGPUIDAMD = (PFNWGLGETCONTEXTGPUIDAMDPROC) load(userptr, "wglGetContextGPUIDAMD");
glad_wglGetCurrentAssociatedContextAMD = (PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC) load(userptr, "wglGetCurrentAssociatedContextAMD");
glad_wglGetGPUIDsAMD = (PFNWGLGETGPUIDSAMDPROC) load(userptr, "wglGetGPUIDsAMD");
glad_wglGetGPUInfoAMD = (PFNWGLGETGPUINFOAMDPROC) load(userptr, "wglGetGPUInfoAMD");
glad_wglMakeAssociatedContextCurrentAMD = (PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) load(userptr, "wglMakeAssociatedContextCurrentAMD");
}
static void glad_wgl_load_WGL_ARB_buffer_region(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_ARB_buffer_region) return;
glad_wglCreateBufferRegionARB = (PFNWGLCREATEBUFFERREGIONARBPROC) load(userptr, "wglCreateBufferRegionARB");
glad_wglDeleteBufferRegionARB = (PFNWGLDELETEBUFFERREGIONARBPROC) load(userptr, "wglDeleteBufferRegionARB");
glad_wglRestoreBufferRegionARB = (PFNWGLRESTOREBUFFERREGIONARBPROC) load(userptr, "wglRestoreBufferRegionARB");
glad_wglSaveBufferRegionARB = (PFNWGLSAVEBUFFERREGIONARBPROC) load(userptr, "wglSaveBufferRegionARB");
}
static void glad_wgl_load_WGL_ARB_create_context(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_ARB_create_context) return;
glad_wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) load(userptr, "wglCreateContextAttribsARB");
}
static void glad_wgl_load_WGL_ARB_extensions_string(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_ARB_extensions_string) return;
glad_wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) load(userptr, "wglGetExtensionsStringARB");
}
static void glad_wgl_load_WGL_ARB_make_current_read(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_ARB_make_current_read) return;
glad_wglGetCurrentReadDCARB = (PFNWGLGETCURRENTREADDCARBPROC) load(userptr, "wglGetCurrentReadDCARB");
glad_wglMakeContextCurrentARB = (PFNWGLMAKECONTEXTCURRENTARBPROC) load(userptr, "wglMakeContextCurrentARB");
}
static void glad_wgl_load_WGL_ARB_pbuffer(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_ARB_pbuffer) return;
glad_wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC) load(userptr, "wglCreatePbufferARB");
glad_wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC) load(userptr, "wglDestroyPbufferARB");
glad_wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC) load(userptr, "wglGetPbufferDCARB");
glad_wglQueryPbufferARB = (PFNWGLQUERYPBUFFERARBPROC) load(userptr, "wglQueryPbufferARB");
glad_wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC) load(userptr, "wglReleasePbufferDCARB");
}
static void glad_wgl_load_WGL_ARB_pixel_format(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_ARB_pixel_format) return;
glad_wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) load(userptr, "wglChoosePixelFormatARB");
glad_wglGetPixelFormatAttribfvARB = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC) load(userptr, "wglGetPixelFormatAttribfvARB");
glad_wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) load(userptr, "wglGetPixelFormatAttribivARB");
}
static void glad_wgl_load_WGL_ARB_render_texture(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_ARB_render_texture) return;
glad_wglBindTexImageARB = (PFNWGLBINDTEXIMAGEARBPROC) load(userptr, "wglBindTexImageARB");
glad_wglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARBPROC) load(userptr, "wglReleaseTexImageARB");
glad_wglSetPbufferAttribARB = (PFNWGLSETPBUFFERATTRIBARBPROC) load(userptr, "wglSetPbufferAttribARB");
}
static void glad_wgl_load_WGL_EXT_display_color_table(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_EXT_display_color_table) return;
glad_wglBindDisplayColorTableEXT = (PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) load(userptr, "wglBindDisplayColorTableEXT");
glad_wglCreateDisplayColorTableEXT = (PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) load(userptr, "wglCreateDisplayColorTableEXT");
glad_wglDestroyDisplayColorTableEXT = (PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) load(userptr, "wglDestroyDisplayColorTableEXT");
glad_wglLoadDisplayColorTableEXT = (PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) load(userptr, "wglLoadDisplayColorTableEXT");
}
static void glad_wgl_load_WGL_EXT_extensions_string(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_EXT_extensions_string) return;
glad_wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) load(userptr, "wglGetExtensionsStringEXT");
}
static void glad_wgl_load_WGL_EXT_make_current_read(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_EXT_make_current_read) return;
glad_wglGetCurrentReadDCEXT = (PFNWGLGETCURRENTREADDCEXTPROC) load(userptr, "wglGetCurrentReadDCEXT");
glad_wglMakeContextCurrentEXT = (PFNWGLMAKECONTEXTCURRENTEXTPROC) load(userptr, "wglMakeContextCurrentEXT");
}
static void glad_wgl_load_WGL_EXT_pbuffer(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_EXT_pbuffer) return;
glad_wglCreatePbufferEXT = (PFNWGLCREATEPBUFFEREXTPROC) load(userptr, "wglCreatePbufferEXT");
glad_wglDestroyPbufferEXT = (PFNWGLDESTROYPBUFFEREXTPROC) load(userptr, "wglDestroyPbufferEXT");
glad_wglGetPbufferDCEXT = (PFNWGLGETPBUFFERDCEXTPROC) load(userptr, "wglGetPbufferDCEXT");
glad_wglQueryPbufferEXT = (PFNWGLQUERYPBUFFEREXTPROC) load(userptr, "wglQueryPbufferEXT");
glad_wglReleasePbufferDCEXT = (PFNWGLRELEASEPBUFFERDCEXTPROC) load(userptr, "wglReleasePbufferDCEXT");
}
static void glad_wgl_load_WGL_EXT_pixel_format(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_EXT_pixel_format) return;
glad_wglChoosePixelFormatEXT = (PFNWGLCHOOSEPIXELFORMATEXTPROC) load(userptr, "wglChoosePixelFormatEXT");
glad_wglGetPixelFormatAttribfvEXT = (PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) load(userptr, "wglGetPixelFormatAttribfvEXT");
glad_wglGetPixelFormatAttribivEXT = (PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) load(userptr, "wglGetPixelFormatAttribivEXT");
}
static void glad_wgl_load_WGL_EXT_swap_control(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_EXT_swap_control) return;
glad_wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC) load(userptr, "wglGetSwapIntervalEXT");
glad_wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) load(userptr, "wglSwapIntervalEXT");
}
static void glad_wgl_load_WGL_I3D_digital_video_control(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_I3D_digital_video_control) return;
glad_wglGetDigitalVideoParametersI3D = (PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) load(userptr, "wglGetDigitalVideoParametersI3D");
glad_wglSetDigitalVideoParametersI3D = (PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) load(userptr, "wglSetDigitalVideoParametersI3D");
}
static void glad_wgl_load_WGL_I3D_gamma(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_I3D_gamma) return;
glad_wglGetGammaTableI3D = (PFNWGLGETGAMMATABLEI3DPROC) load(userptr, "wglGetGammaTableI3D");
glad_wglGetGammaTableParametersI3D = (PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) load(userptr, "wglGetGammaTableParametersI3D");
glad_wglSetGammaTableI3D = (PFNWGLSETGAMMATABLEI3DPROC) load(userptr, "wglSetGammaTableI3D");
glad_wglSetGammaTableParametersI3D = (PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) load(userptr, "wglSetGammaTableParametersI3D");
}
static void glad_wgl_load_WGL_I3D_genlock(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_I3D_genlock) return;
glad_wglDisableGenlockI3D = (PFNWGLDISABLEGENLOCKI3DPROC) load(userptr, "wglDisableGenlockI3D");
glad_wglEnableGenlockI3D = (PFNWGLENABLEGENLOCKI3DPROC) load(userptr, "wglEnableGenlockI3D");
glad_wglGenlockSampleRateI3D = (PFNWGLGENLOCKSAMPLERATEI3DPROC) load(userptr, "wglGenlockSampleRateI3D");
glad_wglGenlockSourceDelayI3D = (PFNWGLGENLOCKSOURCEDELAYI3DPROC) load(userptr, "wglGenlockSourceDelayI3D");
glad_wglGenlockSourceEdgeI3D = (PFNWGLGENLOCKSOURCEEDGEI3DPROC) load(userptr, "wglGenlockSourceEdgeI3D");
glad_wglGenlockSourceI3D = (PFNWGLGENLOCKSOURCEI3DPROC) load(userptr, "wglGenlockSourceI3D");
glad_wglGetGenlockSampleRateI3D = (PFNWGLGETGENLOCKSAMPLERATEI3DPROC) load(userptr, "wglGetGenlockSampleRateI3D");
glad_wglGetGenlockSourceDelayI3D = (PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) load(userptr, "wglGetGenlockSourceDelayI3D");
glad_wglGetGenlockSourceEdgeI3D = (PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) load(userptr, "wglGetGenlockSourceEdgeI3D");
glad_wglGetGenlockSourceI3D = (PFNWGLGETGENLOCKSOURCEI3DPROC) load(userptr, "wglGetGenlockSourceI3D");
glad_wglIsEnabledGenlockI3D = (PFNWGLISENABLEDGENLOCKI3DPROC) load(userptr, "wglIsEnabledGenlockI3D");
glad_wglQueryGenlockMaxSourceDelayI3D = (PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) load(userptr, "wglQueryGenlockMaxSourceDelayI3D");
}
static void glad_wgl_load_WGL_I3D_image_buffer(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_I3D_image_buffer) return;
glad_wglAssociateImageBufferEventsI3D = (PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) load(userptr, "wglAssociateImageBufferEventsI3D");
glad_wglCreateImageBufferI3D = (PFNWGLCREATEIMAGEBUFFERI3DPROC) load(userptr, "wglCreateImageBufferI3D");
glad_wglDestroyImageBufferI3D = (PFNWGLDESTROYIMAGEBUFFERI3DPROC) load(userptr, "wglDestroyImageBufferI3D");
glad_wglReleaseImageBufferEventsI3D = (PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) load(userptr, "wglReleaseImageBufferEventsI3D");
}
static void glad_wgl_load_WGL_I3D_swap_frame_lock(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_I3D_swap_frame_lock) return;
glad_wglDisableFrameLockI3D = (PFNWGLDISABLEFRAMELOCKI3DPROC) load(userptr, "wglDisableFrameLockI3D");
glad_wglEnableFrameLockI3D = (PFNWGLENABLEFRAMELOCKI3DPROC) load(userptr, "wglEnableFrameLockI3D");
glad_wglIsEnabledFrameLockI3D = (PFNWGLISENABLEDFRAMELOCKI3DPROC) load(userptr, "wglIsEnabledFrameLockI3D");
glad_wglQueryFrameLockMasterI3D = (PFNWGLQUERYFRAMELOCKMASTERI3DPROC) load(userptr, "wglQueryFrameLockMasterI3D");
}
static void glad_wgl_load_WGL_I3D_swap_frame_usage(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_I3D_swap_frame_usage) return;
glad_wglBeginFrameTrackingI3D = (PFNWGLBEGINFRAMETRACKINGI3DPROC) load(userptr, "wglBeginFrameTrackingI3D");
glad_wglEndFrameTrackingI3D = (PFNWGLENDFRAMETRACKINGI3DPROC) load(userptr, "wglEndFrameTrackingI3D");
glad_wglGetFrameUsageI3D = (PFNWGLGETFRAMEUSAGEI3DPROC) load(userptr, "wglGetFrameUsageI3D");
glad_wglQueryFrameTrackingI3D = (PFNWGLQUERYFRAMETRACKINGI3DPROC) load(userptr, "wglQueryFrameTrackingI3D");
}
static void glad_wgl_load_WGL_NV_DX_interop(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_NV_DX_interop) return;
glad_wglDXCloseDeviceNV = (PFNWGLDXCLOSEDEVICENVPROC) load(userptr, "wglDXCloseDeviceNV");
glad_wglDXLockObjectsNV = (PFNWGLDXLOCKOBJECTSNVPROC) load(userptr, "wglDXLockObjectsNV");
glad_wglDXObjectAccessNV = (PFNWGLDXOBJECTACCESSNVPROC) load(userptr, "wglDXObjectAccessNV");
glad_wglDXOpenDeviceNV = (PFNWGLDXOPENDEVICENVPROC) load(userptr, "wglDXOpenDeviceNV");
glad_wglDXRegisterObjectNV = (PFNWGLDXREGISTEROBJECTNVPROC) load(userptr, "wglDXRegisterObjectNV");
glad_wglDXSetResourceShareHandleNV = (PFNWGLDXSETRESOURCESHAREHANDLENVPROC) load(userptr, "wglDXSetResourceShareHandleNV");
glad_wglDXUnlockObjectsNV = (PFNWGLDXUNLOCKOBJECTSNVPROC) load(userptr, "wglDXUnlockObjectsNV");
glad_wglDXUnregisterObjectNV = (PFNWGLDXUNREGISTEROBJECTNVPROC) load(userptr, "wglDXUnregisterObjectNV");
}
static void glad_wgl_load_WGL_NV_copy_image(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_NV_copy_image) return;
glad_wglCopyImageSubDataNV = (PFNWGLCOPYIMAGESUBDATANVPROC) load(userptr, "wglCopyImageSubDataNV");
}
static void glad_wgl_load_WGL_NV_delay_before_swap(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_NV_delay_before_swap) return;
glad_wglDelayBeforeSwapNV = (PFNWGLDELAYBEFORESWAPNVPROC) load(userptr, "wglDelayBeforeSwapNV");
}
static void glad_wgl_load_WGL_NV_gpu_affinity(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_NV_gpu_affinity) return;
glad_wglCreateAffinityDCNV = (PFNWGLCREATEAFFINITYDCNVPROC) load(userptr, "wglCreateAffinityDCNV");
glad_wglDeleteDCNV = (PFNWGLDELETEDCNVPROC) load(userptr, "wglDeleteDCNV");
glad_wglEnumGpuDevicesNV = (PFNWGLENUMGPUDEVICESNVPROC) load(userptr, "wglEnumGpuDevicesNV");
glad_wglEnumGpusFromAffinityDCNV = (PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) load(userptr, "wglEnumGpusFromAffinityDCNV");
glad_wglEnumGpusNV = (PFNWGLENUMGPUSNVPROC) load(userptr, "wglEnumGpusNV");
}
static void glad_wgl_load_WGL_NV_present_video(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_NV_present_video) return;
glad_wglBindVideoDeviceNV = (PFNWGLBINDVIDEODEVICENVPROC) load(userptr, "wglBindVideoDeviceNV");
glad_wglEnumerateVideoDevicesNV = (PFNWGLENUMERATEVIDEODEVICESNVPROC) load(userptr, "wglEnumerateVideoDevicesNV");
glad_wglQueryCurrentContextNV = (PFNWGLQUERYCURRENTCONTEXTNVPROC) load(userptr, "wglQueryCurrentContextNV");
}
static void glad_wgl_load_WGL_NV_swap_group(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_NV_swap_group) return;
glad_wglBindSwapBarrierNV = (PFNWGLBINDSWAPBARRIERNVPROC) load(userptr, "wglBindSwapBarrierNV");
glad_wglJoinSwapGroupNV = (PFNWGLJOINSWAPGROUPNVPROC) load(userptr, "wglJoinSwapGroupNV");
glad_wglQueryFrameCountNV = (PFNWGLQUERYFRAMECOUNTNVPROC) load(userptr, "wglQueryFrameCountNV");
glad_wglQueryMaxSwapGroupsNV = (PFNWGLQUERYMAXSWAPGROUPSNVPROC) load(userptr, "wglQueryMaxSwapGroupsNV");
glad_wglQuerySwapGroupNV = (PFNWGLQUERYSWAPGROUPNVPROC) load(userptr, "wglQuerySwapGroupNV");
glad_wglResetFrameCountNV = (PFNWGLRESETFRAMECOUNTNVPROC) load(userptr, "wglResetFrameCountNV");
}
static void glad_wgl_load_WGL_NV_vertex_array_range(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_NV_vertex_array_range) return;
glad_wglAllocateMemoryNV = (PFNWGLALLOCATEMEMORYNVPROC) load(userptr, "wglAllocateMemoryNV");
glad_wglFreeMemoryNV = (PFNWGLFREEMEMORYNVPROC) load(userptr, "wglFreeMemoryNV");
}
static void glad_wgl_load_WGL_NV_video_capture(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_NV_video_capture) return;
glad_wglBindVideoCaptureDeviceNV = (PFNWGLBINDVIDEOCAPTUREDEVICENVPROC) load(userptr, "wglBindVideoCaptureDeviceNV");
glad_wglEnumerateVideoCaptureDevicesNV = (PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC) load(userptr, "wglEnumerateVideoCaptureDevicesNV");
glad_wglLockVideoCaptureDeviceNV = (PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC) load(userptr, "wglLockVideoCaptureDeviceNV");
glad_wglQueryVideoCaptureDeviceNV = (PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC) load(userptr, "wglQueryVideoCaptureDeviceNV");
glad_wglReleaseVideoCaptureDeviceNV = (PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC) load(userptr, "wglReleaseVideoCaptureDeviceNV");
}
static void glad_wgl_load_WGL_NV_video_output(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_NV_video_output) return;
glad_wglBindVideoImageNV = (PFNWGLBINDVIDEOIMAGENVPROC) load(userptr, "wglBindVideoImageNV");
glad_wglGetVideoDeviceNV = (PFNWGLGETVIDEODEVICENVPROC) load(userptr, "wglGetVideoDeviceNV");
glad_wglGetVideoInfoNV = (PFNWGLGETVIDEOINFONVPROC) load(userptr, "wglGetVideoInfoNV");
glad_wglReleaseVideoDeviceNV = (PFNWGLRELEASEVIDEODEVICENVPROC) load(userptr, "wglReleaseVideoDeviceNV");
glad_wglReleaseVideoImageNV = (PFNWGLRELEASEVIDEOIMAGENVPROC) load(userptr, "wglReleaseVideoImageNV");
glad_wglSendPbufferToVideoNV = (PFNWGLSENDPBUFFERTOVIDEONVPROC) load(userptr, "wglSendPbufferToVideoNV");
}
static void glad_wgl_load_WGL_OML_sync_control(GLADuserptrloadfunc load, void *userptr) {
if(!GLAD_WGL_OML_sync_control) return;
glad_wglGetMscRateOML = (PFNWGLGETMSCRATEOMLPROC) load(userptr, "wglGetMscRateOML");
glad_wglGetSyncValuesOML = (PFNWGLGETSYNCVALUESOMLPROC) load(userptr, "wglGetSyncValuesOML");
glad_wglSwapBuffersMscOML = (PFNWGLSWAPBUFFERSMSCOMLPROC) load(userptr, "wglSwapBuffersMscOML");
glad_wglSwapLayerBuffersMscOML = (PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) load(userptr, "wglSwapLayerBuffersMscOML");
glad_wglWaitForMscOML = (PFNWGLWAITFORMSCOMLPROC) load(userptr, "wglWaitForMscOML");
glad_wglWaitForSbcOML = (PFNWGLWAITFORSBCOMLPROC) load(userptr, "wglWaitForSbcOML");
}
static void glad_wgl_resolve_aliases(void) {
}
static int glad_wgl_has_extension(HDC hdc, const char *ext) {
const char *terminator;
const char *loc;
const char *extensions;
if(wglGetExtensionsStringEXT == NULL && wglGetExtensionsStringARB == NULL)
return 0;
if(wglGetExtensionsStringARB == NULL || hdc == INVALID_HANDLE_VALUE)
extensions = wglGetExtensionsStringEXT();
else
extensions = wglGetExtensionsStringARB(hdc);
if(extensions == NULL || ext == NULL)
return 0;
while(1) {
loc = strstr(extensions, ext);
if(loc == NULL)
break;
terminator = loc + strlen(ext);
if((loc == extensions || *(loc - 1) == ' ') &&
(*terminator == ' ' || *terminator == '\0'))
{
return 1;
}
extensions = terminator;
}
return 0;
}
static GLADapiproc glad_wgl_get_proc_from_userptr(void *userptr, const char* name) {
return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);
}
static int glad_wgl_find_extensions_wgl(HDC hdc) {
GLAD_WGL_3DFX_multisample = glad_wgl_has_extension(hdc, "WGL_3DFX_multisample");
GLAD_WGL_3DL_stereo_control = glad_wgl_has_extension(hdc, "WGL_3DL_stereo_control");
GLAD_WGL_AMD_gpu_association = glad_wgl_has_extension(hdc, "WGL_AMD_gpu_association");
GLAD_WGL_ARB_buffer_region = glad_wgl_has_extension(hdc, "WGL_ARB_buffer_region");
GLAD_WGL_ARB_context_flush_control = glad_wgl_has_extension(hdc, "WGL_ARB_context_flush_control");
GLAD_WGL_ARB_create_context = glad_wgl_has_extension(hdc, "WGL_ARB_create_context");
GLAD_WGL_ARB_create_context_no_error = glad_wgl_has_extension(hdc, "WGL_ARB_create_context_no_error");
GLAD_WGL_ARB_create_context_profile = glad_wgl_has_extension(hdc, "WGL_ARB_create_context_profile");
GLAD_WGL_ARB_create_context_robustness = glad_wgl_has_extension(hdc, "WGL_ARB_create_context_robustness");
GLAD_WGL_ARB_extensions_string = glad_wgl_has_extension(hdc, "WGL_ARB_extensions_string");
GLAD_WGL_ARB_framebuffer_sRGB = glad_wgl_has_extension(hdc, "WGL_ARB_framebuffer_sRGB");
GLAD_WGL_ARB_make_current_read = glad_wgl_has_extension(hdc, "WGL_ARB_make_current_read");
GLAD_WGL_ARB_multisample = glad_wgl_has_extension(hdc, "WGL_ARB_multisample");
GLAD_WGL_ARB_pbuffer = glad_wgl_has_extension(hdc, "WGL_ARB_pbuffer");
GLAD_WGL_ARB_pixel_format = glad_wgl_has_extension(hdc, "WGL_ARB_pixel_format");
GLAD_WGL_ARB_pixel_format_float = glad_wgl_has_extension(hdc, "WGL_ARB_pixel_format_float");
GLAD_WGL_ARB_render_texture = glad_wgl_has_extension(hdc, "WGL_ARB_render_texture");
GLAD_WGL_ARB_robustness_application_isolation = glad_wgl_has_extension(hdc, "WGL_ARB_robustness_application_isolation");
GLAD_WGL_ARB_robustness_share_group_isolation = glad_wgl_has_extension(hdc, "WGL_ARB_robustness_share_group_isolation");
GLAD_WGL_ATI_pixel_format_float = glad_wgl_has_extension(hdc, "WGL_ATI_pixel_format_float");
GLAD_WGL_ATI_render_texture_rectangle = glad_wgl_has_extension(hdc, "WGL_ATI_render_texture_rectangle");
GLAD_WGL_EXT_colorspace = glad_wgl_has_extension(hdc, "WGL_EXT_colorspace");
GLAD_WGL_EXT_create_context_es2_profile = glad_wgl_has_extension(hdc, "WGL_EXT_create_context_es2_profile");
GLAD_WGL_EXT_create_context_es_profile = glad_wgl_has_extension(hdc, "WGL_EXT_create_context_es_profile");
GLAD_WGL_EXT_depth_float = glad_wgl_has_extension(hdc, "WGL_EXT_depth_float");
GLAD_WGL_EXT_display_color_table = glad_wgl_has_extension(hdc, "WGL_EXT_display_color_table");
GLAD_WGL_EXT_extensions_string = glad_wgl_has_extension(hdc, "WGL_EXT_extensions_string");
GLAD_WGL_EXT_framebuffer_sRGB = glad_wgl_has_extension(hdc, "WGL_EXT_framebuffer_sRGB");
GLAD_WGL_EXT_make_current_read = glad_wgl_has_extension(hdc, "WGL_EXT_make_current_read");
GLAD_WGL_EXT_multisample = glad_wgl_has_extension(hdc, "WGL_EXT_multisample");
GLAD_WGL_EXT_pbuffer = glad_wgl_has_extension(hdc, "WGL_EXT_pbuffer");
GLAD_WGL_EXT_pixel_format = glad_wgl_has_extension(hdc, "WGL_EXT_pixel_format");
GLAD_WGL_EXT_pixel_format_packed_float = glad_wgl_has_extension(hdc, "WGL_EXT_pixel_format_packed_float");
GLAD_WGL_EXT_swap_control = glad_wgl_has_extension(hdc, "WGL_EXT_swap_control");
GLAD_WGL_EXT_swap_control_tear = glad_wgl_has_extension(hdc, "WGL_EXT_swap_control_tear");
GLAD_WGL_I3D_digital_video_control = glad_wgl_has_extension(hdc, "WGL_I3D_digital_video_control");
GLAD_WGL_I3D_gamma = glad_wgl_has_extension(hdc, "WGL_I3D_gamma");
GLAD_WGL_I3D_genlock = glad_wgl_has_extension(hdc, "WGL_I3D_genlock");
GLAD_WGL_I3D_image_buffer = glad_wgl_has_extension(hdc, "WGL_I3D_image_buffer");
GLAD_WGL_I3D_swap_frame_lock = glad_wgl_has_extension(hdc, "WGL_I3D_swap_frame_lock");
GLAD_WGL_I3D_swap_frame_usage = glad_wgl_has_extension(hdc, "WGL_I3D_swap_frame_usage");
GLAD_WGL_NV_DX_interop = glad_wgl_has_extension(hdc, "WGL_NV_DX_interop");
GLAD_WGL_NV_DX_interop2 = glad_wgl_has_extension(hdc, "WGL_NV_DX_interop2");
GLAD_WGL_NV_copy_image = glad_wgl_has_extension(hdc, "WGL_NV_copy_image");
GLAD_WGL_NV_delay_before_swap = glad_wgl_has_extension(hdc, "WGL_NV_delay_before_swap");
GLAD_WGL_NV_float_buffer = glad_wgl_has_extension(hdc, "WGL_NV_float_buffer");
GLAD_WGL_NV_gpu_affinity = glad_wgl_has_extension(hdc, "WGL_NV_gpu_affinity");
GLAD_WGL_NV_multigpu_context = glad_wgl_has_extension(hdc, "WGL_NV_multigpu_context");
GLAD_WGL_NV_multisample_coverage = glad_wgl_has_extension(hdc, "WGL_NV_multisample_coverage");
GLAD_WGL_NV_present_video = glad_wgl_has_extension(hdc, "WGL_NV_present_video");
GLAD_WGL_NV_render_depth_texture = glad_wgl_has_extension(hdc, "WGL_NV_render_depth_texture");
GLAD_WGL_NV_render_texture_rectangle = glad_wgl_has_extension(hdc, "WGL_NV_render_texture_rectangle");
GLAD_WGL_NV_swap_group = glad_wgl_has_extension(hdc, "WGL_NV_swap_group");
GLAD_WGL_NV_vertex_array_range = glad_wgl_has_extension(hdc, "WGL_NV_vertex_array_range");
GLAD_WGL_NV_video_capture = glad_wgl_has_extension(hdc, "WGL_NV_video_capture");
GLAD_WGL_NV_video_output = glad_wgl_has_extension(hdc, "WGL_NV_video_output");
GLAD_WGL_OML_sync_control = glad_wgl_has_extension(hdc, "WGL_OML_sync_control");
return 1;
}
static int glad_wgl_find_core_wgl(void) {
int major = 1, minor = 0;
GLAD_WGL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
return GLAD_MAKE_VERSION(major, minor);
}
int gladLoadWGLUserPtr(HDC hdc, GLADuserptrloadfunc load, void *userptr) {
int version;
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) load(userptr, "wglGetExtensionsStringARB");
wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) load(userptr, "wglGetExtensionsStringEXT");
if(wglGetExtensionsStringARB == NULL && wglGetExtensionsStringEXT == NULL) return 0;
version = glad_wgl_find_core_wgl();
if (!glad_wgl_find_extensions_wgl(hdc)) return 0;
glad_wgl_load_WGL_3DL_stereo_control(load, userptr);
glad_wgl_load_WGL_AMD_gpu_association(load, userptr);
glad_wgl_load_WGL_ARB_buffer_region(load, userptr);
glad_wgl_load_WGL_ARB_create_context(load, userptr);
glad_wgl_load_WGL_ARB_extensions_string(load, userptr);
glad_wgl_load_WGL_ARB_make_current_read(load, userptr);
glad_wgl_load_WGL_ARB_pbuffer(load, userptr);
glad_wgl_load_WGL_ARB_pixel_format(load, userptr);
glad_wgl_load_WGL_ARB_render_texture(load, userptr);
glad_wgl_load_WGL_EXT_display_color_table(load, userptr);
glad_wgl_load_WGL_EXT_extensions_string(load, userptr);
glad_wgl_load_WGL_EXT_make_current_read(load, userptr);
glad_wgl_load_WGL_EXT_pbuffer(load, userptr);
glad_wgl_load_WGL_EXT_pixel_format(load, userptr);
glad_wgl_load_WGL_EXT_swap_control(load, userptr);
glad_wgl_load_WGL_I3D_digital_video_control(load, userptr);
glad_wgl_load_WGL_I3D_gamma(load, userptr);
glad_wgl_load_WGL_I3D_genlock(load, userptr);
glad_wgl_load_WGL_I3D_image_buffer(load, userptr);
glad_wgl_load_WGL_I3D_swap_frame_lock(load, userptr);
glad_wgl_load_WGL_I3D_swap_frame_usage(load, userptr);
glad_wgl_load_WGL_NV_DX_interop(load, userptr);
glad_wgl_load_WGL_NV_copy_image(load, userptr);
glad_wgl_load_WGL_NV_delay_before_swap(load, userptr);
glad_wgl_load_WGL_NV_gpu_affinity(load, userptr);
glad_wgl_load_WGL_NV_present_video(load, userptr);
glad_wgl_load_WGL_NV_swap_group(load, userptr);
glad_wgl_load_WGL_NV_vertex_array_range(load, userptr);
glad_wgl_load_WGL_NV_video_capture(load, userptr);
glad_wgl_load_WGL_NV_video_output(load, userptr);
glad_wgl_load_WGL_OML_sync_control(load, userptr);
glad_wgl_resolve_aliases();
return version;
}
int gladLoadWGL(HDC hdc, GLADloadfunc load) {
return gladLoadWGLUserPtr(hdc, glad_wgl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
}
#ifdef GLAD_WGL
static GLADapiproc glad_wgl_get_proc(void *vuserptr, const char* name) {
GLAD_UNUSED(vuserptr);
return GLAD_GNUC_EXTENSION (GLADapiproc) wglGetProcAddress(name);
}
int gladLoaderLoadWGL(HDC hdc) {
return gladLoadWGLUserPtr(hdc, glad_wgl_get_proc, NULL);
}
#endif /* GLAD_WGL */
#ifdef __cplusplus
}
#endif