Browse Source

Add missing files

Signed-off-by: falkTX <falktx@falktx.com>
tags/v2.5.0
falkTX 2 years ago
parent
commit
b5ba16f4b8
33 changed files with 9215 additions and 1 deletions
  1. +0
    -1
      source/modules/dgl/src/pugl-upstream
  2. +13
    -0
      source/modules/dgl/src/pugl-upstream/AUTHORS
  3. +13
    -0
      source/modules/dgl/src/pugl-upstream/COPYING
  4. +10
    -0
      source/modules/dgl/src/pugl-upstream/include/.clang-tidy
  5. +12
    -0
      source/modules/dgl/src/pugl-upstream/include/meson.build
  6. +46
    -0
      source/modules/dgl/src/pugl-upstream/include/pugl/cairo.h
  7. +107
    -0
      source/modules/dgl/src/pugl-upstream/include/pugl/gl.h
  8. +1636
    -0
      source/modules/dgl/src/pugl-upstream/include/pugl/pugl.h
  9. +47
    -0
      source/modules/dgl/src/pugl-upstream/include/pugl/stub.h
  10. +156
    -0
      source/modules/dgl/src/pugl-upstream/include/pugl/vulkan.h
  11. +16
    -0
      source/modules/dgl/src/pugl-upstream/src/.clang-tidy
  12. +468
    -0
      source/modules/dgl/src/pugl-upstream/src/implementation.c
  13. +86
    -0
      source/modules/dgl/src/pugl-upstream/src/implementation.h
  14. +55
    -0
      source/modules/dgl/src/pugl-upstream/src/mac.h
  15. +1501
    -0
      source/modules/dgl/src/pugl-upstream/src/mac.m
  16. +160
    -0
      source/modules/dgl/src/pugl-upstream/src/mac_cairo.m
  17. +211
    -0
      source/modules/dgl/src/pugl-upstream/src/mac_gl.m
  18. +92
    -0
      source/modules/dgl/src/pugl-upstream/src/mac_stub.m
  19. +211
    -0
      source/modules/dgl/src/pugl-upstream/src/mac_vulkan.m
  20. +72
    -0
      source/modules/dgl/src/pugl-upstream/src/stub.h
  21. +111
    -0
      source/modules/dgl/src/pugl-upstream/src/types.h
  22. +1295
    -0
      source/modules/dgl/src/pugl-upstream/src/win.c
  23. +68
    -0
      source/modules/dgl/src/pugl-upstream/src/win.h
  24. +178
    -0
      source/modules/dgl/src/pugl-upstream/src/win_cairo.c
  25. +333
    -0
      source/modules/dgl/src/pugl-upstream/src/win_gl.c
  26. +52
    -0
      source/modules/dgl/src/pugl-upstream/src/win_stub.c
  27. +125
    -0
      source/modules/dgl/src/pugl-upstream/src/win_vulkan.c
  28. +1498
    -0
      source/modules/dgl/src/pugl-upstream/src/x11.c
  29. +80
    -0
      source/modules/dgl/src/pugl-upstream/src/x11.h
  30. +160
    -0
      source/modules/dgl/src/pugl-upstream/src/x11_cairo.c
  31. +238
    -0
      source/modules/dgl/src/pugl-upstream/src/x11_gl.c
  32. +38
    -0
      source/modules/dgl/src/pugl-upstream/src/x11_stub.c
  33. +127
    -0
      source/modules/dgl/src/pugl-upstream/src/x11_vulkan.c

+ 0
- 1
source/modules/dgl/src/pugl-upstream

@@ -1 +0,0 @@
Subproject commit b1d9703ecbdb0a033fe0b9acdf58b90f7d81a8e5

+ 13
- 0
source/modules/dgl/src/pugl-upstream/AUTHORS View File

@@ -0,0 +1,13 @@
Pugl is primarily written and maintained by David Robillard <d@drobilla.net>
with contributions from (in increasing chronological order):

Ben Loftis <ben@harrisonconsoles.com>
Robin Gareus <robin@gareus.org>
Erik Åldstedt Sund <erikalds@gmail.com>
Hanspeter Portner <dev@open-music-kontrollers.ch>
Stefan Westerfeld <stefan@space.twc.de>
Jordan Halase <jordan@halase.me>
Oliver Schmidt <oliver@luced.de>
Zoë Sparks <zoe@milky.flowers>
Jean Pierre Cimalando <jp-dev@inbox.ru>
Thomas Brand <tom@trellis.ch>

+ 13
- 0
source/modules/dgl/src/pugl-upstream/COPYING View File

@@ -0,0 +1,13 @@
Copyright 2011-2021 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

+ 10
- 0
source/modules/dgl/src/pugl-upstream/include/.clang-tidy View File

@@ -0,0 +1,10 @@
Checks: >
*,
-*-magic-numbers,
-*-uppercase-literal-suffix,
-altera-struct-pack-align,
-clang-diagnostic-unused-function,
-clang-diagnostic-unused-macros,
-llvmlibc-*,
FormatStyle: file
HeaderFilterRegex: 'pugl/.*'

+ 12
- 0
source/modules/dgl/src/pugl-upstream/include/meson.build View File

@@ -0,0 +1,12 @@
c_headers = [
'pugl/pugl.h',

'pugl/cairo.h',
'pugl/gl.h',
'pugl/stub.h',
'pugl/vulkan.h',
]

c_header_files = files(c_headers)

install_headers(c_headers, subdir: versioned_name / 'pugl')

+ 46
- 0
source/modules/dgl/src/pugl-upstream/include/pugl/cairo.h View File

@@ -0,0 +1,46 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_CAIRO_H
#define PUGL_CAIRO_H

#include "pugl/pugl.h"

PUGL_BEGIN_DECLS

/**
@defgroup cairo Cairo
Cairo graphics support.
@ingroup pugl
@{
*/

/**
Cairo graphics backend accessor.

Pass the returned value to puglSetBackend() to draw to a view with Cairo.
*/
PUGL_CONST_API
const PuglBackend*
puglCairoBackend(void);

/**
@}
*/

PUGL_END_DECLS

#endif // PUGL_CAIRO_H

+ 107
- 0
source/modules/dgl/src/pugl-upstream/include/pugl/gl.h View File

@@ -0,0 +1,107 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_GL_H
#define PUGL_GL_H

#include "pugl/pugl.h"

// IWYU pragma: begin_exports

/* Unfortunately, GL includes vary across platforms, so include them here to
enable pure portable programs. */

#ifndef PUGL_NO_INCLUDE_GL_H
# ifdef __APPLE__
# include <OpenGL/gl.h>
# else
# ifdef _WIN32
# include <windows.h>
# endif
# include <GL/gl.h>
# endif
#endif

#ifndef PUGL_NO_INCLUDE_GLU_H
# ifdef __APPLE__
# include <OpenGL/glu.h>
# else
# ifdef _WIN32
# include <windows.h>
# endif
# include <GL/glu.h>
# endif
#endif

// IWYU pragma: end_exports

PUGL_BEGIN_DECLS

/**
@defgroup gl OpenGL
OpenGL graphics support.
@ingroup pugl
@{
*/

/**
OpenGL extension function.
*/
typedef void (*PuglGlFunc)(void);

/**
Return the address of an OpenGL extension function.
*/
PUGL_API
PuglGlFunc
puglGetProcAddress(const char* name);

/**
Enter the OpenGL context.

This can be used to enter the graphics context in unusual situations, for
doing things like loading textures. Note that this must not be used for
drawing, which may only be done while processing an expose event.
*/
PUGL_API
PuglStatus
puglEnterContext(PuglView* view);

/**
Leave the OpenGL context.

This must only be called after puglEnterContext().
*/
PUGL_API
PuglStatus
puglLeaveContext(PuglView* view);

/**
OpenGL graphics backend.

Pass the returned value to puglSetBackend() to draw to a view with OpenGL.
*/
PUGL_CONST_API
const PuglBackend*
puglGlBackend(void);

PUGL_END_DECLS

/**
@}
*/

#endif // PUGL_GL_H

+ 1636
- 0
source/modules/dgl/src/pugl-upstream/include/pugl/pugl.h
File diff suppressed because it is too large
View File


+ 47
- 0
source/modules/dgl/src/pugl-upstream/include/pugl/stub.h View File

@@ -0,0 +1,47 @@
/*
Copyright 2019-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_STUB_H
#define PUGL_STUB_H

#include "pugl/pugl.h"

PUGL_BEGIN_DECLS

/**
@defgroup stub Stub
Native graphics support.
@ingroup pugl
@{
*/

/**
Stub graphics backend accessor.

This backend just creates a simple native window without setting up any
portable graphics API.
*/
PUGL_CONST_API
const PuglBackend*
puglStubBackend(void);

/**
@}
*/

PUGL_END_DECLS

#endif // PUGL_STUB_H

+ 156
- 0
source/modules/dgl/src/pugl-upstream/include/pugl/vulkan.h View File

@@ -0,0 +1,156 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/*
Note that this header includes Vulkan headers, so if you are writing a
program or plugin that dynamically loads vulkan, you should first define
`VK_NO_PROTOTYPES` before including it.
*/

#ifndef PUGL_VULKAN_H
#define PUGL_VULKAN_H

#include "pugl/pugl.h"

#include <vulkan/vulkan_core.h>

#include <stdint.h>

PUGL_BEGIN_DECLS

/**
@defgroup vulkan Vulkan
Vulkan graphics support.

Vulkan support differs from OpenGL because almost all most configuration is
done using the Vulkan API itself, rather than by setting view hints to
configure the context. Pugl only provides a minimal loader for loading the
Vulkan library, and a portable function to create a Vulkan surface for a
view, which hides the platform-specific implementation details.

@ingroup pugl
@{
*/

/**
Dynamic Vulkan loader.

This can be used to dynamically load the Vulkan library. Applications or
plugins should not link against the Vulkan library, but instead use this at
runtime. This ensures that things will work on as many systems as possible,
and allows errors to be handled gracefully.

This is not a "loader" in the sense of loading all the required Vulkan
functions (which is the application's responsibility), but just a minimal
implementation to portably load the Vulkan library and get the two functions
that are used to load everything else.

Note that this owns the loaded Vulkan library, so it must outlive all use of
the Vulkan API.

@see https://www.khronos.org/registry/vulkan/specs/1.0/html/chap4.html
*/
typedef struct PuglVulkanLoaderImpl PuglVulkanLoader;

/**
Create a new dynamic loader for Vulkan functions.

This dynamically loads the Vulkan library and gets the load functions from
it.

@return A new Vulkan loader, or null on failure.
*/
PUGL_API
PuglVulkanLoader*
puglNewVulkanLoader(PuglWorld* world);

/**
Free a loader created with puglNewVulkanLoader().

Note that this closes the Vulkan library, so no Vulkan objects or API may be
used after this is called.
*/
PUGL_API
void
puglFreeVulkanLoader(PuglVulkanLoader* loader);

/**
Return the `vkGetInstanceProcAddr` function.

@return Null if the Vulkan library does not contain this function (which is
unlikely and indicates a broken system).
*/
PUGL_API
PFN_vkGetInstanceProcAddr
puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader);

/**
Return the `vkGetDeviceProcAddr` function.

@return Null if the Vulkan library does not contain this function (which is
unlikely and indicates a broken system).
*/
PUGL_API
PFN_vkGetDeviceProcAddr
puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader);

/**
Return the Vulkan instance extensions required to draw to a PuglView.

This simply returns static strings, it does not access Vulkan or the window
system. The returned array always contains at least "VK_KHR_surface".

@param[out] count The number of extensions in the returned array.
@return An array of extension name strings.
*/
PUGL_API
const char* const*
puglGetInstanceExtensions(uint32_t* count);

/**
Create a Vulkan surface for a Pugl view.

@param vkGetInstanceProcAddr Accessor for Vulkan functions.
@param view The view the surface is to be displayed on.
@param instance The Vulkan instance.
@param allocator Vulkan allocation callbacks, may be NULL.
@param[out] surface Pointed to a newly created Vulkan surface.
@return `VK_SUCCESS` on success, or a Vulkan error code.
*/
PUGL_API
VkResult
puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr,
PuglView* view,
VkInstance instance,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface);

/**
Vulkan graphics backend.

Pass the returned value to puglSetBackend() to draw to a view with Vulkan.
*/
PUGL_CONST_API
const PuglBackend*
puglVulkanBackend(void);

/**
@}
*/

PUGL_END_DECLS

#endif // PUGL_VULKAN_H

+ 16
- 0
source/modules/dgl/src/pugl-upstream/src/.clang-tidy View File

@@ -0,0 +1,16 @@
Checks: >
*,
-*-uppercase-literal-suffix,
-*magic-numbers,
-altera-struct-pack-align,
-bugprone-reserved-identifier,
-cert-dcl37-c,
-cert-dcl51-cpp,
-cert-flp30-c,
-hicpp-multiway-paths-covered,
-hicpp-signed-bitwise,
-llvm-header-guard,
-llvmlibc-*,
-readability-function-cognitive-complexity,
FormatStyle: file
HeaderFilterRegex: 'pugl/.*'

+ 468
- 0
source/modules/dgl/src/pugl-upstream/src/implementation.c View File

@@ -0,0 +1,468 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "implementation.h"

#include "types.h"

#include "pugl/pugl.h"

#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

const char*
puglStrerror(const PuglStatus status)
{
// clang-format off
switch (status) {
case PUGL_SUCCESS: return "Success";
case PUGL_FAILURE: return "Non-fatal failure";
case PUGL_UNKNOWN_ERROR: return "Unknown system error";
case PUGL_BAD_BACKEND: return "Invalid or missing backend";
case PUGL_BAD_CONFIGURATION: return "Invalid view configuration";
case PUGL_BAD_PARAMETER: return "Invalid parameter";
case PUGL_BACKEND_FAILED: return "Backend initialisation failed";
case PUGL_REGISTRATION_FAILED: return "Class registration failed";
case PUGL_REALIZE_FAILED: return "View creation failed";
case PUGL_SET_FORMAT_FAILED: return "Failed to set pixel format";
case PUGL_CREATE_CONTEXT_FAILED: return "Failed to create drawing context";
case PUGL_UNSUPPORTED_TYPE: return "Unsupported data type";
}
// clang-format on

return "Unknown error";
}

void
puglSetString(char** dest, const char* string)
{
if (*dest != string) {
const size_t len = strlen(string);

*dest = (char*)realloc(*dest, len + 1);
strncpy(*dest, string, len + 1);
}
}

void
puglSetBlob(PuglBlob* const dest, const void* const data, const size_t len)
{
if (data) {
dest->len = len;
dest->data = realloc(dest->data, len + 1);
memcpy(dest->data, data, len);
((char*)dest->data)[len] = 0;
} else {
dest->len = 0;
dest->data = NULL;
}
}

static void
puglSetDefaultHints(PuglHints hints)
{
hints[PUGL_USE_COMPAT_PROFILE] = PUGL_TRUE;
hints[PUGL_CONTEXT_VERSION_MAJOR] = 2;
hints[PUGL_CONTEXT_VERSION_MINOR] = 0;
hints[PUGL_RED_BITS] = 8;
hints[PUGL_GREEN_BITS] = 8;
hints[PUGL_BLUE_BITS] = 8;
hints[PUGL_ALPHA_BITS] = 8;
hints[PUGL_DEPTH_BITS] = 0;
hints[PUGL_STENCIL_BITS] = 0;
hints[PUGL_SAMPLES] = 0;
hints[PUGL_DOUBLE_BUFFER] = PUGL_TRUE;
hints[PUGL_SWAP_INTERVAL] = PUGL_DONT_CARE;
hints[PUGL_RESIZABLE] = PUGL_FALSE;
hints[PUGL_IGNORE_KEY_REPEAT] = PUGL_FALSE;
hints[PUGL_REFRESH_RATE] = PUGL_DONT_CARE;
}

PuglWorld*
puglNewWorld(PuglWorldType type, PuglWorldFlags flags)
{
PuglWorld* world = (PuglWorld*)calloc(1, sizeof(PuglWorld));
if (!world || !(world->impl = puglInitWorldInternals(type, flags))) {
free(world);
return NULL;
}

world->startTime = puglGetTime(world);

puglSetString(&world->className, "Pugl");

return world;
}

void
puglFreeWorld(PuglWorld* const world)
{
puglFreeWorldInternals(world);
free(world->className);
free(world->views);
free(world);
}

void
puglSetWorldHandle(PuglWorld* world, PuglWorldHandle handle)
{
world->handle = handle;
}

PuglWorldHandle
puglGetWorldHandle(PuglWorld* world)
{
return world->handle;
}

PuglStatus
puglSetClassName(PuglWorld* const world, const char* const name)
{
puglSetString(&world->className, name);
return PUGL_SUCCESS;
}

PuglView*
puglNewView(PuglWorld* const world)
{
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
if (!view || !(view->impl = puglInitViewInternals())) {
free(view);
return NULL;
}

view->world = world;
view->minWidth = 1;
view->minHeight = 1;

puglSetDefaultHints(view->hints);

// Add to world view list
++world->numViews;
world->views =
(PuglView**)realloc(world->views, world->numViews * sizeof(PuglView*));

world->views[world->numViews - 1] = view;

return view;
}

void
puglFreeView(PuglView* view)
{
if (view->eventFunc && view->backend) {
puglDispatchSimpleEvent(view, PUGL_DESTROY);
}

// Remove from world view list
PuglWorld* world = view->world;
for (size_t i = 0; i < world->numViews; ++i) {
if (world->views[i] == view) {
if (i == world->numViews - 1) {
world->views[i] = NULL;
} else {
memmove(world->views + i,
world->views + i + 1,
sizeof(PuglView*) * (world->numViews - i - 1));
world->views[world->numViews - 1] = NULL;
}
--world->numViews;
}
}

free(view->title);
free(view->clipboard.data);
puglFreeViewInternals(view);
free(view);
}

PuglWorld*
puglGetWorld(PuglView* view)
{
return view->world;
}

PuglStatus
puglSetViewHint(PuglView* view, PuglViewHint hint, int value)
{
if (value == PUGL_DONT_CARE) {
switch (hint) {
case PUGL_USE_COMPAT_PROFILE:
case PUGL_USE_DEBUG_CONTEXT:
case PUGL_CONTEXT_VERSION_MAJOR:
case PUGL_CONTEXT_VERSION_MINOR:
case PUGL_SWAP_INTERVAL:
return PUGL_BAD_PARAMETER;
default:
break;
}
}

if (hint < PUGL_NUM_VIEW_HINTS) {
view->hints[hint] = value;
return PUGL_SUCCESS;
}

return PUGL_BAD_PARAMETER;
}

int
puglGetViewHint(const PuglView* view, PuglViewHint hint)
{
return (hint < PUGL_NUM_VIEW_HINTS) ? view->hints[hint] : PUGL_DONT_CARE;
}

PuglStatus
puglSetParentWindow(PuglView* view, PuglNativeView parent)
{
view->parent = parent;
return PUGL_SUCCESS;
}

PuglStatus
puglSetBackend(PuglView* view, const PuglBackend* backend)
{
view->backend = backend;
return PUGL_SUCCESS;
}

void
puglSetHandle(PuglView* view, PuglHandle handle)
{
view->handle = handle;
}

PuglHandle
puglGetHandle(PuglView* view)
{
return view->handle;
}

bool
puglGetVisible(const PuglView* view)
{
return view->visible;
}

PuglRect
puglGetFrame(const PuglView* view)
{
return view->frame;
}

void*
puglGetContext(PuglView* view)
{
return view->backend->getContext(view);
}

#ifndef PUGL_DISABLE_DEPRECATED

PuglStatus
puglPollEvents(PuglWorld* world, double timeout)
{
return puglUpdate(world, timeout);
}

PuglStatus
puglDispatchEvents(PuglWorld* world)
{
return puglUpdate(world, 0.0);
}

PuglStatus
puglShowWindow(PuglView* view)
{
return puglShow(view);
}

PuglStatus
puglHideWindow(PuglView* view)
{
return puglHide(view);
}

#endif

PuglStatus
puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc)
{
view->eventFunc = eventFunc;
return PUGL_SUCCESS;
}

/// Return the code point for buf, or the replacement character on error
uint32_t
puglDecodeUTF8(const uint8_t* buf)
{
#define FAIL_IF(cond) \
do { \
if (cond) \
return 0xFFFD; \
} while (0)

// http://en.wikipedia.org/wiki/UTF-8

if (buf[0] < 0x80) {
return buf[0];
}

if (buf[0] < 0xC2) {
return 0xFFFD;
}

if (buf[0] < 0xE0) {
FAIL_IF((buf[1] & 0xC0u) != 0x80);
return ((uint32_t)buf[0] << 6u) + buf[1] - 0x3080u;
}

if (buf[0] < 0xF0) {
FAIL_IF((buf[1] & 0xC0u) != 0x80);
FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0);
FAIL_IF((buf[2] & 0xC0u) != 0x80);
return ((uint32_t)buf[0] << 12u) + //
((uint32_t)buf[1] << 6u) + //
((uint32_t)buf[2] - 0xE2080u);
}

if (buf[0] < 0xF5) {
FAIL_IF((buf[1] & 0xC0u) != 0x80);
FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90);
FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90);
FAIL_IF((buf[2] & 0xC0u) != 0x80u);
FAIL_IF((buf[3] & 0xC0u) != 0x80u);
return (((uint32_t)buf[0] << 18u) + //
((uint32_t)buf[1] << 12u) + //
((uint32_t)buf[2] << 6u) + //
((uint32_t)buf[3] - 0x3C82080u));
}

return 0xFFFD;
}

static inline bool
puglMustConfigure(PuglView* view, const PuglConfigureEvent* configure)
{
return memcmp(configure, &view->lastConfigure, sizeof(PuglConfigureEvent));
}

void
puglDispatchSimpleEvent(PuglView* view, const PuglEventType type)
{
assert(type == PUGL_CREATE || type == PUGL_DESTROY || type == PUGL_MAP ||
type == PUGL_UNMAP || type == PUGL_UPDATE || type == PUGL_CLOSE ||
type == PUGL_LOOP_ENTER || type == PUGL_LOOP_LEAVE);

const PuglEvent event = {{type, 0}};
puglDispatchEvent(view, &event);
}

void
puglConfigure(PuglView* view, const PuglEvent* event)
{
assert(event->type == PUGL_CONFIGURE);

view->frame.x = event->configure.x;
view->frame.y = event->configure.y;
view->frame.width = event->configure.width;
view->frame.height = event->configure.height;

if (puglMustConfigure(view, &event->configure)) {
view->eventFunc(view, event);
view->lastConfigure = event->configure;
}
}

void
puglExpose(PuglView* view, const PuglEvent* event)
{
if (event->expose.width > 0.0 && event->expose.height > 0.0) {
view->eventFunc(view, event);
}
}

void
puglDispatchEvent(PuglView* view, const PuglEvent* event)
{
switch (event->type) {
case PUGL_NOTHING:
break;
case PUGL_CREATE:
case PUGL_DESTROY:
view->backend->enter(view, NULL);
view->eventFunc(view, event);
view->backend->leave(view, NULL);
break;
case PUGL_CONFIGURE:
if (puglMustConfigure(view, &event->configure)) {
view->backend->enter(view, NULL);
puglConfigure(view, event);
view->backend->leave(view, NULL);
}
break;
case PUGL_MAP:
if (!view->visible) {
view->visible = true;
view->eventFunc(view, event);
}
break;
case PUGL_UNMAP:
if (view->visible) {
view->visible = false;
view->eventFunc(view, event);
}
break;
case PUGL_EXPOSE:
view->backend->enter(view, &event->expose);
puglExpose(view, event);
view->backend->leave(view, &event->expose);
break;
default:
view->eventFunc(view, event);
}
}

const void*
puglGetInternalClipboard(const PuglView* const view,
const char** const type,
size_t* const len)
{
if (len) {
*len = view->clipboard.len;
}

if (type) {
*type = "text/plain";
}

return view->clipboard.data;
}

PuglStatus
puglSetInternalClipboard(PuglView* const view,
const char* const type,
const void* const data,
const size_t len)
{
if (type && !!strcmp(type, "text/plain")) {
return PUGL_UNSUPPORTED_TYPE;
}

puglSetBlob(&view->clipboard, data, len);
return PUGL_SUCCESS;
}

+ 86
- 0
source/modules/dgl/src/pugl-upstream/src/implementation.h View File

@@ -0,0 +1,86 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_IMPLEMENTATION_H
#define PUGL_IMPLEMENTATION_H

#include "types.h"

#include "pugl/pugl.h"

#include <stddef.h>
#include <stdint.h>

PUGL_BEGIN_DECLS

/// Set `blob` to `data` with length `len`, reallocating if necessary
void
puglSetBlob(PuglBlob* dest, const void* data, size_t len);

/// Reallocate and set `*dest` to `string`
void
puglSetString(char** dest, const char* string);

/// Allocate and initialise world internals (implemented once per platform)
PuglWorldInternals*
puglInitWorldInternals(PuglWorldType type, PuglWorldFlags flags);

/// Destroy and free world internals (implemented once per platform)
void
puglFreeWorldInternals(PuglWorld* world);

/// Allocate and initialise view internals (implemented once per platform)
PuglInternals*
puglInitViewInternals(void);

/// Destroy and free view internals (implemented once per platform)
void
puglFreeViewInternals(PuglView* view);

/// Return the Unicode code point for `buf` or the replacement character
uint32_t
puglDecodeUTF8(const uint8_t* buf);

/// Dispatch an event with a simple `type` to `view`
void
puglDispatchSimpleEvent(PuglView* view, PuglEventType type);

/// Process configure event while already in the graphics context
void
puglConfigure(PuglView* view, const PuglEvent* event);

/// Process expose event while already in the graphics context
void
puglExpose(PuglView* view, const PuglEvent* event);

/// Dispatch `event` to `view`, entering graphics context if necessary
void
puglDispatchEvent(PuglView* view, const PuglEvent* event);

/// Set internal (stored in view) clipboard contents
const void*
puglGetInternalClipboard(const PuglView* view, const char** type, size_t* len);

/// Set internal (stored in view) clipboard contents
PuglStatus
puglSetInternalClipboard(PuglView* view,
const char* type,
const void* data,
size_t len);

PUGL_END_DECLS

#endif // PUGL_IMPLEMENTATION_H

+ 55
- 0
source/modules/dgl/src/pugl-upstream/src/mac.h View File

@@ -0,0 +1,55 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>
Copyright 2017 Hanspeter Portner <dev@open-music-kontrollers.ch>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_DETAIL_MAC_H
#define PUGL_DETAIL_MAC_H

#include "pugl/pugl.h"

#import <Cocoa/Cocoa.h>

#include <stdint.h>

@interface PuglWrapperView : NSView<NSTextInputClient>

- (void)dispatchExpose:(NSRect)rect;
- (void)setReshaped;

@end

@interface PuglWindow : NSWindow

- (void)setPuglview:(PuglView*)view;

@end

struct PuglWorldInternalsImpl {
NSApplication* app;
NSAutoreleasePool* autoreleasePool;
};

struct PuglInternalsImpl {
NSApplication* app;
PuglWrapperView* wrapperView;
NSView* drawView;
NSCursor* cursor;
PuglWindow* window;
uint32_t mods;
bool mouseTracked;
};

#endif // PUGL_DETAIL_MAC_H

+ 1501
- 0
source/modules/dgl/src/pugl-upstream/src/mac.m
File diff suppressed because it is too large
View File


+ 160
- 0
source/modules/dgl/src/pugl-upstream/src/mac_cairo.m View File

@@ -0,0 +1,160 @@
/*
Copyright 2019-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "implementation.h"
#include "mac.h"
#include "stub.h"

#include "pugl/cairo.h"

#include <cairo-quartz.h>

#import <Cocoa/Cocoa.h>

#include <assert.h>

@interface PuglCairoView : NSView
@end

@implementation PuglCairoView {
@public
PuglView* puglview;
cairo_surface_t* surface;
cairo_t* cr;
}

- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];

return self;
}

- (void)resizeWithOldSuperviewSize:(NSSize)oldSize
{
PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];

[super resizeWithOldSuperviewSize:oldSize];
[wrapper setReshaped];
}

- (void)drawRect:(NSRect)rect
{
PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
[wrapper dispatchExpose:rect];
}

@end

static PuglStatus
puglMacCairoCreate(PuglView* view)
{
PuglInternals* impl = view->impl;
PuglCairoView* drawView = [PuglCairoView alloc];

drawView->puglview = view;
[drawView initWithFrame:[impl->wrapperView bounds]];
if (view->hints[PUGL_RESIZABLE]) {
[drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
} else {
[drawView setAutoresizingMask:NSViewNotSizable];
}

impl->drawView = drawView;
return PUGL_SUCCESS;
}

static PuglStatus
puglMacCairoDestroy(PuglView* view)
{
PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView;

[drawView removeFromSuperview];
[drawView release];

view->impl->drawView = nil;
return PUGL_SUCCESS;
}

static PuglStatus
puglMacCairoEnter(PuglView* view, const PuglExposeEvent* expose)
{
PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView;
if (!expose) {
return PUGL_SUCCESS;
}

assert(!drawView->surface);
assert(!drawView->cr);

const double scale = 1.0 / [[NSScreen mainScreen] backingScaleFactor];
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
const CGSize sizePx = {view->frame.width, view->frame.height};
const CGSize sizePt = CGContextConvertSizeToUserSpace(context, sizePx);

// Convert coordinates to standard Cairo space
CGContextTranslateCTM(context, 0.0, -sizePt.height);
CGContextScaleCTM(context, scale, -scale);

drawView->surface = cairo_quartz_surface_create_for_cg_context(
context, (unsigned)sizePx.width, (unsigned)sizePx.height);

drawView->cr = cairo_create(drawView->surface);

return PUGL_SUCCESS;
}

static PuglStatus
puglMacCairoLeave(PuglView* view, const PuglExposeEvent* expose)
{
PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView;
if (!expose) {
return PUGL_SUCCESS;
}

assert(drawView->surface);
assert(drawView->cr);

CGContextRef context = cairo_quartz_surface_get_cg_context(drawView->surface);

cairo_destroy(drawView->cr);
cairo_surface_destroy(drawView->surface);
drawView->cr = NULL;
drawView->surface = NULL;

CGContextFlush(context);

return PUGL_SUCCESS;
}

static void*
puglMacCairoGetContext(PuglView* view)
{
return ((PuglCairoView*)view->impl->drawView)->cr;
}

const PuglBackend*
puglCairoBackend(void)
{
static const PuglBackend backend = {puglStubConfigure,
puglMacCairoCreate,
puglMacCairoDestroy,
puglMacCairoEnter,
puglMacCairoLeave,
puglMacCairoGetContext};

return &backend;
}

+ 211
- 0
source/modules/dgl/src/pugl-upstream/src/mac_gl.m View File

@@ -0,0 +1,211 @@
/*
Copyright 2019-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "implementation.h"
#include "mac.h"
#include "stub.h"

#include "pugl/gl.h"

#ifndef __MAC_10_10
# define NSOpenGLProfileVersion4_1Core NSOpenGLProfileVersion3_2Core
#endif

@interface PuglOpenGLView : NSOpenGLView
@end

@implementation PuglOpenGLView {
@public
PuglView* puglview;
}

- (id)initWithFrame:(NSRect)frame
{
const bool compat = puglview->hints[PUGL_USE_COMPAT_PROFILE];
const unsigned samples = (unsigned)puglview->hints[PUGL_SAMPLES];
const int major = puglview->hints[PUGL_CONTEXT_VERSION_MAJOR];
const unsigned profile =
((compat || major < 3) ? NSOpenGLProfileVersionLegacy
: (major >= 4 ? NSOpenGLProfileVersion4_1Core
: NSOpenGLProfileVersion3_2Core));

// Set attributes to default if they are unset
// (There is no GLX_DONT_CARE equivalent on MacOS)
if (puglview->hints[PUGL_DEPTH_BITS] == PUGL_DONT_CARE) {
puglview->hints[PUGL_DEPTH_BITS] = 0;
}
if (puglview->hints[PUGL_STENCIL_BITS] == PUGL_DONT_CARE) {
puglview->hints[PUGL_STENCIL_BITS] = 0;
}
if (puglview->hints[PUGL_SAMPLES] == PUGL_DONT_CARE) {
puglview->hints[PUGL_SAMPLES] = 1;
}
if (puglview->hints[PUGL_DOUBLE_BUFFER] == PUGL_DONT_CARE) {
puglview->hints[PUGL_DOUBLE_BUFFER] = 1;
}
if (puglview->hints[PUGL_SWAP_INTERVAL] == PUGL_DONT_CARE) {
puglview->hints[PUGL_SWAP_INTERVAL] = 1;
}

const unsigned colorSize = (unsigned)(puglview->hints[PUGL_RED_BITS] +
puglview->hints[PUGL_BLUE_BITS] +
puglview->hints[PUGL_GREEN_BITS] +
puglview->hints[PUGL_ALPHA_BITS]);

// clang-format off
NSOpenGLPixelFormatAttribute pixelAttribs[17] = {
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAAccelerated,
NSOpenGLPFAOpenGLProfile, profile,
NSOpenGLPFAColorSize, colorSize,
NSOpenGLPFADepthSize, (unsigned)puglview->hints[PUGL_DEPTH_BITS],
NSOpenGLPFAStencilSize, (unsigned)puglview->hints[PUGL_STENCIL_BITS],
NSOpenGLPFAMultisample, samples ? 1u : 0u,
NSOpenGLPFASampleBuffers, samples ? 1u : 0u,
NSOpenGLPFASamples, samples,
0};
// clang-format on

NSOpenGLPixelFormat* pixelFormat =
[[NSOpenGLPixelFormat alloc] initWithAttributes:pixelAttribs];

if (pixelFormat) {
self = [super initWithFrame:frame pixelFormat:pixelFormat];
[pixelFormat release];
} else {
self = [super initWithFrame:frame];
}

[self setWantsBestResolutionOpenGLSurface:YES];

if (self) {
[[self openGLContext] makeCurrentContext];
[self reshape];
[NSOpenGLContext clearCurrentContext];
}
return self;
}

- (void)reshape
{
PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];

[super reshape];
[wrapper setReshaped];
}

- (void)drawRect:(NSRect)rect
{
PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
[wrapper dispatchExpose:rect];
}

@end

static PuglStatus
puglMacGlCreate(PuglView* view)
{
PuglInternals* impl = view->impl;
PuglOpenGLView* drawView = [PuglOpenGLView alloc];

drawView->puglview = view;
[drawView initWithFrame:[impl->wrapperView bounds]];
if (view->hints[PUGL_RESIZABLE]) {
[drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
} else {
[drawView setAutoresizingMask:NSViewNotSizable];
}

impl->drawView = drawView;
return PUGL_SUCCESS;
}

static PuglStatus
puglMacGlDestroy(PuglView* view)
{
PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView;

[drawView removeFromSuperview];
[drawView release];

view->impl->drawView = nil;
return PUGL_SUCCESS;
}

static PuglStatus
puglMacGlEnter(PuglView* view, const PuglExposeEvent* PUGL_UNUSED(expose))
{
PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView;

[[drawView openGLContext] makeCurrentContext];
return PUGL_SUCCESS;
}

static PuglStatus
puglMacGlLeave(PuglView* view, const PuglExposeEvent* expose)
{
PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView;

if (expose) {
[[drawView openGLContext] flushBuffer];
}

[NSOpenGLContext clearCurrentContext];

return PUGL_SUCCESS;
}

PuglGlFunc
puglGetProcAddress(const char* name)
{
CFBundleRef framework =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));

CFStringRef symbol = CFStringCreateWithCString(
kCFAllocatorDefault, name, kCFStringEncodingASCII);

PuglGlFunc func =
(PuglGlFunc)CFBundleGetFunctionPointerForName(framework, symbol);

CFRelease(symbol);

return func;
}

PuglStatus
puglEnterContext(PuglView* view)
{
return view->backend->enter(view, NULL);
}

PuglStatus
puglLeaveContext(PuglView* view)
{
return view->backend->leave(view, NULL);
}

const PuglBackend*
puglGlBackend(void)
{
static const PuglBackend backend = {puglStubConfigure,
puglMacGlCreate,
puglMacGlDestroy,
puglMacGlEnter,
puglMacGlLeave,
puglStubGetContext};

return &backend;
}

+ 92
- 0
source/modules/dgl/src/pugl-upstream/src/mac_stub.m View File

@@ -0,0 +1,92 @@
/*
Copyright 2019-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "implementation.h"
#include "mac.h"
#include "stub.h"

#include "pugl/stub.h"

#import <Cocoa/Cocoa.h>

@interface PuglStubView : NSView
@end

@implementation PuglStubView {
@public
PuglView* puglview;
}

- (void)resizeWithOldSuperviewSize:(NSSize)oldSize
{
PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];

[super resizeWithOldSuperviewSize:oldSize];
[wrapper setReshaped];
}

- (void)drawRect:(NSRect)rect
{
PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];

[wrapper dispatchExpose:rect];
}

@end

static PuglStatus
puglMacStubCreate(PuglView* view)
{
PuglInternals* impl = view->impl;
PuglStubView* drawView = [PuglStubView alloc];

drawView->puglview = view;
[drawView
initWithFrame:NSMakeRect(0, 0, view->frame.width, view->frame.height)];
if (view->hints[PUGL_RESIZABLE]) {
[drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
} else {
[drawView setAutoresizingMask:NSViewNotSizable];
}

impl->drawView = drawView;
return PUGL_SUCCESS;
}

static PuglStatus
puglMacStubDestroy(PuglView* view)
{
PuglStubView* const drawView = (PuglStubView*)view->impl->drawView;

[drawView removeFromSuperview];
[drawView release];

view->impl->drawView = nil;
return PUGL_SUCCESS;
}

const PuglBackend*
puglStubBackend(void)
{
static const PuglBackend backend = {puglStubConfigure,
puglMacStubCreate,
puglMacStubDestroy,
puglStubEnter,
puglStubLeave,
puglStubGetContext};

return &backend;
}

+ 211
- 0
source/modules/dgl/src/pugl-upstream/src/mac_vulkan.m View File

@@ -0,0 +1,211 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#define VK_NO_PROTOTYPES 1

#include "implementation.h"
#include "mac.h"
#include "stub.h"
#include "types.h"

#include "pugl/pugl.h"
#include "pugl/stub.h"
#include "pugl/vulkan.h"

#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_macos.h>

#import <Cocoa/Cocoa.h>
#import <QuartzCore/CAMetalLayer.h>

#include <dlfcn.h>

#include <stdint.h>
#include <stdlib.h>

@interface PuglVulkanView : NSView<CALayerDelegate>

@end

@implementation PuglVulkanView {
@public
PuglView* puglview;
}

- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];

if (self) {
self.wantsLayer = YES;
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
}

return self;
}

- (CALayer*)makeBackingLayer
{
CAMetalLayer* layer = [CAMetalLayer layer];
[layer setDelegate:self];
return layer;
}

- (void)setFrameSize:(NSSize)newSize
{
PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];

[super setFrameSize:newSize];
[wrapper setReshaped];

self.layer.frame = self.bounds;
}

- (void)displayLayer:(CALayer*)layer
{
(void)layer;
PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
[wrapper dispatchExpose:[self bounds]];
}

@end

static PuglStatus
puglMacVulkanCreate(PuglView* view)
{
PuglInternals* impl = view->impl;
PuglVulkanView* drawView = [PuglVulkanView alloc];
const NSRect rect = NSMakeRect(0, 0, view->frame.width, view->frame.height);

drawView->puglview = view;
[drawView initWithFrame:rect];
if (view->hints[PUGL_RESIZABLE]) {
[drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
} else {
[drawView setAutoresizingMask:NSViewNotSizable];
}

impl->drawView = drawView;
return PUGL_SUCCESS;
}

static PuglStatus
puglMacVulkanDestroy(PuglView* view)
{
PuglVulkanView* const drawView = (PuglVulkanView*)view->impl->drawView;

[drawView removeFromSuperview];
[drawView release];

view->impl->drawView = nil;
return PUGL_SUCCESS;
}

struct PuglVulkanLoaderImpl {
void* libvulkan;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
};

PuglVulkanLoader*
puglNewVulkanLoader(PuglWorld* PUGL_UNUSED(world))
{
PuglVulkanLoader* loader =
(PuglVulkanLoader*)calloc(1, sizeof(PuglVulkanLoader));
if (!loader) {
return NULL;
}

if (!(loader->libvulkan = dlopen("libvulkan.dylib", RTLD_LAZY))) {
free(loader);
return NULL;
}

loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(
loader->libvulkan, "vkGetInstanceProcAddr");

loader->vkGetDeviceProcAddr =
(PFN_vkGetDeviceProcAddr)dlsym(loader->libvulkan, "vkGetDeviceProcAddr");

return loader;
}

void
puglFreeVulkanLoader(PuglVulkanLoader* loader)
{
if (loader) {
dlclose(loader->libvulkan);
free(loader);
}
}

PFN_vkGetInstanceProcAddr
puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader)
{
return loader->vkGetInstanceProcAddr;
}

PFN_vkGetDeviceProcAddr
puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader)
{
return loader->vkGetDeviceProcAddr;
}

const PuglBackend*
puglVulkanBackend(void)
{
static const PuglBackend backend = {puglStubConfigure,
puglMacVulkanCreate,
puglMacVulkanDestroy,
puglStubEnter,
puglStubLeave,
puglStubGetContext};

return &backend;
}

const char* const*
puglGetInstanceExtensions(uint32_t* const count)
{
static const char* const extensions[] = {"VK_KHR_surface",
"VK_MVK_macos_surface"};

*count = 2;
return extensions;
}

VkResult
puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr,
PuglView* const view,
VkInstance instance,
const VkAllocationCallbacks* const allocator,
VkSurfaceKHR* const surface)
{
PuglInternals* const impl = view->impl;

PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK =
(PFN_vkCreateMacOSSurfaceMVK)vkGetInstanceProcAddr(
instance, "vkCreateMacOSSurfaceMVK");

const VkMacOSSurfaceCreateInfoMVK info = {
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK,
NULL,
0,
impl->drawView,
};

return vkCreateMacOSSurfaceMVK(instance, &info, allocator, surface);
}

+ 72
- 0
source/modules/dgl/src/pugl-upstream/src/stub.h View File

@@ -0,0 +1,72 @@
/*
Copyright 2012-2021 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_DETAIL_STUB_H
#define PUGL_DETAIL_STUB_H

#include "pugl/pugl.h"

#include <stddef.h>

PUGL_BEGIN_DECLS

static inline PuglStatus
puglStubConfigure(PuglView* const view)
{
(void)view;
return PUGL_SUCCESS;
}

static inline PuglStatus
puglStubCreate(PuglView* const view)
{
(void)view;
return PUGL_SUCCESS;
}

static inline PuglStatus
puglStubDestroy(PuglView* const view)
{
(void)view;
return PUGL_SUCCESS;
}

static inline PuglStatus
puglStubEnter(PuglView* const view, const PuglExposeEvent* const expose)
{
(void)view;
(void)expose;
return PUGL_SUCCESS;
}

static inline PuglStatus
puglStubLeave(PuglView* const view, const PuglExposeEvent* const expose)
{
(void)view;
(void)expose;
return PUGL_SUCCESS;
}

static inline void*
puglStubGetContext(PuglView* const view)
{
(void)view;
return NULL;
}

PUGL_END_DECLS

#endif // PUGL_DETAIL_STUB_H

+ 111
- 0
source/modules/dgl/src/pugl-upstream/src/types.h View File

@@ -0,0 +1,111 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_DETAIL_TYPES_H
#define PUGL_DETAIL_TYPES_H

#include "pugl/pugl.h"

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

// Unused parameter macro to suppresses warnings and make it impossible to use
#if defined(__cplusplus)
# define PUGL_UNUSED(name)
#elif defined(__GNUC__) || defined(__clang__)
# define PUGL_UNUSED(name) name##_unused __attribute__((__unused__))
#else
# define PUGL_UNUSED(name) name
#endif

/// Platform-specific world internals
typedef struct PuglWorldInternalsImpl PuglWorldInternals;

/// Platform-specific view internals
typedef struct PuglInternalsImpl PuglInternals;

/// View hints
typedef int PuglHints[PUGL_NUM_VIEW_HINTS];

/// Blob of arbitrary data
typedef struct {
void* data; ///< Dynamically allocated data
size_t len; ///< Length of data in bytes
} PuglBlob;

/// Cross-platform view definition
struct PuglViewImpl {
PuglWorld* world;
const PuglBackend* backend;
PuglInternals* impl;
PuglHandle handle;
PuglEventFunc eventFunc;
char* title;
PuglBlob clipboard;
PuglNativeView parent;
uintptr_t transientParent;
PuglRect frame;
PuglConfigureEvent lastConfigure;
PuglHints hints;
int defaultWidth;
int defaultHeight;
int minWidth;
int minHeight;
int maxWidth;
int maxHeight;
int minAspectX;
int minAspectY;
int maxAspectX;
int maxAspectY;
bool visible;
};

/// Cross-platform world definition
struct PuglWorldImpl {
PuglWorldInternals* impl;
PuglWorldHandle handle;
char* className;
double startTime;
size_t numViews;
PuglView** views;
};

/// Opaque surface used by graphics backend
typedef void PuglSurface;

/// Graphics backend interface
struct PuglBackendImpl {
/// Get visual information from display and setup view as necessary
PuglStatus (*configure)(PuglView*);

/// Create surface and drawing context
PuglStatus (*create)(PuglView*);

/// Destroy surface and drawing context
PuglStatus (*destroy)(PuglView*);

/// Enter drawing context, for drawing if expose is non-null
PuglStatus (*enter)(PuglView*, const PuglExposeEvent*);

/// Leave drawing context, after drawing if expose is non-null
PuglStatus (*leave)(PuglView*, const PuglExposeEvent*);

/// Return the puglGetContext() handle for the application, if any
void* (*getContext)(PuglView*);
};

#endif // PUGL_DETAIL_TYPES_H

+ 1295
- 0
source/modules/dgl/src/pugl-upstream/src/win.c
File diff suppressed because it is too large
View File


+ 68
- 0
source/modules/dgl/src/pugl-upstream/src/win.h View File

@@ -0,0 +1,68 @@
/*
Copyright 2012-2021 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_DETAIL_WIN_H
#define PUGL_DETAIL_WIN_H

#include "implementation.h"

#include "pugl/pugl.h"

#include <windows.h>

#include <stdbool.h>

typedef PIXELFORMATDESCRIPTOR PuglWinPFD;

struct PuglWorldInternalsImpl {
double timerFrequency;
};

struct PuglInternalsImpl {
PuglWinPFD pfd;
int pfId;
HWND hwnd;
HCURSOR cursor;
HDC hdc;
PuglSurface* surface;
bool flashing;
bool mouseTracked;
};

PUGL_API
PuglWinPFD
puglWinGetPixelFormatDescriptor(const PuglHints hints);

PUGL_API
PuglStatus
puglWinCreateWindow(PuglView* const view,
const char* const title,
HWND* const hwnd,
HDC* const hdc);

PUGL_API
PuglStatus
puglWinConfigure(PuglView* view);

PUGL_API
PuglStatus
puglWinEnter(PuglView* view, const PuglExposeEvent* expose);

PUGL_API
PuglStatus
puglWinLeave(PuglView* view, const PuglExposeEvent* expose);

#endif // PUGL_DETAIL_WIN_H

+ 178
- 0
source/modules/dgl/src/pugl-upstream/src/win_cairo.c View File

@@ -0,0 +1,178 @@
/*
Copyright 2012-2021 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "stub.h"
#include "types.h"
#include "win.h"

#include "pugl/cairo.h"

#include <cairo-win32.h>
#include <cairo.h>

#include <stdlib.h>

typedef struct {
cairo_surface_t* surface;
cairo_t* cr;
HDC drawDc;
HBITMAP drawBitmap;
} PuglWinCairoSurface;

static PuglStatus
puglWinCairoCreateDrawContext(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;

surface->drawDc = CreateCompatibleDC(impl->hdc);
surface->drawBitmap = CreateCompatibleBitmap(
impl->hdc, (int)view->frame.width, (int)view->frame.height);

DeleteObject(SelectObject(surface->drawDc, surface->drawBitmap));

return PUGL_SUCCESS;
}

static PuglStatus
puglWinCairoDestroyDrawContext(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;

DeleteDC(surface->drawDc);
DeleteObject(surface->drawBitmap);

surface->drawDc = NULL;
surface->drawBitmap = NULL;

return PUGL_SUCCESS;
}

static PuglStatus
puglWinCairoConfigure(PuglView* view)
{
const PuglStatus st = puglWinConfigure(view);

if (!st) {
view->impl->surface =
(PuglWinCairoSurface*)calloc(1, sizeof(PuglWinCairoSurface));
}

return st;
}

static void
puglWinCairoClose(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;

cairo_surface_destroy(surface->surface);

surface->surface = NULL;
}

static PuglStatus
puglWinCairoOpen(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;

if (!(surface->surface = cairo_win32_surface_create(surface->drawDc)) ||
cairo_surface_status(surface->surface) ||
!(surface->cr = cairo_create(surface->surface)) ||
cairo_status(surface->cr)) {
return PUGL_CREATE_CONTEXT_FAILED;
}

return PUGL_SUCCESS;
}

static PuglStatus
puglWinCairoDestroy(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;

puglWinCairoClose(view);
puglWinCairoDestroyDrawContext(view);
free(surface);
impl->surface = NULL;

return PUGL_SUCCESS;
}

static PuglStatus
puglWinCairoEnter(PuglView* view, const PuglExposeEvent* expose)
{
PuglStatus st = PUGL_SUCCESS;

if (expose && !(st = puglWinCairoCreateDrawContext(view)) &&
!(st = puglWinCairoOpen(view))) {
PAINTSTRUCT ps;
BeginPaint(view->impl->hwnd, &ps);
}

return st;
}

static PuglStatus
puglWinCairoLeave(PuglView* view, const PuglExposeEvent* expose)
{
PuglInternals* const impl = view->impl;
PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;

if (expose) {
cairo_surface_flush(surface->surface);
BitBlt(impl->hdc,
0,
0,
(int)view->frame.width,
(int)view->frame.height,
surface->drawDc,
0,
0,
SRCCOPY);

puglWinCairoClose(view);
puglWinCairoDestroyDrawContext(view);

PAINTSTRUCT ps;
EndPaint(view->impl->hwnd, &ps);
}

return PUGL_SUCCESS;
}

static void*
puglWinCairoGetContext(PuglView* view)
{
return ((PuglWinCairoSurface*)view->impl->surface)->cr;
}

const PuglBackend*
puglCairoBackend()
{
static const PuglBackend backend = {puglWinCairoConfigure,
puglStubCreate,
puglWinCairoDestroy,
puglWinCairoEnter,
puglWinCairoLeave,
puglWinCairoGetContext};

return &backend;
}

+ 333
- 0
source/modules/dgl/src/pugl-upstream/src/win_gl.c View File

@@ -0,0 +1,333 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "stub.h"
#include "types.h"
#include "win.h"

#include "pugl/gl.h"

#include <windows.h>

#include <GL/gl.h>

#include <stdbool.h>
#include <stdlib.h>

#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_RED_BITS_ARB 0x2015
#define WGL_GREEN_BITS_ARB 0x2017
#define WGL_BLUE_BITS_ARB 0x2019
#define WGL_ALPHA_BITS_ARB 0x201b
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_TYPE_RGBA_ARB 0x202b
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
#define WGL_SAMPLES_ARB 0x2042

#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define WGL_CONTEXT_FLAGS_ARB 0x2094
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126

#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001

typedef HGLRC(WINAPI* WglCreateContextAttribs)(HDC, HGLRC, const int*);

typedef BOOL(WINAPI* WglSwapInterval)(int);

typedef BOOL(WINAPI* WglChoosePixelFormat)(HDC,
const int*,
const FLOAT*,
UINT,
int*,
UINT*);

typedef struct {
WglChoosePixelFormat wglChoosePixelFormat;
WglCreateContextAttribs wglCreateContextAttribs;
WglSwapInterval wglSwapInterval;
} PuglWinGlProcs;

typedef struct {
PuglWinGlProcs procs;
HGLRC hglrc;
} PuglWinGlSurface;

// Struct to manage the fake window used during configuration
typedef struct {
HWND hwnd;
HDC hdc;
} PuglFakeWindow;

static PuglStatus
puglWinError(PuglFakeWindow* fakeWin, const PuglStatus status)
{
if (fakeWin->hwnd) {
ReleaseDC(fakeWin->hwnd, fakeWin->hdc);
DestroyWindow(fakeWin->hwnd);
}

return status;
}

static PuglWinGlProcs
puglWinGlGetProcs(void)
{
const PuglWinGlProcs procs = {
(WglChoosePixelFormat)(wglGetProcAddress("wglChoosePixelFormatARB")),
(WglCreateContextAttribs)(wglGetProcAddress("wglCreateContextAttribsARB")),
(WglSwapInterval)(wglGetProcAddress("wglSwapIntervalEXT"))};

return procs;
}

static PuglStatus
puglWinGlConfigure(PuglView* view)
{
PuglInternals* impl = view->impl;

// Set attributes to default if they are unset
// (There is no GLX_DONT_CARE equivalent on Windows)
if (view->hints[PUGL_DEPTH_BITS] == PUGL_DONT_CARE) {
view->hints[PUGL_DEPTH_BITS] = 0;
}
if (view->hints[PUGL_STENCIL_BITS] == PUGL_DONT_CARE) {
view->hints[PUGL_STENCIL_BITS] = 0;
}
if (view->hints[PUGL_SAMPLES] == PUGL_DONT_CARE) {
view->hints[PUGL_SAMPLES] = 1;
}
if (view->hints[PUGL_DOUBLE_BUFFER] == PUGL_DONT_CARE) {
view->hints[PUGL_DOUBLE_BUFFER] = 1;
}
if (view->hints[PUGL_SWAP_INTERVAL] == PUGL_DONT_CARE) {
view->hints[PUGL_SWAP_INTERVAL] = 1;
}

// clang-format off
const int pixelAttrs[] = {
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, view->hints[PUGL_DOUBLE_BUFFER],
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_SAMPLE_BUFFERS_ARB, view->hints[PUGL_SAMPLES] ? 1 : 0,
WGL_SAMPLES_ARB, view->hints[PUGL_SAMPLES],
WGL_RED_BITS_ARB, view->hints[PUGL_RED_BITS],
WGL_GREEN_BITS_ARB, view->hints[PUGL_GREEN_BITS],
WGL_BLUE_BITS_ARB, view->hints[PUGL_BLUE_BITS],
WGL_ALPHA_BITS_ARB, view->hints[PUGL_ALPHA_BITS],
WGL_DEPTH_BITS_ARB, view->hints[PUGL_DEPTH_BITS],
WGL_STENCIL_BITS_ARB, view->hints[PUGL_STENCIL_BITS],
0,
};
// clang-format on

PuglWinGlSurface* const surface =
(PuglWinGlSurface*)calloc(1, sizeof(PuglWinGlSurface));
impl->surface = surface;

// Create fake window for getting at GL context
PuglStatus st = PUGL_SUCCESS;
PuglFakeWindow fakeWin = {0, 0};
static const char* title = "Pugl Configuration";
if ((st = puglWinCreateWindow(view, title, &fakeWin.hwnd, &fakeWin.hdc))) {
return puglWinError(&fakeWin, st);
}

// Set pixel format for fake window
const PuglWinPFD fakePfd = puglWinGetPixelFormatDescriptor(view->hints);
const int fakePfId = ChoosePixelFormat(fakeWin.hdc, &fakePfd);
if (!fakePfId || !SetPixelFormat(fakeWin.hdc, fakePfId, &fakePfd)) {
return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED);
}

// Create fake GL context to get at the functions we need
HGLRC fakeRc = wglCreateContext(fakeWin.hdc);
if (!fakeRc) {
return puglWinError(&fakeWin, PUGL_CREATE_CONTEXT_FAILED);
}

// Enter fake context and get extension functions
wglMakeCurrent(fakeWin.hdc, fakeRc);
surface->procs = puglWinGlGetProcs();

if (surface->procs.wglChoosePixelFormat) {
// Choose pixel format based on attributes
UINT numFormats = 0;
if (!surface->procs.wglChoosePixelFormat(
fakeWin.hdc, pixelAttrs, NULL, 1u, &impl->pfId, &numFormats)) {
return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED);
}

DescribePixelFormat(impl->hdc, impl->pfId, sizeof(impl->pfd), &impl->pfd);
} else {
// Modern extensions not available, use basic pixel format
impl->pfd = fakePfd;
impl->pfId = fakePfId;
}

// Dispose of fake window and context
wglMakeCurrent(NULL, NULL);
wglDeleteContext(fakeRc);
ReleaseDC(fakeWin.hwnd, fakeWin.hdc);
DestroyWindow(fakeWin.hwnd);

return PUGL_SUCCESS;
}

static PuglStatus
puglWinGlCreate(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglWinGlSurface* const surface = (PuglWinGlSurface*)impl->surface;
PuglStatus st = PUGL_SUCCESS;

const int contextAttribs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB,
view->hints[PUGL_CONTEXT_VERSION_MAJOR],

WGL_CONTEXT_MINOR_VERSION_ARB,
view->hints[PUGL_CONTEXT_VERSION_MINOR],

WGL_CONTEXT_FLAGS_ARB,
(view->hints[PUGL_USE_DEBUG_CONTEXT] ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),

WGL_CONTEXT_PROFILE_MASK_ARB,
(view->hints[PUGL_USE_COMPAT_PROFILE]
? WGL_CONTEXT_CORE_PROFILE_BIT_ARB
: WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB),

0};

// Create real window with desired pixel format
if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) {
return st;
} else if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) {
ReleaseDC(impl->hwnd, impl->hdc);
DestroyWindow(impl->hwnd);
impl->hwnd = NULL;
impl->hdc = NULL;
return PUGL_SET_FORMAT_FAILED;
}

// Create GL context
if (surface->procs.wglCreateContextAttribs &&
!(surface->hglrc = surface->procs.wglCreateContextAttribs(
impl->hdc, 0, contextAttribs))) {
return PUGL_CREATE_CONTEXT_FAILED;
} else if (!(surface->hglrc = wglCreateContext(impl->hdc))) {
return PUGL_CREATE_CONTEXT_FAILED;
}

// Enter context and set swap interval
wglMakeCurrent(impl->hdc, surface->hglrc);
const int swapInterval = view->hints[PUGL_SWAP_INTERVAL];
if (surface->procs.wglSwapInterval && swapInterval != PUGL_DONT_CARE) {
surface->procs.wglSwapInterval(swapInterval);
}

return PUGL_SUCCESS;
}

static PuglStatus
puglWinGlDestroy(PuglView* view)
{
PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface;
if (surface) {
wglMakeCurrent(NULL, NULL);
wglDeleteContext(surface->hglrc);
free(surface);
view->impl->surface = NULL;
}

return PUGL_SUCCESS;
}

static PuglStatus
puglWinGlEnter(PuglView* view, const PuglExposeEvent* expose)
{
PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface;

wglMakeCurrent(view->impl->hdc, surface->hglrc);

if (expose) {
PAINTSTRUCT ps;
BeginPaint(view->impl->hwnd, &ps);
}

return PUGL_SUCCESS;
}

static PuglStatus
puglWinGlLeave(PuglView* view, const PuglExposeEvent* expose)
{
if (expose) {
PAINTSTRUCT ps;
EndPaint(view->impl->hwnd, &ps);
SwapBuffers(view->impl->hdc);
}

wglMakeCurrent(NULL, NULL);
return PUGL_SUCCESS;
}

PuglGlFunc
puglGetProcAddress(const char* name)
{
const PuglGlFunc func = (PuglGlFunc)wglGetProcAddress(name);

/* Windows has the annoying property that wglGetProcAddress returns NULL
for functions from OpenGL 1.1, so we fall back to pulling them directly
from opengl32.dll */

return func
? func
: (PuglGlFunc)GetProcAddress(GetModuleHandle("opengl32.dll"), name);
}

PuglStatus
puglEnterContext(PuglView* view)
{
return view->backend->enter(view, NULL);
}

PuglStatus
puglLeaveContext(PuglView* view)
{
return view->backend->leave(view, NULL);
}

const PuglBackend*
puglGlBackend(void)
{
static const PuglBackend backend = {puglWinGlConfigure,
puglWinGlCreate,
puglWinGlDestroy,
puglWinGlEnter,
puglWinGlLeave,
puglStubGetContext};

return &backend;
}

+ 52
- 0
source/modules/dgl/src/pugl-upstream/src/win_stub.c View File

@@ -0,0 +1,52 @@
/*
Copyright 2012-2021 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "stub.h"
#include "types.h"
#include "win.h"

#include "pugl/stub.h"

static PuglStatus
puglWinStubConfigure(PuglView* view)
{
return puglWinConfigure(view);
}

static PuglStatus
puglWinStubEnter(PuglView* view, const PuglExposeEvent* expose)
{
return puglWinEnter(view, expose);
}

static PuglStatus
puglWinStubLeave(PuglView* view, const PuglExposeEvent* expose)
{
return puglWinLeave(view, expose);
}

const PuglBackend*
puglStubBackend(void)
{
static const PuglBackend backend = {puglWinStubConfigure,
puglStubCreate,
puglStubDestroy,
puglWinStubEnter,
puglWinStubLeave,
puglStubGetContext};

return &backend;
}

+ 125
- 0
source/modules/dgl/src/pugl-upstream/src/win_vulkan.c View File

@@ -0,0 +1,125 @@
/*
Copyright 2012-2021 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#define VK_NO_PROTOTYPES 1

#include "stub.h"
#include "types.h"
#include "win.h"

#include "pugl/vulkan.h"

#include <vulkan/vulkan.h>
#include <vulkan/vulkan_win32.h>

#include <stdlib.h>

struct PuglVulkanLoaderImpl {
HMODULE libvulkan;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
};

PuglVulkanLoader*
puglNewVulkanLoader(PuglWorld* PUGL_UNUSED(world))
{
PuglVulkanLoader* loader =
(PuglVulkanLoader*)calloc(1, sizeof(PuglVulkanLoader));
if (!loader) {
return NULL;
}

if (!(loader->libvulkan = LoadLibrary("vulkan-1.dll"))) {
free(loader);
return NULL;
}

loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(
loader->libvulkan, "vkGetInstanceProcAddr");

loader->vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)GetProcAddress(
loader->libvulkan, "vkGetDeviceProcAddr");

return loader;
}

void
puglFreeVulkanLoader(PuglVulkanLoader* loader)
{
if (loader) {
FreeLibrary(loader->libvulkan);
free(loader);
}
}

PFN_vkGetInstanceProcAddr
puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader)
{
return loader->vkGetInstanceProcAddr;
}

PFN_vkGetDeviceProcAddr
puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader)
{
return loader->vkGetDeviceProcAddr;
}

const PuglBackend*
puglVulkanBackend()
{
static const PuglBackend backend = {puglWinConfigure,
puglStubCreate,
puglStubDestroy,
puglWinEnter,
puglWinLeave,
puglStubGetContext};

return &backend;
}

const char* const*
puglGetInstanceExtensions(uint32_t* const count)
{
static const char* const extensions[] = {"VK_KHR_surface",
"VK_KHR_win32_surface"};

*count = 2;
return extensions;
}

VkResult
puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr,
PuglView* const view,
VkInstance instance,
const VkAllocationCallbacks* const pAllocator,
VkSurfaceKHR* const pSurface)
{
PuglInternals* const impl = view->impl;

PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR =
(PFN_vkCreateWin32SurfaceKHR)vkGetInstanceProcAddr(
instance, "vkCreateWin32SurfaceKHR");

const VkWin32SurfaceCreateInfoKHR createInfo = {
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
NULL,
0,
GetModuleHandle(NULL),
impl->hwnd,
};

return vkCreateWin32SurfaceKHR(instance, &createInfo, pAllocator, pSurface);
}

+ 1498
- 0
source/modules/dgl/src/pugl-upstream/src/x11.c
File diff suppressed because it is too large
View File


+ 80
- 0
source/modules/dgl/src/pugl-upstream/src/x11.h View File

@@ -0,0 +1,80 @@
/*
Copyright 2012-2021 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef PUGL_DETAIL_X11_H
#define PUGL_DETAIL_X11_H

#include "types.h"

#include "pugl/pugl.h"

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

typedef struct {
Atom CLIPBOARD;
Atom UTF8_STRING;
Atom WM_PROTOCOLS;
Atom WM_DELETE_WINDOW;
Atom PUGL_CLIENT_MSG;
Atom NET_WM_NAME;
Atom NET_WM_STATE;
Atom NET_WM_STATE_DEMANDS_ATTENTION;
Atom NET_WM_STATE_HIDDEN;
} PuglX11Atoms;

typedef struct {
XID alarm;
PuglView* view;
uintptr_t id;
} PuglTimer;

struct PuglWorldInternalsImpl {
Display* display;
PuglX11Atoms atoms;
XIM xim;
PuglTimer* timers;
size_t numTimers;
XID serverTimeCounter;
int syncEventBase;
bool syncSupported;
bool dispatchingEvents;
};

struct PuglInternalsImpl {
Display* display;
XVisualInfo* vi;
Window win;
XIC xic;
PuglSurface* surface;
PuglEvent pendingConfigure;
PuglEvent pendingExpose;
int screen;
#ifdef HAVE_XCURSOR
const char* cursorName;
#endif
};

PUGL_API
PuglStatus
puglX11Configure(PuglView* view);

#endif // PUGL_DETAIL_X11_H

+ 160
- 0
source/modules/dgl/src/pugl-upstream/src/x11_cairo.c View File

@@ -0,0 +1,160 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "types.h"
#include "x11.h"

#include "pugl/cairo.h"
#include "pugl/pugl.h"

#include <X11/Xutil.h>
#include <cairo-xlib.h>
#include <cairo.h>

#include <stdlib.h>

typedef struct {
cairo_surface_t* back;
cairo_surface_t* front;
cairo_t* cr;
} PuglX11CairoSurface;

static void
puglX11CairoClose(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;

cairo_surface_destroy(surface->front);
cairo_surface_destroy(surface->back);
surface->front = surface->back = NULL;
}

static PuglStatus
puglX11CairoOpen(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;

surface->back = cairo_xlib_surface_create(impl->display,
impl->win,
impl->vi->visual,
(int)view->frame.width,
(int)view->frame.height);

surface->front =
cairo_surface_create_similar(surface->back,
cairo_surface_get_content(surface->back),
(int)view->frame.width,
(int)view->frame.height);

if (cairo_surface_status(surface->back) ||
cairo_surface_status(surface->front)) {
puglX11CairoClose(view);
return PUGL_CREATE_CONTEXT_FAILED;
}

return PUGL_SUCCESS;
}

static PuglStatus
puglX11CairoCreate(PuglView* view)
{
PuglInternals* const impl = view->impl;

impl->surface = (cairo_surface_t*)calloc(1, sizeof(PuglX11CairoSurface));

return PUGL_SUCCESS;
}

static PuglStatus
puglX11CairoDestroy(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;

puglX11CairoClose(view);
free(surface);

return PUGL_SUCCESS;
}

static PuglStatus
puglX11CairoEnter(PuglView* view, const PuglExposeEvent* expose)
{
PuglInternals* const impl = view->impl;
PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
PuglStatus st = PUGL_SUCCESS;

if (expose && !(st = puglX11CairoOpen(view))) {
surface->cr = cairo_create(surface->front);
st = cairo_status(surface->cr) ? PUGL_CREATE_CONTEXT_FAILED : PUGL_SUCCESS;
}

return st;
}

static PuglStatus
puglX11CairoLeave(PuglView* view, const PuglExposeEvent* expose)
{
PuglInternals* const impl = view->impl;
PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;

if (expose) {
// Destroy front context and create a new one for drawing to the back
cairo_destroy(surface->cr);
surface->cr = cairo_create(surface->back);

// Clip to expose region
cairo_rectangle(
surface->cr, expose->x, expose->y, expose->width, expose->height);
cairo_clip(surface->cr);

// Paint front onto back
cairo_set_source_surface(surface->cr, surface->front, 0, 0);
cairo_paint(surface->cr);

// Flush to X and close everything
cairo_destroy(surface->cr);
cairo_surface_flush(surface->back);
puglX11CairoClose(view);
surface->cr = NULL;
}

return PUGL_SUCCESS;
}

static void*
puglX11CairoGetContext(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;

return surface->cr;
}

const PuglBackend*
puglCairoBackend(void)
{
static const PuglBackend backend = {puglX11Configure,
puglX11CairoCreate,
puglX11CairoDestroy,
puglX11CairoEnter,
puglX11CairoLeave,
puglX11CairoGetContext};

return &backend;
}

+ 238
- 0
source/modules/dgl/src/pugl-upstream/src/x11_gl.c View File

@@ -0,0 +1,238 @@
/*
Copyright 2012-2020 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "stub.h"
#include "types.h"
#include "x11.h"

#include "pugl/gl.h"
#include "pugl/pugl.h"

#include <GL/glx.h>
#include <X11/X.h>
#include <X11/Xlib.h>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct {
GLXFBConfig fb_config;
GLXContext ctx;
} PuglX11GlSurface;

static int
puglX11GlHintValue(const int value)
{
return value == PUGL_DONT_CARE ? (int)GLX_DONT_CARE : value;
}

static int
puglX11GlGetAttrib(Display* const display,
GLXFBConfig fb_config,
const int attrib)
{
int value = 0;
glXGetFBConfigAttrib(display, fb_config, attrib, &value);
return value;
}

static PuglStatus
puglX11GlConfigure(PuglView* view)
{
PuglInternals* const impl = view->impl;
const int screen = impl->screen;
Display* const display = impl->display;

PuglX11GlSurface* const surface =
(PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface));
impl->surface = surface;

// clang-format off
const int attrs[] = {
#ifdef DGL_USE_RGBA
GLX_RGBA,
#endif
GLX_X_RENDERABLE, True,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_SAMPLES, puglX11GlHintValue(view->hints[PUGL_SAMPLES]),
GLX_RED_SIZE, puglX11GlHintValue(view->hints[PUGL_RED_BITS]),
GLX_GREEN_SIZE, puglX11GlHintValue(view->hints[PUGL_GREEN_BITS]),
GLX_BLUE_SIZE, puglX11GlHintValue(view->hints[PUGL_BLUE_BITS]),
GLX_ALPHA_SIZE, puglX11GlHintValue(view->hints[PUGL_ALPHA_BITS]),
GLX_DEPTH_SIZE, puglX11GlHintValue(view->hints[PUGL_DEPTH_BITS]),
GLX_STENCIL_SIZE, puglX11GlHintValue(view->hints[PUGL_STENCIL_BITS]),
GLX_DOUBLEBUFFER, puglX11GlHintValue(view->hints[PUGL_DOUBLE_BUFFER]),
None
};
// clang-format on

int n_fbc = 0;
GLXFBConfig* fbc = glXChooseFBConfig(display, screen, attrs, &n_fbc);
if (n_fbc <= 0) {
return PUGL_CREATE_CONTEXT_FAILED;
}

surface->fb_config = fbc[0];
impl->vi = glXGetVisualFromFBConfig(impl->display, fbc[0]);

view->hints[PUGL_RED_BITS] =
puglX11GlGetAttrib(display, fbc[0], GLX_RED_SIZE);
view->hints[PUGL_GREEN_BITS] =
puglX11GlGetAttrib(display, fbc[0], GLX_GREEN_SIZE);
view->hints[PUGL_BLUE_BITS] =
puglX11GlGetAttrib(display, fbc[0], GLX_BLUE_SIZE);
view->hints[PUGL_ALPHA_BITS] =
puglX11GlGetAttrib(display, fbc[0], GLX_ALPHA_SIZE);
view->hints[PUGL_DEPTH_BITS] =
puglX11GlGetAttrib(display, fbc[0], GLX_DEPTH_SIZE);
view->hints[PUGL_STENCIL_BITS] =
puglX11GlGetAttrib(display, fbc[0], GLX_STENCIL_SIZE);
view->hints[PUGL_SAMPLES] = puglX11GlGetAttrib(display, fbc[0], GLX_SAMPLES);
view->hints[PUGL_DOUBLE_BUFFER] =
puglX11GlGetAttrib(display, fbc[0], GLX_DOUBLEBUFFER);

XFree(fbc);

return PUGL_SUCCESS;
}

static PuglStatus
puglX11GlEnter(PuglView* view, const PuglExposeEvent* PUGL_UNUSED(expose))
{
PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
glXMakeCurrent(view->impl->display, view->impl->win, surface->ctx);
return PUGL_SUCCESS;
}

static PuglStatus
puglX11GlLeave(PuglView* view, const PuglExposeEvent* expose)
{
if (expose && view->hints[PUGL_DOUBLE_BUFFER]) {
glXSwapBuffers(view->impl->display, view->impl->win);
}

glXMakeCurrent(view->impl->display, None, NULL);

return PUGL_SUCCESS;
}

static PuglStatus
puglX11GlCreate(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglX11GlSurface* const surface = (PuglX11GlSurface*)impl->surface;
Display* const display = impl->display;
GLXFBConfig fb_config = surface->fb_config;

const int ctx_attrs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB,
view->hints[PUGL_CONTEXT_VERSION_MAJOR],

GLX_CONTEXT_MINOR_VERSION_ARB,
view->hints[PUGL_CONTEXT_VERSION_MINOR],

GLX_CONTEXT_FLAGS_ARB,
(view->hints[PUGL_USE_DEBUG_CONTEXT] ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),

GLX_CONTEXT_PROFILE_MASK_ARB,
(view->hints[PUGL_USE_COMPAT_PROFILE]
? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
: GLX_CONTEXT_CORE_PROFILE_BIT_ARB),
0};

PFNGLXCREATECONTEXTATTRIBSARBPROC create_context =
(PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress(
(const uint8_t*)"glXCreateContextAttribsARB");

PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT =
(PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress(
(const uint8_t*)"glXSwapIntervalEXT");

surface->ctx = create_context(display, fb_config, 0, True, ctx_attrs);
if (!surface->ctx) {
surface->ctx =
glXCreateNewContext(display, fb_config, GLX_RGBA_TYPE, 0, True);
}

if (!surface->ctx) {
return PUGL_CREATE_CONTEXT_FAILED;
}

const int swapInterval = view->hints[PUGL_SWAP_INTERVAL];
if (glXSwapIntervalEXT && swapInterval != PUGL_DONT_CARE) {
puglX11GlEnter(view, NULL);
glXSwapIntervalEXT(display, impl->win, swapInterval);
puglX11GlLeave(view, NULL);
}

glXGetConfig(impl->display,
impl->vi,
GLX_DOUBLEBUFFER,
&view->hints[PUGL_DOUBLE_BUFFER]);

glXQueryDrawable(display,
impl->win,
GLX_SWAP_INTERVAL_EXT,
(unsigned int*)&view->hints[PUGL_SWAP_INTERVAL]);

return PUGL_SUCCESS;
}

static PuglStatus
puglX11GlDestroy(PuglView* view)
{
PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
if (surface) {
glXDestroyContext(view->impl->display, surface->ctx);
free(surface);
view->impl->surface = NULL;
}
return PUGL_SUCCESS;
}

PuglGlFunc
puglGetProcAddress(const char* name)
{
return glXGetProcAddress((const uint8_t*)name);
}

PuglStatus
puglEnterContext(PuglView* view)
{
return view->backend->enter(view, NULL);
}

PuglStatus
puglLeaveContext(PuglView* view)
{
return view->backend->leave(view, NULL);
}

const PuglBackend*
puglGlBackend(void)
{
static const PuglBackend backend = {puglX11GlConfigure,
puglX11GlCreate,
puglX11GlDestroy,
puglX11GlEnter,
puglX11GlLeave,
puglStubGetContext};

return &backend;
}

+ 38
- 0
source/modules/dgl/src/pugl-upstream/src/x11_stub.c View File

@@ -0,0 +1,38 @@
/*
Copyright 2012-2021 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "pugl/stub.h"

#include "stub.h"
#include "types.h"
#include "x11.h"

#include "pugl/pugl.h"

const PuglBackend*
puglStubBackend(void)
{
static const PuglBackend backend = {
puglX11Configure,
puglStubCreate,
puglStubDestroy,
puglStubEnter,
puglStubLeave,
puglStubGetContext,
};

return &backend;
}

+ 127
- 0
source/modules/dgl/src/pugl-upstream/src/x11_vulkan.c View File

@@ -0,0 +1,127 @@
/*
Copyright 2012-2021 David Robillard <d@drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#define VK_NO_PROTOTYPES 1

#include "stub.h"
#include "types.h"
#include "x11.h"

#include "pugl/pugl.h"
#include "pugl/vulkan.h"

#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_xlib.h>

#include <dlfcn.h>

#include <stdint.h>
#include <stdlib.h>

struct PuglVulkanLoaderImpl {
void* libvulkan;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
};

PuglVulkanLoader*
puglNewVulkanLoader(PuglWorld* PUGL_UNUSED(world))
{
PuglVulkanLoader* const loader =
(PuglVulkanLoader*)calloc(1, sizeof(PuglVulkanLoader));

if (!loader || !(loader->libvulkan = dlopen("libvulkan.so", RTLD_LAZY))) {
free(loader);
return NULL;
}

loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(
loader->libvulkan, "vkGetInstanceProcAddr");

loader->vkGetDeviceProcAddr =
(PFN_vkGetDeviceProcAddr)dlsym(loader->libvulkan, "vkGetDeviceProcAddr");

return loader;
}

void
puglFreeVulkanLoader(PuglVulkanLoader* loader)
{
if (loader) {
dlclose(loader->libvulkan);
free(loader);
}
}

PFN_vkGetInstanceProcAddr
puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader)
{
return loader->vkGetInstanceProcAddr;
}

PFN_vkGetDeviceProcAddr
puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader)
{
return loader->vkGetDeviceProcAddr;
}

const PuglBackend*
puglVulkanBackend(void)
{
static const PuglBackend backend = {puglX11Configure,
puglStubCreate,
puglStubDestroy,
puglStubEnter,
puglStubLeave,
puglStubGetContext};

return &backend;
}

const char* const*
puglGetInstanceExtensions(uint32_t* const count)
{
static const char* const extensions[] = {"VK_KHR_surface",
"VK_KHR_xlib_surface"};

*count = 2;
return extensions;
}

VkResult
puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr,
PuglView* const view,
VkInstance instance,
const VkAllocationCallbacks* const allocator,
VkSurfaceKHR* const surface)
{
PuglInternals* const impl = view->impl;
PuglWorldInternals* world_impl = view->world->impl;

PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR =
(PFN_vkCreateXlibSurfaceKHR)vkGetInstanceProcAddr(instance,
"vkCreateXlibSurfaceKHR");

const VkXlibSurfaceCreateInfoKHR info = {
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
NULL,
0,
world_impl->display,
impl->win,
};

return vkCreateXlibSurfaceKHR(instance, &info, allocator, surface);
}

Loading…
Cancel
Save