From 650c7077f15fa7654d7cf0dca5e03ee05c6c0535 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 23 Mar 2012 14:29:25 +0100 Subject: [PATCH] Remove old output subsystem This subsystem is no longer used so remove it. Signed-off-by: David Herrmann --- Makefile.am | 3 - autogen.sh | 2 +- configure.ac | 21 +- src/gl_shader.c | 2 +- src/output.c | 1072 ------------------------------------------ src/output.h | 166 ------- src/output_context.c | 862 --------------------------------- src/output_math.c | 281 ----------- 8 files changed, 5 insertions(+), 2404 deletions(-) delete mode 100644 src/output.c delete mode 100644 src/output.h delete mode 100644 src/output_context.c delete mode 100644 src/output_math.c diff --git a/Makefile.am b/Makefile.am index 4c385dd..f39f692 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,9 +40,6 @@ nodist_libkmscon_core_la_SOURCES = \ libkmscon_core_la_SOURCES = \ src/misc.c src/misc.h \ src/console.c src/console.h \ - src/output.c src/output.h \ - src/output_context.c \ - src/output_math.c \ src/console_cell.c \ src/unicode.c src/unicode.h \ src/log.c src/log.h \ diff --git a/autogen.sh b/autogen.sh index aa4cc76..ce27d98 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,4 +1,4 @@ #!/bin/sh mkdir -p m4/ autoreconf -i -./configure --enable-debug --enable-gles2 $* +./configure --enable-debug $* diff --git a/configure.ac b/configure.ac index 32f1213..005e9b3 100644 --- a/configure.ac +++ b/configure.ac @@ -33,25 +33,12 @@ PKG_CHECK_MODULES([GBM], [gbm]) AC_SUBST(GBM_CFLAGS) AC_SUBST(GBM_LIBS) -AC_MSG_CHECKING([whether to use OpenGLES2 instead of OpenGL]) -AC_ARG_ENABLE([gles2], - [AS_HELP_STRING([--enable-gles2], [whether to use OpenGLES2 instead of OpenGL])], - [force_gles2="$enableval"; - AC_DEFINE([USE_GLES2], [1], [Define if OpenGLES2 should be used])], - [force_gles2=no]) -AC_MSG_RESULT([$force_gles2]) - -if test x$force_gles2 = xyes ; then - PKG_CHECK_MODULES([OPENGLES2], [glesv2]) - OPENGL_CFLAGS=$OPENGLES2_CFLAGS - OPENGL_LIBS=$OPENGLES2_LIBS -else - PKG_CHECK_MODULES([OPENGL], [gl]) -fi - +PKG_CHECK_MODULES([OPENGL], [glesv2]) AC_SUBST(OPENGL_CFLAGS) AC_SUBST(OPENGL_LIBS) +AC_DEFINE([UTERM_HAVE_DRM], [1], [Use DRM uterm backend]) + PKG_CHECK_MODULES([UDEV], [libudev]) AC_SUBST(UDEV_CFLAGS) AC_SUBST(UDEV_LIBS) @@ -120,7 +107,5 @@ else AC_DEFINE([LOG_ENABLE_DEBUG], [1], [Enable debug for log subsystem]) fi -AC_DEFINE([UTERM_HAVE_DRM], [1], [Use DRM uterm backend]) - AC_CONFIG_FILES([Makefile]) AC_OUTPUT([src/genshader.c]) diff --git a/src/gl_shader.c b/src/gl_shader.c index e9a3585..8bb319a 100644 --- a/src/gl_shader.c +++ b/src/gl_shader.c @@ -39,8 +39,8 @@ #include #include #include "gl.h" -#include "output.h" #include "log.h" +#include "uterm.h" #define LOG_SUBSYSTEM "gl" diff --git a/src/output.c b/src/output.c deleted file mode 100644 index 74e48c5..0000000 --- a/src/output.c +++ /dev/null @@ -1,1072 +0,0 @@ -/* - * kmscon - KMS/DRM output handling - * - * Copyright (c) 2011 David Herrmann - * Copyright (c) 2011 University of Tuebingen - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * KMS/DRM Output Handling - * This provides the compositor, output and mode objects and creates OpenGL - * contexts available for drawing directly to the graphics framebuffer. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "log.h" -#include "output.h" - -struct kmscon_mode { - size_t ref; - struct kmscon_mode *next; - struct kmscon_output *output; - - drmModeModeInfo info; -}; - -struct render_buffer { - struct gbm_bo *bo; - uint32_t fb; -}; - -struct kmscon_output { - size_t ref; - struct kmscon_output *next; - struct kmscon_compositor *comp; - - /* temporary flag used in compositor_refresh */ - unsigned int available : 1; - /* flag which indicates whether the output is connected */ - unsigned int connected : 1; - /* flag which indicates whether the output is active */ - unsigned int active : 1; - - size_t count_modes; - struct kmscon_mode *modes; - struct kmscon_mode *current; - struct kmscon_mode *def_mode; - - uint32_t conn_id; - uint32_t crtc_id; - - struct render_buffer rb[2]; - struct kmscon_framebuffer *fb; - - drmModeCrtcPtr saved_crtc; -}; - -enum compositor_state { - COMPOSITOR_ASLEEP, - COMPOSITOR_AWAKE, -}; - -struct kmscon_compositor { - size_t ref; - int state; - - size_t count_outputs; - struct kmscon_output *outputs; - - int drm_fd; - struct gbm_device *gbm; - struct kmscon_context *ctx; -}; - -/* - * Creates a new output mode. This mode is not bound to any output and all - * values are initialized to zero. - * Returns 0 on success and copies a pointer to the object into \out. - * Otherwise returns negative error code. - */ -int kmscon_mode_new(struct kmscon_mode **out) -{ - struct kmscon_mode *mode; - - if (!out) - return -EINVAL; - - mode = malloc(sizeof(*mode)); - if (!mode) - return -ENOMEM; - - memset(mode, 0, sizeof(*mode)); - mode->ref = 1; - - *out = mode; - return 0; -} - -void kmscon_mode_ref(struct kmscon_mode *mode) -{ - if (!mode) - return; - - ++mode->ref; -} - -void kmscon_mode_unref(struct kmscon_mode *mode) -{ - if (!mode || !mode->ref) - return; - - if (--mode->ref) - return; - - /* - * The mode is always unbound at this time, because mode_bind takes a - * reference and mode_unbind releases it. - */ - - free(mode); -} - -/* - * Binds the mode to an output. Even though this is called "mode"_bind, its the - * output object that owns the mode, not vice versa! - * The output object must go sure that it unbinds all modes before destroying - * itself. - * Binding a mode does not mean using it. This only links it into the list of - * available modes. The output must set the values of the mode directly. By - * default they are set to 0/NULL. - * Returns 0 on success or negative error code on failure. - */ -static int kmscon_mode_bind(struct kmscon_mode *mode, - struct kmscon_output *output) -{ - if (!mode || !output) - return -EINVAL; - - if (mode->output || mode->next) - return -EALREADY; - - mode->next = output->modes; - output->modes = mode; - ++output->count_modes; - - mode->output = output; - kmscon_mode_ref(mode); - - if (!output->def_mode) - output->def_mode = mode; - - return 0; -} - -/* - * This unbinds the mode from its output. If the mode is currently active, then - * this function will return -EBUSY. Otherwise it returns 0. - */ -static int kmscon_mode_unbind(struct kmscon_mode *mode) -{ - struct kmscon_mode *iter; - struct kmscon_output *output; - - if (!mode || !mode->output) - return 0; - - output = mode->output; - - if (output->current == mode) - return -EBUSY; - - if (output->modes == mode) { - output->modes = output->modes->next; - } else if (output->modes) { - for (iter = output->modes; iter->next; iter = iter->next) { - if (iter->next == mode) { - iter->next = mode->next; - break; - } - } - } - - mode->next = NULL; - mode->output = NULL; - --output->count_modes; - kmscon_mode_unref(mode); - - if (output->def_mode == mode) - output->def_mode = output->modes; - - return 0; -} - -struct kmscon_mode *kmscon_mode_next(struct kmscon_mode *mode) -{ - if (!mode) - return NULL; - - return mode->next; -} - -const char *kmscon_mode_get_name(const struct kmscon_mode *mode) -{ - if (!mode) - return NULL; - - return mode->info.name; -} - -uint32_t kmscon_mode_get_width(const struct kmscon_mode *mode) -{ - if (!mode) - return 0; - - return mode->info.hdisplay; -} - -uint32_t kmscon_mode_get_height(const struct kmscon_mode *mode) -{ - if (!mode) - return 0; - - return mode->info.vdisplay; -} - -/* - * Creates a new output object. The returned raw output object is useless - * unless you bind it to a compositor, connect it to the DRM and activate it. - * Returns 0 on success, otherwise a negative error code. - */ -int kmscon_output_new(struct kmscon_output **out) -{ - struct kmscon_output *output; - - if (!out) - return -EINVAL; - - log_debug("output: creating output object\n"); - - output = malloc(sizeof(*output)); - if (!output) - return -ENOMEM; - - memset(output, 0, sizeof(*output)); - output->ref = 1; - - *out = output; - return 0; -} - -void kmscon_output_ref(struct kmscon_output *output) -{ - if (!output) - return; - - ++output->ref; -} - -/* - * Drops a reference. All connected modes should already be removed when the - * output is unbound so no cleanup needs to be done here. - */ -void kmscon_output_unref(struct kmscon_output *output) -{ - if (!output || !output->ref) - return; - - if (--output->ref) - return; - - /* - * Output is already deactivated because output_bind takes - * a reference and output_unbind drops it. - * output->current is also NULL then. - */ - - free(output); - log_debug("output: destroying output object\n"); -} - -/* - * This binds the output to the given compositor. If the output is already - * bound, this will fail with -EALREADY. - * This only links the output into the list of available outputs, it does not - * activate the output or connect an crtc, nor does it create a framebuffer. - */ -static int kmscon_output_bind(struct kmscon_output *output, - struct kmscon_compositor *comp) -{ - if (!output || !comp) - return -EINVAL; - - if (output->comp || output->next) - return -EALREADY; - - output->next = comp->outputs; - comp->outputs = output; - ++comp->count_outputs; - - output->comp = comp; - kmscon_output_ref(output); - - return 0; -} - -/* - * This unbinds the output from its compositor. If the output is currently - * active, then it is deactivated first. The DRM connection is also removed so - * the object is quite useless now unless you reconnect it. - */ -static void kmscon_output_unbind(struct kmscon_output *output) -{ - struct kmscon_output *iter; - struct kmscon_compositor *comp; - - if (!output || !output->comp) - return; - - /* deactivate and disconnect the output */ - kmscon_output_deactivate(output); - output->connected = 0; - while (output->modes) - kmscon_mode_unbind(output->modes); - - comp = output->comp; - - if (comp->outputs == output) { - comp->outputs = comp->outputs->next; - } else if (comp->outputs) { - for (iter = comp->outputs; iter->next; iter = iter->next) { - if (iter->next == output) { - iter->next = output->next; - break; - } - } - } - - output->next = NULL; - output->comp = NULL; - --comp->count_outputs; - kmscon_output_unref(output); -} - -/* - * Finds an available unused crtc for the given encoder. Returns -1 if none is - * found. Otherwise returns the non-negative crtc id. - */ -static int32_t find_crtc(struct kmscon_compositor *comp, drmModeRes *res, - drmModeEncoder *enc) -{ - int i; - struct kmscon_output *iter; - uint32_t crtc = 0; - - for (i = 0; i < res->count_crtcs; ++i) { - if (enc->possible_crtcs & (1 << i)) { - crtc = res->crtcs[i]; - - /* check that the crtc is unused */ - for (iter = comp->outputs; iter; iter = iter->next) { - if (iter->connected && iter->crtc_id == crtc) - break; - } - - if (!iter) - break; - } - } - - if (i == res->count_crtcs) - return -1; - - return crtc; -} - -/* - * This connects the given output with the drm connector/crtc/encoder. This can - * only be called once on a bound output. It will fail if it is called again - * unless you unbind and rebind the object. - * If the given drm connector is invalid or cannot be initialized, then this - * function returns an appropriate negative error code. Returns 0 on success. - * - * This does not create any framebuffer or renderbuffers. It only reads the - * available data so the application can retrieve information about the output. - * The application can now activate and deactivate the output as often as it - * wants. - * - * This does not work if the bound compositor is asleep! - */ -static int kmscon_output_connect(struct kmscon_output *output, drmModeRes *res, - drmModeConnector *conn) -{ - struct kmscon_compositor *comp; - struct kmscon_mode *mode; - drmModeEncoder *enc; - int ret, i; - int32_t crtc = -1; - - if (!output || !output->comp || !conn->count_modes) - return -EINVAL; - - if (kmscon_compositor_is_asleep(output->comp)) - return -EINVAL; - - if (output->connected) - return -EALREADY; - - comp = output->comp; - - /* find unused crtc */ - for (i = 0; i < conn->count_encoders; ++i) { - enc = drmModeGetEncoder(comp->drm_fd, conn->encoders[i]); - if (!enc) - continue; - - crtc = find_crtc(comp, res, enc); - drmModeFreeEncoder(enc); - if (crtc >= 0) - break; - } - - if (crtc < 0) { - log_warn("output: no free CRTC left to connect output\n"); - return -EINVAL; - } - - /* copy all modes into the output modes-list */ - for (i = 0; i < conn->count_modes; ++i) { - ret = kmscon_mode_new(&mode); - if (ret) - continue; - - ret = kmscon_mode_bind(mode, output); - if (ret) { - kmscon_mode_unref(mode); - continue; - } - - mode->info = conn->modes[i]; - kmscon_mode_unref(mode); - } - - if (!output->count_modes) { - log_warn("output: no suitable mode available for output\n"); - return -EINVAL; - } - - output->conn_id = conn->connector_id; - output->crtc_id = crtc; - output->connected = 1; - - return 0; -} - -/* - * Returns true if the output is active and the related compositor is awake. - */ -bool kmscon_output_is_awake(struct kmscon_output *output) -{ - if (!output) - return NULL; - - return output->active && !kmscon_compositor_is_asleep(output->comp); -} - -/* - * Returns the next output in the list. If there is no next output or the - * output is not bound to any compositor, then it returns NULL. - * This does not take a reference of the next output nor drop a reference of - * the current output. - */ -struct kmscon_output *kmscon_output_next(struct kmscon_output *output) -{ - if (!output) - return NULL; - - return output->next; -} - -/* - * Returns the first entry in the list of available modes at this output. This - * does not take a reference of the returned mode so you shouldn't call unref - * on it unless you called *_ref earlier. - * Returns NULL if the list is empty. - */ -struct kmscon_mode *kmscon_output_get_modes(struct kmscon_output *output) -{ - if (!output) - return NULL; - - return output->modes; -} - -/* - * Returns a pointer to the currently used mode. Returns NULL if no mode is - * currently active. - */ -struct kmscon_mode *kmscon_output_get_current(struct kmscon_output *output) -{ - if (!output) - return NULL; - - return output->current; -} - -/* - * Returns a pointer to the default mode which will be used if no other mode is - * set explicitely. Returns NULL if no default mode is available. - */ -struct kmscon_mode *kmscon_output_get_default(struct kmscon_output *output) -{ - if (!output) - return NULL; - - return output->def_mode; -} - -static int init_rb(struct render_buffer *rb, struct kmscon_compositor *comp, - drmModeModeInfo *mode) -{ - int ret; - unsigned int stride, handle; - - rb->bo = gbm_bo_create(comp->gbm, mode->hdisplay, mode->vdisplay, - GBM_BO_FORMAT_XRGB8888, - GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - if (!rb->bo) { - log_warn("output: cannot create gbm buffer object\n"); - return -EFAULT; - } - - stride = gbm_bo_get_pitch(rb->bo); - handle = gbm_bo_get_handle(rb->bo).u32; - - /* - * TODO: Is there a way to choose 24/32 dynamically without hard-coding - * these values here? - */ - ret = drmModeAddFB(comp->drm_fd, mode->hdisplay, mode->vdisplay, - 24, 32, stride, handle, &rb->fb); - if (ret) { - log_warn("output: cannot add DRM framebuffer object\n"); - ret = -EFAULT; - goto err_bo; - } - - return 0; - -err_bo: - gbm_bo_destroy(rb->bo); - return ret; -} - -static void destroy_rb(struct render_buffer *rb, - struct kmscon_compositor *comp) -{ - drmModeRmFB(comp->drm_fd, rb->fb); - gbm_bo_destroy(rb->bo); -} - -/* - * This activates the output in the given mode. This returns -EALREADY if the - * output is already activated. To switch modes, deactivate and then reactivate - * the output. - * When the output is activated, its previous screen contents and mode are - * saved, to be restored when the output is deactivated. - * Returns 0 on success. - * This does not work if the compositor is asleep. - */ -int kmscon_output_activate(struct kmscon_output *output, - struct kmscon_mode *mode) -{ - struct kmscon_compositor *comp; - int ret; - - if (!output || !output->comp || !output->connected || !output->modes) - return -EINVAL; - - if (kmscon_compositor_is_asleep(output->comp)) - return -EINVAL; - - if (output->active) - return -EALREADY; - - if (!mode) - mode = output->def_mode; - - log_debug("output: activating output with res %ux%u\n", - mode->info.hdisplay, mode->info.vdisplay); - - comp = output->comp; - output->saved_crtc = drmModeGetCrtc(comp->drm_fd, output->crtc_id); - - ret = init_rb(&output->rb[0], comp, &mode->info); - if (ret) - goto err_saved; - - ret = init_rb(&output->rb[1], comp, &mode->info); - if (ret) { - destroy_rb(&output->rb[0], comp); - goto err_saved; - } - - output->current = mode; - output->active = 1; - - ret = kmscon_framebuffer_new(&output->fb, comp->ctx, output->rb[0].bo, - output->rb[1].bo); - if (ret) - goto err_rb; - - kmscon_context_viewport(output->comp->ctx, mode->info.hdisplay, - mode->info.vdisplay); - kmscon_context_clear(output->comp->ctx); - - ret = kmscon_output_swap(output); - if (ret) - goto err_fb; - - return 0; - -err_fb: - kmscon_framebuffer_destroy(output->fb); -err_rb: - destroy_rb(&output->rb[0], output->comp); - destroy_rb(&output->rb[1], output->comp); - output->active = 0; - output->current = NULL; -err_saved: - if (output->saved_crtc) { - drmModeFreeCrtc(output->saved_crtc); - output->saved_crtc = NULL; - } - - return ret; -} - -/* - * Deactivate the output. This does not disconnect the output so you can - * reactivate this output again. - * When the output is deactivated, the screen contents and mode it had before - * it was activated are restored. - */ -void kmscon_output_deactivate(struct kmscon_output *output) -{ - if (!output || !output->active) - return; - - if (output->saved_crtc) { - drmModeSetCrtc(output->comp->drm_fd, - output->saved_crtc->crtc_id, - output->saved_crtc->buffer_id, - output->saved_crtc->x, - output->saved_crtc->y, - &output->conn_id, - 1, - &output->saved_crtc->mode); - drmModeFreeCrtc(output->saved_crtc); - output->saved_crtc = NULL; - } - - kmscon_framebuffer_destroy(output->fb); - destroy_rb(&output->rb[0], output->comp); - destroy_rb(&output->rb[1], output->comp); - output->current = NULL; - output->active = 0; - log_debug("output: deactivated output\n"); -} - -/* - * Returns true if the output is currently active. Otherwise returns false. - */ -bool kmscon_output_is_active(struct kmscon_output *output) -{ - if (!output) - return false; - - return output->active; -} - -/* - * Binds the framebuffer of this output and sets a valid viewport so you can - * start drawing to this output. - * This does not work if the compositor is asleep. Returns 0 on success. - */ -int kmscon_output_use(struct kmscon_output *output) -{ - if (!output || !output->active) - return -EINVAL; - - if (kmscon_compositor_is_asleep(output->comp)) - return -EINVAL; - - kmscon_framebuffer_use(output->fb); - - return 0; -} - -/* - * This swaps the two renderbuffers and displays the new front buffer on the - * screen. This does not work if the compositor is asleep. - * This automatically binds the framebuffer of the output so you do not need to - * call kmscon_output_use after calling this even if another framebuffer was - * bound before. - * Returns 0 on success. - */ -int kmscon_output_swap(struct kmscon_output *output) -{ - int ret, num; - - if (!output || !output->active) - return -EINVAL; - - if (kmscon_compositor_is_asleep(output->comp)) - return -EINVAL; - - kmscon_context_flush(output->comp->ctx); - num = kmscon_framebuffer_swap(output->fb); - if (num < 0) - return num; - if (num > 1) - num = 1; - - num ^= 1; - ret = drmModeSetCrtc(output->comp->drm_fd, output->crtc_id, - output->rb[num].fb, 0, 0, &output->conn_id, 1, - &output->current->info); - if (ret) { - log_warn("output: cannot set CRTC\n"); - ret = -EFAULT; - } - - kmscon_context_viewport(output->comp->ctx, - output->current->info.hdisplay, - output->current->info.vdisplay); - kmscon_context_clear(output->comp->ctx); - - return ret; -} - -/* - * Create a new compositor object. A GL context is created but the - * compositor is asleep by default so no outputs are connected. - */ -int kmscon_compositor_new(struct kmscon_compositor **out) -{ - struct kmscon_compositor *comp; - int ret; - - if (!out) - return -EINVAL; - - log_debug("output: creating compositor\n"); - - comp = malloc(sizeof(*comp)); - if (!comp) - return -ENOMEM; - - memset(comp, 0, sizeof(*comp)); - comp->ref = 1; - comp->state = COMPOSITOR_ASLEEP; - - /* TODO: Retrieve this path dynamically */ - comp->drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); - if (comp->drm_fd < 0) { - log_warn("output: cannot open /dev/dri/card0: %m\n"); - ret = -errno; - goto err_free; - } - drmDropMaster(comp->drm_fd); - - comp->gbm = gbm_create_device(comp->drm_fd); - if (!comp->gbm) { - log_warn("output: cannot allocate gbm device\n"); - ret = -EFAULT; - goto err_drm; - } - - ret = kmscon_context_new(&comp->ctx, comp->gbm); - if (ret) - goto err_gbm; - - *out = comp; - return 0; - -err_gbm: - gbm_device_destroy(comp->gbm); -err_drm: - close(comp->drm_fd); -err_free: - free(comp); - return ret; -} - -void kmscon_compositor_ref(struct kmscon_compositor *comp) -{ - if (!comp) - return; - - ++comp->ref; -} - -/* - * Drops a compositor reference. This automatically disconnects all outputs if - * the last reference is dropped. - */ -void kmscon_compositor_unref(struct kmscon_compositor *comp) -{ - if (!comp || !comp->ref) - return; - - if (--comp->ref) - return; - - while (comp->outputs) - kmscon_output_unbind(comp->outputs); - - kmscon_context_destroy(comp->ctx); - gbm_device_destroy(comp->gbm); - close(comp->drm_fd); - free(comp); - log_debug("output: destroying compositor\n"); -} - -/* - * This puts the compositor asleep. While the compositor is asleep, no access - * to the DRM are made so other applications may use the DRM. - * You shouldn't access the compositor and its outputs while it is asleep as - * almost all functions will return -EINVAL while asleep. - */ -void kmscon_compositor_sleep(struct kmscon_compositor *comp) -{ - if (!comp) - return; - - log_debug("output: putting compositor asleep\n"); - comp->state = COMPOSITOR_ASLEEP; - drmDropMaster(comp->drm_fd); -} - -/* - * This wakes up the compositor. It automatically calls - * kmscon_compositor_refresh(). If this function fails, the compositor is kept - * asleep. - * Returns the number of detected outputs on success or a negative error code - * on failure. - */ -int kmscon_compositor_wake_up(struct kmscon_compositor *comp) -{ - int ret; - - if (!comp) - return -EINVAL; - - if (comp->state == COMPOSITOR_AWAKE) - return comp->count_outputs; - - log_debug("output: waking up compositor\n"); - - ret = drmSetMaster(comp->drm_fd); - if (ret) { - log_warn("output: cannot acquire DRM master privs\n"); - return -EACCES; - } - - comp->state = COMPOSITOR_AWAKE; - ret = kmscon_compositor_refresh(comp); - if (ret >= 0) - return ret; - - comp->state = COMPOSITOR_ASLEEP; - drmDropMaster(comp->drm_fd); - - return ret; -} - -/* - * Returns true if the compositor is asleep. Returns false if the compositor is - * awake. - */ -bool kmscon_compositor_is_asleep(struct kmscon_compositor *comp) -{ - if (!comp) - return false; - - return comp->state == COMPOSITOR_ASLEEP; -} - -/* - * This activates the EGL/GL context of this compositor. This works even if the - * compositor is asleep. Moreover, most other subsystems that need an GL context - * require this function to be called before they are used. - * - * You must call this before trying to enable outputs. A new compositor is not - * enabled by default. - * Returns 0 on success. - * - * If you have multiple compositors or GL contexts, you must take into account - * that only one context can be active at a time. It is not recommended to have - * different contexts in different threads. - */ -int kmscon_compositor_use(struct kmscon_compositor *comp) -{ - if (!comp) - return -EINVAL; - - return kmscon_context_use(comp->ctx); -} - -struct kmscon_context *kmscon_compositor_get_context( - struct kmscon_compositor *comp) -{ - if (!comp) - return NULL; - - return comp->ctx; -} - -/* - * Returns a pointer to the first output that is bound to the compositor. You - * can use kmscon_output_next() to iterate through the single linked list of - * outputs. - * Returns NULL if the list is empty or on failure. - * You do *NOT* own a reference to the returned output. If you want to keep the - * pointer you *MUST* call kmscon_output_ref() on it. Otherwise, you must not - * call kmscon_output_unref() on the returned object. - * This is because you are considered to own the compositor and guarantee that - * the compositor is not destroyed while you iterate the list. The compositor - * itself owns a reference of all its outputs so there is no need to increase - * this every time you iterate the list. - * - * This works even if the compositor is asleep. - */ -struct kmscon_output *kmscon_compositor_get_outputs( - struct kmscon_compositor *comp) -{ - if (!comp) - return NULL; - - return comp->outputs; -} - -static int add_output(struct kmscon_compositor *comp, drmModeRes *res, - drmModeConnector *conn) -{ - struct kmscon_output *output; - int ret; - - ret = kmscon_output_new(&output); - if (ret) - return ret; - - ret = kmscon_output_bind(output, comp); - if (ret) - goto err_unref; - - ret = kmscon_output_connect(output, res, conn); - if (ret) - goto err_unbind; - - output->available = 1; - kmscon_output_unref(output); - return 0; - -err_unbind: - kmscon_output_unbind(output); -err_unref: - kmscon_output_unref(output); - return ret; -} - -/* - * Refreshs the list of available outputs. This returns -EINVAL if the - * compositor is asleep. - * All currently connected outputs that are still available are left untouched. - * If an output is no longer available, it is disconnected and unbound from the - * compositor. You should no longer use it and drop all your references. - * - * New monitors are automatically added into the list of outputs and all - * available modes are added. The outputs are left deactivated, though. You - * should reiterate the output list and activate new outputs if you want - * hotplug support. - * - * Returns the number of available outputs on success and negative error code - * on failure. - */ -int kmscon_compositor_refresh(struct kmscon_compositor *comp) -{ - drmModeConnector *conn; - drmModeRes *res; - int i; - uint32_t cid; - struct kmscon_output *output, *tmp; - - if (!comp || comp->state != COMPOSITOR_AWAKE) - return -EINVAL; - - res = drmModeGetResources(comp->drm_fd); - if (!res) { - log_warn("output: cannot retrieve DRM resources\n"); - return -EACCES; - } - - for (output = comp->outputs; output; output = output->next) - output->available = 0; - - for (i = 0; i < res->count_connectors; ++i) { - cid = res->connectors[i]; - conn = drmModeGetConnector(comp->drm_fd, cid); - if (!conn) - continue; - - if (conn->connection == DRM_MODE_CONNECTED) { - for (output = comp->outputs; output; - output = output->next) { - if (output->conn_id == cid) { - output->available = 1; - break; - } - } - - if (!output) - add_output(comp, res, conn); - } - - drmModeFreeConnector(conn); - } - - drmModeFreeResources(res); - - for (output = comp->outputs; output; ) { - tmp = output; - output = output->next; - - if (tmp->available) - continue; - - kmscon_output_unbind(tmp); - } - - return comp->count_outputs; -} diff --git a/src/output.h b/src/output.h deleted file mode 100644 index 44f9169..0000000 --- a/src/output.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * kmscon - KMS/DRM output handling - * - * Copyright (c) 2011 David Herrmann - * Copyright (c) 2011 University of Tuebingen - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * KMS/DRM Output Handling - * This module provides a compositor object which manages the different outputs. - * Each output object belongs to a connected monitor. - * After creating a compositor object it will create a list of all available - * outputs. All outputs are disconnected by default. If you connect an - * output, a framebuffer with two renderbuffers is registered and you can start - * drawing to it using double-buffering. - * You can connect as many outputs as you want. - * - * To allow other applications to access the DRM you can put a compositor asleep - * and wake it up. When the compositor is asleep, the OpenGL context and - * framebuffers are still available, however, you cannot add or remove outputs - * unless the compositor is awake. You also cannot modify output modes or other - * output settings. It is recommended to avoid accessing the output objects at - * all as most of the functions simply return -EINVAL while being asleep. - * - * When waking up the compositor, it rereads all connected outputs. If a - * previously connected output has gone, it disconnects the output, removes - * the associated framebuffer and context and unbinds the output object from the - * compositor. If you own a reference to the output object, you should unref it - * now. - * You should also reread the output list for newly connected outputs. - * You can also force the compositor to reread all outputs if you noticed any - * monitor hotplugging (for instance via udev). - * - * An output may be used in different modes. Each output chooses one mode by - * default, however, you can always switch to another mode if you want another - * pixel-resolution, color-mode, etc. When switching modes, the current - * framebuffer is destroyed and a new one is created. - */ - -#ifndef KMSCON_OUTPUT_H -#define KMSCON_OUTPUT_H - -#include -#include -#include - -struct kmscon_mode; -struct kmscon_framebuffer; -struct kmscon_output; -struct kmscon_context; -struct kmscon_compositor; - -/* output modes */ - -int kmscon_mode_new(struct kmscon_mode **out); -void kmscon_mode_ref(struct kmscon_mode *mode); -void kmscon_mode_unref(struct kmscon_mode *mode); - -struct kmscon_mode *kmscon_mode_next(struct kmscon_mode *mode); -const char *kmscon_mode_get_name(const struct kmscon_mode *mode); -uint32_t kmscon_mode_get_width(const struct kmscon_mode *mode); -uint32_t kmscon_mode_get_height(const struct kmscon_mode *mode); - -/* framebuffer */ - -int kmscon_framebuffer_new(struct kmscon_framebuffer **out, - struct kmscon_context *ctx, void *bo1, void *bo2); -void kmscon_framebuffer_destroy(struct kmscon_framebuffer *fb); - -void kmscon_framebuffer_use(struct kmscon_framebuffer *fb); -int kmscon_framebuffer_swap(struct kmscon_framebuffer *fb); - -/* compositor outputs */ - -int kmscon_output_new(struct kmscon_output **out); -void kmscon_output_ref(struct kmscon_output *output); -void kmscon_output_unref(struct kmscon_output *output); - -bool kmscon_output_is_awake(struct kmscon_output *output); -struct kmscon_output *kmscon_output_next(struct kmscon_output *output); -struct kmscon_mode *kmscon_output_get_modes(struct kmscon_output *output); -struct kmscon_mode *kmscon_output_get_current(struct kmscon_output *output); -struct kmscon_mode *kmscon_output_get_default(struct kmscon_output *output); - -int kmscon_output_activate(struct kmscon_output *output, - struct kmscon_mode *mode); -void kmscon_output_deactivate(struct kmscon_output *output); -bool kmscon_output_is_active(struct kmscon_output *output); - -int kmscon_output_use(struct kmscon_output *output); -int kmscon_output_swap(struct kmscon_output *output); - -/* math helpers */ - -struct kmscon_m4_stack; - -void kmscon_m4_identity(float *m); -void kmscon_m4_copy(float *dest, const float *src); -void kmscon_m4_mult(float *n, const float *m); -void kmscon_m4_trans(float *m, float x, float y, float z); -void kmscon_m4_scale(float *m, float x, float y, float z); -void kmscon_m4_transp(float *m); -void kmscon_m4_transp_dest(float *dest, const float *src); - -int kmscon_m4_stack_new(struct kmscon_m4_stack **out); -void kmscon_m4_stack_free(struct kmscon_m4_stack *stack); -float *kmscon_m4_stack_push(struct kmscon_m4_stack *stack); -float *kmscon_m4_stack_pop(struct kmscon_m4_stack *stack); -float *kmscon_m4_stack_tip(struct kmscon_m4_stack *stack); - -/* drawing contexts */ - -int kmscon_context_new(struct kmscon_context **out, void *gbm); -void kmscon_context_destroy(struct kmscon_context *ctx); -int kmscon_context_use(struct kmscon_context *ctx); -bool kmscon_context_is_active(struct kmscon_context *ctx); -void kmscon_context_flush(struct kmscon_context *ctx); -void kmscon_context_viewport(struct kmscon_context *ctx, - unsigned int width, unsigned int height); -void kmscon_context_clear(struct kmscon_context *ctx); -void kmscon_context_draw_def(struct kmscon_context *ctx, float *vertices, - float *colors, size_t num); -void kmscon_context_draw_tex(struct kmscon_context *ctx, const float *vertices, - const float *texcoords, size_t num, unsigned int tex, const float *m); -unsigned int kmscon_context_new_tex(struct kmscon_context *ctx); -void kmscon_context_free_tex(struct kmscon_context *ctx, unsigned int tex); -void kmscon_context_set_tex(struct kmscon_context *ctx, unsigned int tex, - unsigned int width, unsigned int height, void *buf); - -/* compositors */ - -int kmscon_compositor_new(struct kmscon_compositor **out); -void kmscon_compositor_ref(struct kmscon_compositor *comp); -void kmscon_compositor_unref(struct kmscon_compositor *comp); - -void kmscon_compositor_sleep(struct kmscon_compositor *comp); -int kmscon_compositor_wake_up(struct kmscon_compositor *comp); -bool kmscon_compositor_is_asleep(struct kmscon_compositor *comp); -int kmscon_compositor_use(struct kmscon_compositor *comp); -struct kmscon_context *kmscon_compositor_get_context( - struct kmscon_compositor *comp); - -struct kmscon_output *kmscon_compositor_get_outputs( - struct kmscon_compositor *comp); -int kmscon_compositor_refresh(struct kmscon_compositor *comp); - -#endif /* KMSCON_OUTPUT_H */ diff --git a/src/output_context.c b/src/output_context.c deleted file mode 100644 index 96495a8..0000000 --- a/src/output_context.c +++ /dev/null @@ -1,862 +0,0 @@ -/* - * kmscon - Drawing Contexts - * - * Copyright (c) 2011 David Herrmann - * Copyright (c) 2011 University of Tuebingen - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Drawing Contexts - * This provides a drwaing context for compositor objects and associated - * framebuffers for output objects. It is implemented with OpenGL as backend. - */ - -#include -#include -#include -#include - -#include -#include - -#ifdef USE_GLES2 - #include - #include -#else - #include - #include -#endif - -#include "log.h" -#include "output.h" - -/* OpenGL extension definitions */ -typedef void (*PFNGLGENRENDERBUFFERSPROC) - (GLsizei n, GLuint *renderbuffers); -typedef void (*PFNGLBINDRENDERBUFFERPROC) - (GLenum target, GLuint renderbuffer); -typedef void (*PFNGLDELETERENDERBUFFERSPROC) - (GLsizei n, const GLuint *renderbuffers); - -typedef void (*PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, - GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef GLenum (*PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); -typedef void (*PFNGLGENFRAMEBUFFERSPROC) - (GLsizei n, GLuint *framebuffers); -typedef void (*PFNGLBINDFRAMEBUFFERPROC) - (GLenum target, GLuint framebuffer); -typedef void (*PFNGLDELETEFRAMEBUFFERSPROC) - (GLsizei n, const GLuint *framebuffers); - -typedef GLuint (*PFNGLCREATESHADERPROC) (GLenum type); -typedef void (*PFNGLDELETESHADERPROC) (GLuint shader); -typedef void (*PFNGLSHADERSOURCEPROC) (GLuint shader, - GLsizei count, const GLchar* *string, const GLint *length); -typedef void (*PFNGLCOMPILESHADERPROC) (GLuint shader); -typedef void (*PFNGLGETSHADERIVPROC) - (GLuint shader, GLenum pname, GLint *params); -typedef void (*PFNGLGETSHADERINFOLOGPROC) - (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); - -typedef GLuint (*PFNGLCREATEPROGRAMPROC) (void); -typedef void (*PFNGLDELETEPROGRAMPROC) (GLuint program); -typedef void (*PFNGLUSEPROGRAMPROC) (GLuint program); -typedef void (*PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); -typedef void (*PFNGLBINDATTRIBLOCATIONPROC) - (GLuint program, GLuint index, const GLchar *name); -typedef void (*PFNGLLINKPROGRAMPROC) (GLuint program); -typedef void (*PFNGLGETPROGRAMIVPROC) - (GLuint program, GLenum pname, GLint *params); -typedef void (*PFNGLGETPROGRAMINFOLOGPROC) - (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef GLint (*PFNGLGETUNIFORMLOCATIONPROC) - (GLuint program, const GLchar *name); -typedef void (*PFNGLUNIFORMMATRIX4FVPROC) (GLint location, - GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (*PFNGLUNIFORM1IPROC) (GLint location, GLint v0); -typedef void (*PFNGLVERTEXATTRIBPOINTERPROC) - (GLuint index, GLint size, GLenum type, GLboolean normalized, - GLsizei stride, const GLvoid *pointer); -typedef void (*PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (*PFNGLDRAWARRAYSEXTPROC) - (GLenum mode, GLint first, GLsizei count); - -struct kmscon_context { - EGLDisplay display; - EGLContext context; - - GLuint def_program; - GLuint def_vshader; - GLuint def_fshader; - GLuint def_uni_projection; - - GLuint tex_program; - GLuint tex_vshader; - GLuint tex_fshader; - GLuint tex_uni_projection; - GLuint tex_uni_texture; - - PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC proc_rbuf_storage; - PFNEGLCREATEIMAGEKHRPROC proc_create_image; - PFNEGLDESTROYIMAGEKHRPROC proc_destroy_image; - - PFNGLGENRENDERBUFFERSPROC proc_gen_renderbuffers; - PFNGLBINDRENDERBUFFERPROC proc_bind_renderbuffer; - PFNGLDELETERENDERBUFFERSPROC proc_delete_renderbuffers; - - PFNGLFRAMEBUFFERRENDERBUFFERPROC proc_framebuffer_renderbuffer; - PFNGLCHECKFRAMEBUFFERSTATUSPROC proc_check_framebuffer_status; - PFNGLGENFRAMEBUFFERSPROC proc_gen_framebuffers; - PFNGLBINDFRAMEBUFFERPROC proc_bind_framebuffer; - PFNGLDELETEFRAMEBUFFERSPROC proc_delete_framebuffers; - - PFNGLCREATESHADERPROC proc_create_shader; - PFNGLDELETESHADERPROC proc_delete_shader; - PFNGLSHADERSOURCEPROC proc_shader_source; - PFNGLCOMPILESHADERPROC proc_compile_shader; - PFNGLGETSHADERIVPROC proc_get_shader_iv; - PFNGLGETSHADERINFOLOGPROC proc_get_shader_info_log; - - PFNGLCREATEPROGRAMPROC proc_create_program; - PFNGLDELETEPROGRAMPROC proc_delete_program; - PFNGLUSEPROGRAMPROC proc_use_program; - PFNGLATTACHSHADERPROC proc_attach_shader; - PFNGLBINDATTRIBLOCATIONPROC proc_bind_attrib_location; - PFNGLLINKPROGRAMPROC proc_link_program; - PFNGLGETPROGRAMIVPROC proc_get_program_iv; - PFNGLGETPROGRAMINFOLOGPROC proc_get_program_info_log; - PFNGLGETUNIFORMLOCATIONPROC proc_get_uniform_location; - PFNGLUNIFORMMATRIX4FVPROC proc_uniform_matrix_4fv; - PFNGLUNIFORM1IPROC proc_uniform_1i; - PFNGLVERTEXATTRIBPOINTERPROC proc_vertex_attrib_pointer; - PFNGLENABLEVERTEXATTRIBARRAYPROC proc_enable_vertex_attrib_array; - PFNGLDRAWARRAYSEXTPROC proc_draw_arrays; -}; - -struct renderbuffer { - struct kmscon_context *ctx; - EGLImageKHR image; - GLuint rb; -}; - -struct kmscon_framebuffer { - struct kmscon_context *ctx; - GLuint fb; - struct renderbuffer *rbs[2]; - unsigned int current_rb; -}; - -/* - * Clear the GL error stack. The standard says that the error value is just a - * single value and no list/stack. However, multiple error fields may be defined - * and glGetError() returns only one of them until all are cleared. Hence, we - * loop until no more error is retrieved. - */ -static void clear_gl_error() -{ - GLenum err; - - do { - err = glGetError(); - } while (err != GL_NO_ERROR); -} - -/* return true if there is a pending GL error */ -static bool has_gl_error() -{ - GLenum err; - - err = glGetError(); - if (err != GL_NO_ERROR) { - log_err("context: GL error %d\n", err); - return true; - } - - return false; -} - -/* external shader sources; generated during build */ -extern const char *kmscon_vert_def; -extern const char *kmscon_frag_def; -extern const char *kmscon_vert_tex; -extern const char *kmscon_frag_tex; - -static int compile_shader(struct kmscon_context *ctx, GLenum type, - const char *source) -{ - char msg[512]; - GLint status = 1; - GLuint s; - - s = ctx->proc_create_shader(type); - if (s == GL_NONE) { - log_warn("context: cannot allocate GL shader\n"); - return GL_NONE; - } - - ctx->proc_shader_source(s, 1, &source, NULL); - ctx->proc_compile_shader(s); - - ctx->proc_get_shader_iv(s, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - msg[0] = 0; - ctx->proc_get_shader_info_log(s, sizeof(msg), NULL, msg); - log_warn("context: cannot compile shader: %s\n", msg); - return GL_NONE; - } - - return s; -} - -static int init_def_shader(struct kmscon_context *ctx) -{ - char msg[512]; - GLint status = 1; - int ret; - - if (!ctx) - return -EINVAL; - - ctx->def_vshader = compile_shader(ctx, GL_VERTEX_SHADER, - kmscon_vert_def); - if (ctx->def_vshader == GL_NONE) - return -EFAULT; - - ctx->def_fshader = compile_shader(ctx, GL_FRAGMENT_SHADER, - kmscon_frag_def); - if (ctx->def_fshader == GL_NONE) { - ret = -EFAULT; - goto err_vshader; - } - - ctx->def_program = ctx->proc_create_program(); - ctx->proc_attach_shader(ctx->def_program, ctx->def_vshader); - ctx->proc_attach_shader(ctx->def_program, ctx->def_fshader); - ctx->proc_bind_attrib_location(ctx->def_program, 0, "position"); - ctx->proc_bind_attrib_location(ctx->def_program, 1, "color"); - - ctx->proc_link_program(ctx->def_program); - ctx->proc_get_program_iv(ctx->def_program, GL_LINK_STATUS, &status); - if (status == GL_FALSE) { - msg[0] = 0; - ctx->proc_get_program_info_log(ctx->def_program, sizeof(msg), - NULL, msg); - log_warn("context: cannot link shader: %s\n", msg); - ret = -EFAULT; - goto err_link; - } - - ctx->def_uni_projection = - ctx->proc_get_uniform_location(ctx->def_program, "projection"); - - return 0; - -err_link: - ctx->proc_delete_program(ctx->def_program); - ctx->proc_delete_shader(ctx->def_fshader); -err_vshader: - ctx->proc_delete_shader(ctx->def_vshader); - return ret; -} - -static int init_tex_shader(struct kmscon_context *ctx) -{ - char msg[512]; - GLint status = 1; - int ret; - - if (!ctx) - return -EINVAL; - - ctx->tex_vshader = compile_shader(ctx, GL_VERTEX_SHADER, - kmscon_vert_tex); - if (ctx->tex_vshader == GL_NONE) - return -EFAULT; - - ctx->tex_fshader = compile_shader(ctx, GL_FRAGMENT_SHADER, - kmscon_frag_tex); - if (ctx->tex_fshader == GL_NONE) { - ret = -EFAULT; - goto err_vshader; - } - - ctx->tex_program = ctx->proc_create_program(); - ctx->proc_attach_shader(ctx->tex_program, ctx->tex_vshader); - ctx->proc_attach_shader(ctx->tex_program, ctx->tex_fshader); - ctx->proc_bind_attrib_location(ctx->tex_program, 0, "position"); - ctx->proc_bind_attrib_location(ctx->tex_program, 1, "texture_position"); - - ctx->proc_link_program(ctx->tex_program); - ctx->proc_get_program_iv(ctx->tex_program, GL_LINK_STATUS, &status); - if (status == GL_FALSE) { - msg[0] = 0; - ctx->proc_get_program_info_log(ctx->tex_program, sizeof(msg), - NULL, msg); - log_warn("context: cannot link shader: %s\n", msg); - ret = -EFAULT; - goto err_link; - } - - ctx->tex_uni_projection = - ctx->proc_get_uniform_location(ctx->tex_program, "projection"); - ctx->tex_uni_texture = - ctx->proc_get_uniform_location(ctx->tex_program, "texture"); - - return 0; - -err_link: - ctx->proc_delete_program(ctx->tex_program); - ctx->proc_delete_shader(ctx->tex_fshader); -err_vshader: - ctx->proc_delete_shader(ctx->tex_vshader); - return ret; -} - -static int init_shader(struct kmscon_context *ctx) -{ - int ret; - - ret = init_def_shader(ctx); - if (ret) - return ret; - - ret = init_tex_shader(ctx); - if (ret) { - ctx->proc_delete_program(ctx->def_program); - ctx->proc_delete_shader(ctx->def_fshader); - ctx->proc_delete_shader(ctx->def_vshader); - return ret; - } - - return 0; -} - -static void destroy_shader(struct kmscon_context *ctx) -{ - if (!ctx) - return; - - ctx->proc_delete_program(ctx->tex_program); - ctx->proc_delete_shader(ctx->tex_fshader); - ctx->proc_delete_shader(ctx->tex_vshader); - ctx->proc_delete_program(ctx->def_program); - ctx->proc_delete_shader(ctx->def_fshader); - ctx->proc_delete_shader(ctx->def_vshader); -} - -/* - * Create the GL context - * This uses the EGL library for context creation and needs a valid gbm device - * as argument. The caller must provide a valid gbm device as \gbm. We do not - * touch \gbm at all but pass it to EGL. The \gbm object must live as long as we - * do. - */ -int kmscon_context_new(struct kmscon_context **out, void *gbm) -{ - struct kmscon_context *ctx; - EGLint major, minor; - int ret; - const char *ext; - EGLenum api; - -#ifdef USE_GLES2 - static const EGLint ctx_attribs[] = - { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; -#else - static const EGLint *ctx_attribs = NULL; -#endif - - if (!out || !gbm) - return -EINVAL; - - log_debug("context: new GL context\n"); - - ctx = malloc(sizeof(*ctx)); - if (!ctx) - return -ENOMEM; - - memset(ctx, 0, sizeof(*ctx)); - - ctx->display = eglGetDisplay((EGLNativeDisplayType) gbm); - if (!ctx->display) { - log_warn("context: cannot get EGL display\n"); - ret = -EFAULT; - goto err_free; - } - - ret = eglInitialize(ctx->display, &major, &minor); - if (!ret) { - log_warn("context: cannot initialize EGL display\n"); - ret = -EFAULT; - goto err_free; - } - - ext = eglQueryString(ctx->display, EGL_EXTENSIONS); - if (!ext || !strstr(ext, "EGL_KHR_surfaceless_opengl")) { - log_warn("context: surfaceless EGL not supported\n"); - ret = -ENOTSUP; - goto err_display; - } - -#ifdef USE_GLES2 - api = EGL_OPENGL_ES_API; -#else - api = EGL_OPENGL_API; -#endif - - if (!eglBindAPI(api)) { - log_warn("context: cannot bind EGL OpenGL API\n"); - ret = -EFAULT; - goto err_display; - } - - ctx->context = eglCreateContext(ctx->display, NULL, EGL_NO_CONTEXT, - ctx_attribs); - if (!ctx->context) { - log_warn("context: cannot create EGL context\n"); - ret = -EFAULT; - goto err_display; - } - - if (!eglMakeCurrent(ctx->display, EGL_NO_SURFACE, EGL_NO_SURFACE, - ctx->context)) { - log_warn("context: cannot use EGL context\n"); - ret = -EFAULT; - goto err_ctx; - } - - ctx->proc_rbuf_storage = (void*) - eglGetProcAddress("glEGLImageTargetRenderbufferStorageOES"); - ctx->proc_create_image = - (void*) eglGetProcAddress("eglCreateImageKHR"); - ctx->proc_destroy_image = - (void*) eglGetProcAddress("eglDestroyImageKHR"); - ctx->proc_gen_renderbuffers = - (void*) eglGetProcAddress("glGenRenderbuffers"); - ctx->proc_bind_renderbuffer = - (void*) eglGetProcAddress("glBindRenderbuffer"); - ctx->proc_delete_renderbuffers = - (void*) eglGetProcAddress("glDeleteRenderbuffers"); - ctx->proc_framebuffer_renderbuffer = - (void*) eglGetProcAddress("glFramebufferRenderbuffer"); - ctx->proc_check_framebuffer_status = - (void*) eglGetProcAddress("glCheckFramebufferStatus"); - ctx->proc_gen_framebuffers = - (void*) eglGetProcAddress("glGenFramebuffers"); - ctx->proc_bind_framebuffer = - (void*) eglGetProcAddress("glBindFramebuffer"); - ctx->proc_delete_framebuffers = - (void*) eglGetProcAddress("glDeleteFramebuffers"); - - ctx->proc_create_shader = - (void*) eglGetProcAddress("glCreateShader"); - ctx->proc_delete_shader = - (void*) eglGetProcAddress("glDeleteShader"); - ctx->proc_shader_source = - (void*) eglGetProcAddress("glShaderSource"); - ctx->proc_compile_shader = - (void*) eglGetProcAddress("glCompileShader"); - ctx->proc_get_shader_iv = - (void*) eglGetProcAddress("glGetShaderiv"); - ctx->proc_get_shader_info_log = - (void*) eglGetProcAddress("glGetShaderInfoLog"); - - ctx->proc_create_program = - (void*) eglGetProcAddress("glCreateProgram"); - ctx->proc_delete_program = - (void*) eglGetProcAddress("glDeleteProgram"); - ctx->proc_use_program = - (void*) eglGetProcAddress("glUseProgram"); - ctx->proc_attach_shader = - (void*) eglGetProcAddress("glAttachShader"); - ctx->proc_bind_attrib_location = - (void*) eglGetProcAddress("glBindAttribLocation"); - ctx->proc_link_program = - (void*) eglGetProcAddress("glLinkProgram"); - ctx->proc_get_program_iv = - (void*) eglGetProcAddress("glGetProgramiv"); - ctx->proc_get_program_info_log = - (void*) eglGetProcAddress("glGetProgramInfoLog"); - ctx->proc_get_uniform_location = - (void*) eglGetProcAddress("glGetUniformLocation"); - ctx->proc_uniform_matrix_4fv = - (void*) eglGetProcAddress("glUniformMatrix4fv"); - ctx->proc_uniform_1i = - (void*) eglGetProcAddress("glUniform1i"); - ctx->proc_vertex_attrib_pointer = - (void*) eglGetProcAddress("glVertexAttribPointer"); - ctx->proc_enable_vertex_attrib_array = - (void*) eglGetProcAddress("glEnableVertexAttribArray"); - ctx->proc_draw_arrays = - (void*) eglGetProcAddress("glDrawArraysEXT"); - - if (!ctx->proc_rbuf_storage || !ctx->proc_create_image || - !ctx->proc_destroy_image) { - log_warn("context: KHR images not supported\n"); - ret = -ENOTSUP; - goto err_ctx; - } else if (!ctx->proc_gen_renderbuffers || - !ctx->proc_bind_renderbuffer || - !ctx->proc_delete_renderbuffers || - !ctx->proc_framebuffer_renderbuffer || - !ctx->proc_check_framebuffer_status) { - log_warn("context: renderbuffers not supported\n"); - ret = -ENOTSUP; - goto err_ctx; - } else if (!ctx->proc_create_shader || - !ctx->proc_delete_shader || - !ctx->proc_shader_source || - !ctx->proc_compile_shader || - !ctx->proc_get_shader_iv || - !ctx->proc_get_shader_info_log) { - log_warn("context: shaders not supported\n"); - ret = -ENOTSUP; - goto err_ctx; - } else if (!ctx->proc_create_program || - !ctx->proc_delete_program || - !ctx->proc_use_program || - !ctx->proc_attach_shader || - !ctx->proc_bind_attrib_location || - !ctx->proc_link_program || - !ctx->proc_get_program_iv || - !ctx->proc_get_program_info_log || - !ctx->proc_get_uniform_location || - !ctx->proc_uniform_matrix_4fv || - !ctx->proc_uniform_1i || - !ctx->proc_vertex_attrib_pointer || - !ctx->proc_enable_vertex_attrib_array || - !ctx->proc_draw_arrays) { - log_warn("context: shaders not supported\n"); - ret = -ENOTSUP; - goto err_ctx; - } - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - ret = init_shader(ctx); - if (ret) - goto err_ctx; - - *out = ctx; - return 0; - -err_ctx: - eglDestroyContext(ctx->display, ctx->context); -err_display: - eglTerminate(ctx->display); -err_free: - free(ctx); - return ret; -} - -void kmscon_context_destroy(struct kmscon_context *ctx) -{ - if (!ctx) - return; - - destroy_shader(ctx); - eglDestroyContext(ctx->display, ctx->context); - eglTerminate(ctx->display); - free(ctx); - log_debug("context: destroying GL context\n"); -} - -int kmscon_context_use(struct kmscon_context *ctx) -{ - if (!ctx) - return -EINVAL; - - if (!eglMakeCurrent(ctx->display, EGL_NO_SURFACE, EGL_NO_SURFACE, - ctx->context)) { - log_warn("context: cannot use EGL context\n"); - return -EFAULT; - } - - return 0; -} - -bool kmscon_context_is_active(struct kmscon_context *ctx) -{ - if (!ctx) - return false; - - return ctx->context == eglGetCurrentContext(); -} - -void kmscon_context_flush(struct kmscon_context *ctx) -{ - if (!ctx) - return; - - glFinish(); -} - -void kmscon_context_viewport(struct kmscon_context *ctx, - unsigned int width, unsigned int height) -{ - if (!ctx) - return; - - glViewport(0, 0, width, height); -} - -void kmscon_context_clear(struct kmscon_context *ctx) -{ - if (!ctx) - return; - - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); -} - -void kmscon_context_draw_def(struct kmscon_context *ctx, float *vertices, - float *colors, size_t num) -{ - float m[16] = { 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 }; - - if (!ctx) - return; - - ctx->proc_use_program(ctx->def_program); - ctx->proc_uniform_matrix_4fv(ctx->def_uni_projection, 1, GL_FALSE, m); - - ctx->proc_vertex_attrib_pointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices); - ctx->proc_vertex_attrib_pointer(1, 4, GL_FLOAT, GL_FALSE, 0, colors); - ctx->proc_enable_vertex_attrib_array(0); - ctx->proc_enable_vertex_attrib_array(1); - ctx->proc_draw_arrays(GL_TRIANGLES, 0, num); -} - -void kmscon_context_draw_tex(struct kmscon_context *ctx, const float *vertices, - const float *texcoords, size_t num, unsigned int tex, const float *m) -{ - float mat[16]; - - if (!ctx) - return; - - kmscon_m4_transp_dest(mat, m); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, tex); - - ctx->proc_use_program(ctx->tex_program); - ctx->proc_uniform_matrix_4fv(ctx->tex_uni_projection, 1, GL_FALSE, mat); - ctx->proc_uniform_1i(ctx->tex_uni_texture, 0); - - ctx->proc_vertex_attrib_pointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices); - ctx->proc_vertex_attrib_pointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoords); - ctx->proc_enable_vertex_attrib_array(0); - ctx->proc_enable_vertex_attrib_array(1); - ctx->proc_draw_arrays(GL_TRIANGLES, 0, num); -} - -unsigned int kmscon_context_new_tex(struct kmscon_context *ctx) -{ - GLuint tex = 0; - - if (!ctx) - return tex; - - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - return tex; -} - -void kmscon_context_free_tex(struct kmscon_context *ctx, unsigned int tex) -{ - if (!ctx) - return; - - glDeleteTextures(1, &tex); -} - -void kmscon_context_set_tex(struct kmscon_context *ctx, unsigned int tex, - unsigned int width, unsigned int height, void *buf) -{ - if (!ctx || !buf || !width || !height) - return; - - glBindTexture(GL_TEXTURE_2D, tex); -#ifdef USE_GLES2 - glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0, GL_BGRA_EXT, - GL_UNSIGNED_BYTE, buf); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, - GL_UNSIGNED_BYTE, buf); -#endif -} - -int renderbuffer_new(struct renderbuffer **out, struct kmscon_context *ctx, - void *bo) -{ - struct renderbuffer *rb; - int ret; - - if (!out || !ctx || !bo) - return -EINVAL; - - rb = malloc(sizeof(*rb)); - if (!rb) - return -ENOMEM; - - memset(rb, 0, sizeof(*rb)); - rb->ctx = ctx; - - clear_gl_error(); - - rb->image = ctx->proc_create_image(ctx->display, NULL, - EGL_NATIVE_PIXMAP_KHR, bo, NULL); - if (!rb->image) { - log_warn("context: cannot create EGL image\n"); - ret = -EFAULT; - goto err_free; - } - - ctx->proc_gen_renderbuffers(1, &rb->rb); - ctx->proc_bind_renderbuffer(GL_RENDERBUFFER, rb->rb); - ctx->proc_rbuf_storage(GL_RENDERBUFFER, rb->image); - - if (has_gl_error()) { - log_warn("context: cannot create renderbuffers\n"); - ret = -EFAULT; - goto err_gl; - } - - *out = rb; - return 0; - -err_gl: - ctx->proc_bind_renderbuffer(GL_RENDERBUFFER, 0); - ctx->proc_delete_renderbuffers(1, &rb->rb); - ctx->proc_destroy_image(ctx->display, rb->image); -err_free: - free(rb); - return ret; -} - -void renderbuffer_destroy(struct renderbuffer *rb) -{ - if (!rb) - return; - - rb->ctx->proc_bind_renderbuffer(GL_RENDERBUFFER, 0); - rb->ctx->proc_delete_renderbuffers(1, &rb->rb); - rb->ctx->proc_destroy_image(rb->ctx->display, rb->image); - free(rb); -} - -int kmscon_framebuffer_new(struct kmscon_framebuffer **out, - struct kmscon_context *ctx, void *bo1, void *bo2) -{ - struct kmscon_framebuffer *fb; - int ret; - - if (!out || !ctx || !bo1 || !bo2) - return -EINVAL; - - fb = malloc(sizeof(*fb)); - if (!fb) - return -ENOMEM; - - memset(fb, 0, sizeof(*fb)); - fb->ctx = ctx; - - ret = renderbuffer_new(&fb->rbs[0], ctx, bo1); - if (ret) - goto err_free; - - ret = renderbuffer_new(&fb->rbs[1], ctx, bo2); - if (ret) - goto err_rb; - - ctx->proc_gen_framebuffers(1, &fb->fb); - ctx->proc_bind_framebuffer(GL_FRAMEBUFFER, fb->fb); - ctx->proc_framebuffer_renderbuffer(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fb->rbs[0]->rb); - - if (ctx->proc_check_framebuffer_status(GL_FRAMEBUFFER) != - GL_FRAMEBUFFER_COMPLETE) { - log_warn("context: invalid GL framebuffer state\n"); - ret = -EFAULT; - goto err_fb; - } - - *out = fb; - return 0; - -err_fb: - ctx->proc_bind_framebuffer(GL_FRAMEBUFFER, 0); - ctx->proc_delete_framebuffers(1, &fb->fb); - renderbuffer_destroy(fb->rbs[1]); -err_rb: - renderbuffer_destroy(fb->rbs[0]); -err_free: - free(fb); - return ret; -} - -void kmscon_framebuffer_destroy(struct kmscon_framebuffer *fb) -{ - if (!fb) - return; - - fb->ctx->proc_bind_framebuffer(GL_FRAMEBUFFER, 0); - fb->ctx->proc_delete_framebuffers(1, &fb->fb); - renderbuffer_destroy(fb->rbs[1]); - renderbuffer_destroy(fb->rbs[0]); - free(fb); -} - -void kmscon_framebuffer_use(struct kmscon_framebuffer *fb) -{ - if (!fb) - return; - - fb->ctx->proc_bind_framebuffer(GL_FRAMEBUFFER, fb->fb); -} - -int kmscon_framebuffer_swap(struct kmscon_framebuffer *fb) -{ - if (!fb) - return -EINVAL; - - fb->current_rb ^= 1; - fb->ctx->proc_bind_framebuffer(GL_FRAMEBUFFER, fb->fb); - fb->ctx->proc_framebuffer_renderbuffer(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, - fb->rbs[fb->current_rb]->rb); - - if (fb->ctx->proc_check_framebuffer_status(GL_FRAMEBUFFER) != - GL_FRAMEBUFFER_COMPLETE) - log_warn("context: invalid GL framebuffer state\n"); - - return fb->current_rb; -} diff --git a/src/output_math.c b/src/output_math.c deleted file mode 100644 index 6020394..0000000 --- a/src/output_math.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * kmscon - Math Helper - * - * Copyright (c) 2011 David Herrmann - * Copyright (c) 2011 University of Tuebingen - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Math Helper - * Basic linear algebra. - */ - -#include -#include -#include - -#include "log.h" -#include "output.h" - -struct kmscon_m4_entry { - struct kmscon_m4_entry *next; - float matrix[16]; -}; - -struct kmscon_m4_stack { - struct kmscon_m4_entry stack; - struct kmscon_m4_entry *cache; -}; - -void kmscon_m4_identity(float *m) -{ - if (!m) - return; - - m[0] = 1; - m[1] = 0; - m[2] = 0; - m[3] = 0; - - m[4] = 0; - m[5] = 1; - m[6] = 0; - m[7] = 0; - - m[8] = 0; - m[9] = 0; - m[10] = 1; - m[11] = 0; - - m[12] = 0; - m[13] = 0; - m[14] = 0; - m[15] = 1; -} - -void kmscon_m4_copy(float *dest, const float *src) -{ - if (!dest || !src) - return; - - dest[0] = src[0]; - dest[1] = src[1]; - dest[2] = src[2]; - dest[3] = src[3]; - - dest[4] = src[4]; - dest[5] = src[5]; - dest[6] = src[6]; - dest[7] = src[7]; - - dest[8] = src[8]; - dest[9] = src[9]; - dest[10] = src[10]; - dest[11] = src[11]; - - dest[12] = src[12]; - dest[13] = src[13]; - dest[14] = src[14]; - dest[15] = src[15]; -} - -void kmscon_m4_mult(float *n, const float *m) -{ - float tmp[16]; - unsigned int row, col, j; - - for (row = 0; row < 4; ++row) { - for (col = 0; col < 4; ++col) { - tmp[row * 4 + col] = 0; - for (j = 0; j < 4; ++j) - tmp[row * 4 + col] += - n[row * 4 + j] * m[j * 4 + col]; - } - } - - kmscon_m4_copy(n, tmp); -} - -void kmscon_m4_trans(float *m, float x, float y, float z) -{ - float trans[16] = { 1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1 }; - - kmscon_m4_mult(m, trans); -} - -void kmscon_m4_scale(float *m, float x, float y, float z) -{ - float scale[16] = { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 }; - - kmscon_m4_mult(m, scale); -} - -void kmscon_m4_transp(float *m) -{ - float tmp; - - if (!m) - return; - - tmp = m[1]; - m[1] = m[4]; - m[4] = tmp; - - tmp = m[8]; - m[8] = m[2]; - m[2] = tmp; - - tmp = m[3]; - m[3] = m[12]; - m[12] = tmp; - - tmp = m[7]; - m[7] = m[13]; - m[13] = tmp; - - tmp = m[11]; - m[11] = m[14]; - m[14] = tmp; - - tmp = m[6]; - m[6] = m[9]; - m[9] = tmp; -} - -void kmscon_m4_transp_dest(float *dest, const float *src) -{ - if (!dest || !src) - return; - - dest[0] = src[0]; - dest[5] = src[5]; - dest[10] = src[10]; - dest[15] = src[15]; - - dest[1] = src[4]; - dest[4] = src[1]; - - dest[8] = src[2]; - dest[2] = src[8]; - - dest[3] = src[12]; - dest[12] = src[3]; - - dest[7] = src[13]; - dest[13] = src[7]; - - dest[11] = src[14]; - dest[14] = src[11]; - - dest[6] = src[9]; - dest[9] = src[6]; -} - -int kmscon_m4_stack_new(struct kmscon_m4_stack **out) -{ - struct kmscon_m4_stack *stack; - - if (!out) - return -EINVAL; - - stack = malloc(sizeof(*stack)); - if (!stack) - return -ENOMEM; - - memset(stack, 0, sizeof(*stack)); - kmscon_m4_identity(stack->stack.matrix); - - *out = stack; - return 0; -} - -void kmscon_m4_stack_free(struct kmscon_m4_stack *stack) -{ - struct kmscon_m4_entry *tmp; - - if (!stack) - return; - - while (stack->stack.next) { - tmp = stack->stack.next; - stack->stack.next = tmp->next; - free(tmp); - } - - while (stack->cache) { - tmp = stack->cache; - stack->cache = tmp->next; - free(tmp); - } - - free(stack); -} - -float *kmscon_m4_stack_push(struct kmscon_m4_stack *stack) -{ - struct kmscon_m4_entry *entry; - - if (stack->cache) { - entry = stack->cache; - stack->cache = entry->next; - } else { - entry = malloc(sizeof(*entry)); - if (!entry) - return NULL; - } - - kmscon_m4_copy(entry->matrix, stack->stack.matrix); - entry->next = stack->stack.next; - stack->stack.next = entry; - - return stack->stack.matrix; -} - -float *kmscon_m4_stack_pop(struct kmscon_m4_stack *stack) -{ - struct kmscon_m4_entry *entry; - - if (!stack) - return NULL; - - entry = stack->stack.next; - if (!entry) { - kmscon_m4_identity(stack->stack.matrix); - return stack->stack.matrix; - } - - stack->stack.next = entry->next; - entry->next = stack->cache; - stack->cache = entry; - - kmscon_m4_copy(stack->stack.matrix, entry->matrix); - - return stack->stack.matrix; -} - -float *kmscon_m4_stack_tip(struct kmscon_m4_stack *stack) -{ - if (!stack) - return NULL; - - return stack->stack.matrix; -}