1 module gfx.gl3; 2 3 import gfx.core.rc : AtomicRefCounted; 4 import gfx.graal : DebugCallback, Instance; 5 import gfx.graal.device : PhysicalDevice; 6 7 class GlInstance : Instance 8 { 9 import gfx.core.rc : atomicRcCode, Rc; 10 import gfx.gl3.context : GlContext; 11 import gfx.graal : ApiProps, Backend, CoordSystem; 12 13 mixin(atomicRcCode); 14 15 private Rc!GlContext _ctx; 16 private Rc!GlShare _share; 17 private Rc!PhysicalDevice _phd; 18 19 this(GlContext ctx) { 20 _ctx = ctx; 21 _share = new GlShare(_ctx); 22 _phd = new GlPhysicalDevice(_share); 23 } 24 25 override void dispose() { 26 _phd.unload(); 27 _share.unload(); 28 _ctx.unload(); 29 } 30 31 override @property Backend backend() { 32 return Backend.gl3; 33 } 34 35 override @property ApiProps apiProps() { 36 return ApiProps( 37 "gl3", CoordSystem.leftHanded 38 ); 39 } 40 41 override PhysicalDevice[] devices() { 42 return [ _phd.obj ]; 43 } 44 45 override void setDebugCallback(DebugCallback callback) { 46 _share._callback = callback; 47 } 48 49 @property GlContext ctx() { 50 return _ctx.obj; 51 } 52 } 53 54 package: 55 56 import gfx.bindings.opengl.gl : Gl; 57 58 struct GlInfo 59 { 60 ushort glVer; 61 ushort glslVer; 62 bool bufferStorage; 63 bool textureStorage; 64 bool textureStorageMS; 65 bool samplerObject; 66 bool drawElementsBaseVertex; 67 bool baseInstance; 68 bool viewportArray; 69 bool polygonOffsetClamp; 70 71 private static GlInfo fetchAndCheck (Gl gl, uint glVer) { 72 import gfx.bindings.opengl.gl : GL_VERSION, GL_SHADING_LANGUAGE_VERSION; 73 import gfx.gl3.context : glAvailableExtensions, glRequiredExtensions, glslVersion; 74 import std.algorithm : canFind; 75 import std.string : fromStringz; 76 77 const exts = glAvailableExtensions(gl); 78 79 foreach (glE; glRequiredExtensions) { 80 import std.exception : enforce; 81 import std.format : format; 82 enforce(exts.canFind(glE), format(glE ~ " is required but was not found")); 83 } 84 85 bool checkVersion(uint ver) { 86 return glVer >= ver; 87 } 88 89 bool checkFeature(uint ver, in string ext) { 90 return glVer >= ver || exts.canFind(ext); 91 } 92 93 GlInfo gi; 94 gi.glVer = cast(ushort)glVer; 95 gi.glslVer = cast(ushort)glslVersion(glVer); 96 gi.bufferStorage = checkFeature(44, "GL_ARB_buffer_storage"); 97 gi.textureStorage = checkFeature(42, "GL_ARB_texture_storage"); 98 gi.textureStorageMS = checkFeature(43, "GL_ARB_texture_storage_multisample"); 99 gi.samplerObject = checkFeature(33, "GL_ARB_sampler_objects"); 100 gi.drawElementsBaseVertex = checkFeature(32, "ARB_draw_elements_base_vertex"); 101 gi.baseInstance = checkFeature(42, "ARB_base_instance"); 102 gi.viewportArray = checkFeature(41, "ARB_viewport_array"); 103 gi.polygonOffsetClamp = exts.canFind("GL_EXT_polygon_offset_clamp"); 104 return gi; 105 } 106 } 107 108 109 class GlShare : AtomicRefCounted 110 { 111 import gfx.core.rc : atomicRcCode, Rc; 112 import gfx.gl3.context : GlContext; 113 114 mixin(atomicRcCode); 115 116 private Rc!GlContext _ctx; 117 private size_t _dummyWin; 118 private Gl _gl; 119 private GlInfo _info; 120 private DebugCallback _callback; 121 122 this(GlContext ctx) { 123 _ctx = ctx; 124 _dummyWin = _ctx.createDummy(); 125 _ctx.makeCurrent(_dummyWin); 126 _gl = ctx.gl; 127 _info = GlInfo.fetchAndCheck(_gl, ctx.attribs.decimalVersion); 128 } 129 130 override void dispose() { 131 _ctx.doneCurrent(); 132 _ctx.releaseDummy(_dummyWin); 133 _ctx.unload(); 134 } 135 136 @property inout(GlContext) ctx() inout { 137 return _ctx.obj; 138 } 139 @property inout(Gl) gl() inout { 140 return _gl; 141 } 142 @property GlInfo info() const { 143 return _info; 144 } 145 package @property size_t dummyWin() const { 146 return _dummyWin; 147 } 148 } 149 150 151 class GlPhysicalDevice : PhysicalDevice 152 { 153 import gfx.bindings.opengl.gl : Gl; 154 import gfx.core.rc : atomicRcCode, Rc; 155 import gfx.gl3.context : GlContext; 156 import gfx.graal.device : Device, DeviceFeatures, DeviceLimits, DeviceType, 157 QueueRequest; 158 import gfx.graal.format : Format, FormatProperties; 159 import gfx.graal.memory : MemoryProperties; 160 import gfx.graal.queue : QueueFamily; 161 import gfx.graal.presentation : PresentMode, Surface, SurfaceCaps; 162 163 mixin(atomicRcCode); 164 165 private Rc!GlShare _share; 166 private string _name; 167 168 this(GlShare share) { 169 _share = share; 170 171 import gfx.bindings.opengl.gl : GL_RENDERER; 172 import std.string : fromStringz; 173 _name = fromStringz(cast(const(char)*)share.gl.GetString(GL_RENDERER)).idup; 174 } 175 176 override void dispose() { 177 _share.unload(); 178 } 179 180 override @property string name() { 181 return _name; 182 } 183 184 override @property DeviceType type() { 185 return DeviceType.other; 186 } 187 188 override @property DeviceFeatures features() { 189 // TODO 190 return DeviceFeatures.all(); 191 } 192 193 override @property DeviceLimits limits() { 194 return DeviceLimits.init; 195 } 196 197 override @property MemoryProperties memoryProperties() { 198 import gfx.graal.memory : MemoryHeap, MemProps, MemoryType; 199 const props = MemProps.deviceLocal | MemProps.hostVisible | MemProps.hostCoherent; 200 // TODO: buffer storage 201 return MemoryProperties( 202 [ MemoryHeap(size_t.max, true) ], 203 [ MemoryType(props, 0) ] 204 ); 205 } 206 207 override @property QueueFamily[] queueFamilies() { 208 import gfx.graal.queue : QueueCap; 209 return [ 210 QueueFamily(QueueCap.graphics, 1) 211 ]; 212 } 213 214 override FormatProperties formatProperties(in Format format) { 215 import gfx.graal.format : FormatFeatures; 216 217 const color = FormatFeatures.sampledImage | 218 FormatFeatures.colorAttachment | FormatFeatures.blit; 219 const depthStencil = FormatFeatures.depthStencilAttachment; 220 221 switch (format) { 222 case Format.r8_uNorm: 223 case Format.rg8_uNorm: 224 case Format.rgba8_uNorm: 225 case Format.r8_sInt: 226 case Format.rg8_sInt: 227 case Format.rgba8_sInt: 228 case Format.r8_uInt: 229 case Format.rg8_uInt: 230 case Format.rgba8_uInt: 231 case Format.r16_uNorm: 232 case Format.rg16_uNorm: 233 case Format.rgba16_uNorm: 234 case Format.r16_sInt: 235 case Format.rg16_sInt: 236 case Format.rgba16_sInt: 237 case Format.r16_uInt: 238 case Format.rg16_uInt: 239 case Format.rgba16_uInt: 240 return FormatProperties( 241 color, color, FormatFeatures.init 242 ); 243 case Format.d16_uNorm: 244 case Format.x8d24_uNorm: 245 case Format.d32_sFloat: 246 case Format.d24s8_uNorm: 247 case Format.s8_uInt: 248 return FormatProperties( 249 depthStencil, depthStencil, FormatFeatures.init 250 ); 251 default: 252 return FormatProperties.init; 253 } 254 } 255 256 override bool supportsSurface(uint queueFamilyIndex, Surface surface) { 257 return true; 258 } 259 260 override SurfaceCaps surfaceCaps(Surface surface) { 261 import gfx.graal.image : ImageUsage; 262 import gfx.graal.presentation : CompositeAlpha; 263 return SurfaceCaps( 264 2, 4, [4, 4], [16384, 16384], 1, 265 ImageUsage.colorAttachment | ImageUsage.sampled | ImageUsage.transfer, 266 CompositeAlpha.inherit 267 ); 268 } 269 270 override Format[] surfaceFormats(Surface surface) { 271 return [ Format.rgba8_uNorm ]; 272 } 273 274 override PresentMode[] surfacePresentModes(Surface surface) { 275 return [ PresentMode.fifo ]; 276 } 277 278 /// Open a logical device with the specified queues. 279 /// Returns: null if it can't meet all requested queues, the opened device otherwise. 280 override Device open(in QueueRequest[], in DeviceFeatures) 281 { 282 import gfx.gl3.device : GlDevice; 283 return new GlDevice(this, _share); 284 } 285 }