forked from aya/aya
Initial commit
This commit is contained in:
314
engine/gfx/src/API/BGFX/DeviceBGFX.cpp
Normal file
314
engine/gfx/src/API/BGFX/DeviceBGFX.cpp
Normal 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
|
||||
195
engine/gfx/src/API/BGFX/DeviceBGFX.hpp
Normal file
195
engine/gfx/src/API/BGFX/DeviceBGFX.hpp
Normal 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
|
||||
552
engine/gfx/src/API/BGFX/DeviceContextBGFX.cpp
Normal file
552
engine/gfx/src/API/BGFX/DeviceContextBGFX.cpp
Normal 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
|
||||
148
engine/gfx/src/API/BGFX/FramebufferBGFX.cpp
Normal file
148
engine/gfx/src/API/BGFX/FramebufferBGFX.cpp
Normal 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
|
||||
53
engine/gfx/src/API/BGFX/FramebufferBGFX.hpp
Normal file
53
engine/gfx/src/API/BGFX/FramebufferBGFX.hpp
Normal 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
|
||||
343
engine/gfx/src/API/BGFX/GeometryBGFX.cpp
Normal file
343
engine/gfx/src/API/BGFX/GeometryBGFX.cpp
Normal 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
|
||||
100
engine/gfx/src/API/BGFX/GeometryBGFX.hpp
Normal file
100
engine/gfx/src/API/BGFX/GeometryBGFX.hpp
Normal 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
|
||||
14
engine/gfx/src/API/BGFX/HeadersBGFX.hpp
Normal file
14
engine/gfx/src/API/BGFX/HeadersBGFX.hpp
Normal 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
|
||||
293
engine/gfx/src/API/BGFX/ShaderBGFX.cpp
Normal file
293
engine/gfx/src/API/BGFX/ShaderBGFX.cpp
Normal 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
|
||||
93
engine/gfx/src/API/BGFX/ShaderBGFX.hpp
Normal file
93
engine/gfx/src/API/BGFX/ShaderBGFX.hpp
Normal 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
|
||||
269
engine/gfx/src/API/BGFX/TextureBGFX.cpp
Normal file
269
engine/gfx/src/API/BGFX/TextureBGFX.cpp
Normal 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
|
||||
57
engine/gfx/src/API/BGFX/TextureBGFX.hpp
Normal file
57
engine/gfx/src/API/BGFX/TextureBGFX.hpp
Normal 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
|
||||
201
engine/gfx/src/API/GL/ContextEGL.cpp
Normal file
201
engine/gfx/src/API/GL/ContextEGL.cpp
Normal 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
|
||||
28
engine/gfx/src/API/GL/ContextGL.hpp
Normal file
28
engine/gfx/src/API/GL/ContextGL.hpp
Normal 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
|
||||
286
engine/gfx/src/API/GL/ContextGLAndroid.cpp
Normal file
286
engine/gfx/src/API/GL/ContextGLAndroid.cpp
Normal 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
|
||||
177
engine/gfx/src/API/GL/ContextGLMac.mm
Normal file
177
engine/gfx/src/API/GL/ContextGLMac.mm
Normal 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
|
||||
146
engine/gfx/src/API/GL/ContextGLWin32.cpp
Normal file
146
engine/gfx/src/API/GL/ContextGLWin32.cpp
Normal 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
|
||||
513
engine/gfx/src/API/GL/DeviceContextGL.cpp
Normal file
513
engine/gfx/src/API/GL/DeviceContextGL.cpp
Normal 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
|
||||
617
engine/gfx/src/API/GL/DeviceGL.cpp
Normal file
617
engine/gfx/src/API/GL/DeviceGL.cpp
Normal 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
|
||||
178
engine/gfx/src/API/GL/DeviceGL.hpp
Normal file
178
engine/gfx/src/API/GL/DeviceGL.hpp
Normal 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
|
||||
163
engine/gfx/src/API/GL/FramebufferGL.cpp
Normal file
163
engine/gfx/src/API/GL/FramebufferGL.cpp
Normal 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
|
||||
67
engine/gfx/src/API/GL/FramebufferGL.hpp
Normal file
67
engine/gfx/src/API/GL/FramebufferGL.hpp
Normal 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
|
||||
339
engine/gfx/src/API/GL/GeometryGL.cpp
Normal file
339
engine/gfx/src/API/GL/GeometryGL.cpp
Normal 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
|
||||
83
engine/gfx/src/API/GL/GeometryGL.hpp
Normal file
83
engine/gfx/src/API/GL/GeometryGL.hpp
Normal 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
|
||||
137
engine/gfx/src/API/GL/HeadersGL.hpp
Normal file
137
engine/gfx/src/API/GL/HeadersGL.hpp
Normal 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
|
||||
563
engine/gfx/src/API/GL/ShaderGL.cpp
Normal file
563
engine/gfx/src/API/GL/ShaderGL.cpp
Normal 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
|
||||
123
engine/gfx/src/API/GL/ShaderGL.hpp
Normal file
123
engine/gfx/src/API/GL/ShaderGL.hpp
Normal 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
|
||||
545
engine/gfx/src/API/GL/TextureGL.cpp
Normal file
545
engine/gfx/src/API/GL/TextureGL.cpp
Normal 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
|
||||
75
engine/gfx/src/API/GL/TextureGL.hpp
Normal file
75
engine/gfx/src/API/GL/TextureGL.hpp
Normal 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
|
||||
175
engine/gfx/src/API/GL/glad/include/EGL/eglplatform.h
Normal file
175
engine/gfx/src/API/GL/glad/include/EGL/eglplatform.h
Normal 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 */
|
||||
311
engine/gfx/src/API/GL/glad/include/KHR/khrplatform.h
Normal file
311
engine/gfx/src/API/GL/glad/include/KHR/khrplatform.h
Normal 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_ */
|
||||
1651
engine/gfx/src/API/GL/glad/include/glad/egl.h
Normal file
1651
engine/gfx/src/API/GL/glad/include/glad/egl.h
Normal file
File diff suppressed because it is too large
Load Diff
15685
engine/gfx/src/API/GL/glad/include/glad/gl.h
Normal file
15685
engine/gfx/src/API/GL/glad/include/glad/gl.h
Normal file
File diff suppressed because one or more lines are too long
1179
engine/gfx/src/API/GL/glad/include/glad/glx.h
Normal file
1179
engine/gfx/src/API/GL/glad/include/glad/glx.h
Normal file
File diff suppressed because it is too large
Load Diff
1025
engine/gfx/src/API/GL/glad/include/glad/wgl.h
Normal file
1025
engine/gfx/src/API/GL/glad/include/glad/wgl.h
Normal file
File diff suppressed because it is too large
Load Diff
1217
engine/gfx/src/API/GL/glad/src/egl.c
Normal file
1217
engine/gfx/src/API/GL/glad/src/egl.c
Normal file
File diff suppressed because it is too large
Load Diff
11634
engine/gfx/src/API/GL/glad/src/gl.c
Normal file
11634
engine/gfx/src/API/GL/glad/src/gl.c
Normal file
File diff suppressed because it is too large
Load Diff
798
engine/gfx/src/API/GL/glad/src/glx.c
Normal file
798
engine/gfx/src/API/GL/glad/src/glx.c
Normal 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
|
||||
596
engine/gfx/src/API/GL/glad/src/wgl.c
Normal file
596
engine/gfx/src/API/GL/glad/src/wgl.c
Normal 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
|
||||
Reference in New Issue
Block a user