void
S9xGTKDisplayDriver::update (int width, int height)
{
    int           x, y, w, h;
    int           c_width, c_height, final_pitch, width2, height2;
    uint8         *final_buffer1, *final_buffer2;
    GtkAllocation allocation;
    width2=width;
    height2=height;
    gtk_widget_get_allocation (drawing_area, &allocation);
    c_width = allocation.width;
    c_height = allocation.height;

    if (width == SIZE_FLAG_DIRTY)
    {
        this->clear ();
        return;
    }

    if (width <= 0)
        return;
    
    if (config->scale_method > 0)
    {
        uint8 *src_buffer1 = (uint8 *) padded_buffer1[0];
        uint8 *dst_buffer1 = (uint8 *) padded_buffer1[1];
        uint8 *src_buffer2 = (uint8 *) padded_buffer2[0];
        uint8 *dst_buffer2 = (uint8 *) padded_buffer2[1];
        int   src_pitch = image_width * image_bpp;
        int   dst_pitch = scaled_max_width * image_bpp;

        S9xFilter (src_buffer1,
                   src_pitch,
                   dst_buffer1,
                   dst_pitch,
                   width,
                   height);
       S9xFilter (src_buffer2,
                   src_pitch,
                   dst_buffer2,
                   dst_pitch,
                   width2,
                   height2);
        final_buffer1 = (uint8 *) padded_buffer1[1];
        final_buffer2 = (uint8 *) padded_buffer2[1];
        final_pitch = dst_pitch;
    }
    else
    {
        final_buffer1 = (uint8 *) padded_buffer1[0];
        final_buffer2 = (uint8 *) padded_buffer2[0];
        final_pitch = image_width * image_bpp;
    }
    x = width; y = height; w = c_width; h = c_height;
    S9xApplyAspect (x, y, w, h);
    output (final_buffer1, final_buffer2, final_pitch, x, y, width, height, w, h);

    return;
}
void
S9xGTKDisplayDriver::update (int width, int height, int yoffset)
{
    int           x, y, w, h;
    int           final_pitch;
    uint8         *final_buffer;
    GtkAllocation allocation;

    if (width <= 0)
        return;

    gtk_widget_get_allocation (drawing_area, &allocation);

    if (config->scale_method > 0)
    {
        uint8 *src_buffer = (uint8 *) padded_buffer[0];
        uint8 *dst_buffer = (uint8 *) padded_buffer[1];
        int   src_pitch = image_width * image_bpp;
        int   dst_pitch = scaled_max_width * image_bpp;

        src_buffer += (src_pitch * yoffset);

        S9xFilter (src_buffer,
                   src_pitch,
                   dst_buffer,
                   dst_pitch,
                   width,
                   height);

        final_buffer = (uint8 *) padded_buffer[1];
        final_pitch = dst_pitch;
    }
    else
    {
        final_buffer = (uint8 *) padded_buffer[0];
        final_pitch = image_width * image_bpp;
        final_buffer += (final_pitch * yoffset);
    }

    x = width; y = height; w = allocation.width; h = allocation.height;
    S9xApplyAspect (x, y, w, h);

    output (final_buffer, final_pitch, x, y, width, height, w, h);
}
void S9xOpenGLDisplayDriver::update (int width, int height, int yoffset)
{
    uint8 *final_buffer = NULL;
    int   final_pitch;
    void  *pbo_map = NULL;
    int   x, y, w, h;

    GtkAllocation allocation;
    gtk_widget_get_allocation (drawing_area, &allocation);

    if (output_window_width  != allocation.width ||
        output_window_height != allocation.height)
    {
        resize ();
    }

#if GTK_CHECK_VERSION(3,10,0)
    int gdk_scale_factor = gdk_window_get_scale_factor (gdk_window);

    allocation.width *= gdk_scale_factor;
    allocation.height *= gdk_scale_factor;
#endif

    if (!legacy)
        glActiveTexture (GL_TEXTURE0);
    glBindTexture (GL_TEXTURE_2D, texmap);
    GLint filter = Settings.BilinearFilter ? GL_LINEAR : GL_NEAREST;
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
    GLint clamp = (using_glsl_shaders || !npot) ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE;
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp);

    glClear (GL_COLOR_BUFFER_BIT);

    if (config->scale_method > 0)
    {
        uint8 *src_buffer = (uint8 *) padded_buffer[0];
        int   src_pitch = image_width * image_bpp;
        uint8 *dst_buffer;
        int   dst_pitch;

        src_buffer += (src_pitch * yoffset);

        dst_buffer = (uint8 *) padded_buffer[1];
        dst_pitch = scaled_max_width * image_bpp;
        final_buffer = (uint8 *) padded_buffer[1];
        final_pitch = scaled_max_width * image_bpp;

        S9xFilter (src_buffer,
                   src_pitch,
                   dst_buffer,
                   dst_pitch,
                   width,
                   height);
    }
    else
    {
        final_buffer = (uint8 *) padded_buffer[0];
        final_pitch = image_width * image_bpp;
        final_buffer += (final_pitch * yoffset);
    }

    x = width;
    y = height;
    w = allocation.width;
    h = allocation.height;
    S9xApplyAspect (x, y, w, h);

    glViewport (x, allocation.height - y - h, w, h);
    window->set_mouseable_area (x, y, w, h);

    update_texture_size (width, height);

    if (using_pbos)
    {
        if (config->pbo_format == 16)
        {

            glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
            glBufferData (GL_PIXEL_UNPACK_BUFFER,
                          width * height * 2,
                          NULL,
                          GL_STREAM_DRAW);

            if (version >= 30)
                pbo_map = glMapBufferRange (
                    GL_PIXEL_UNPACK_BUFFER, 0, width * height * 2,
                    GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT |
                        GL_MAP_UNSYNCHRONIZED_BIT);
            else
                pbo_map = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);

            for (int y = 0; y < height; y++)
            {
                memcpy ((uint8 *) pbo_map + (width * y * 2),
                        final_buffer + (y * final_pitch),
                        width * image_bpp);
            }

            glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);

            glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
            glTexSubImage2D (GL_TEXTURE_2D,
                             0,
                             0,
                             0,
                             width,
                             height,
                             GL_RGB,
                             GL_UNSIGNED_SHORT_5_6_5,
                             BUFFER_OFFSET (0));

            glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
        }
        else /* 32-bit color */
        {
            glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
            glBufferData (GL_PIXEL_UNPACK_BUFFER,
                          width * height * 4,
                          NULL,
                          GL_STREAM_DRAW);

            if (version >= 30)
                pbo_map = glMapBufferRange (
                    GL_PIXEL_UNPACK_BUFFER, 0, width * height * 4,
                    GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT |
                        GL_MAP_UNSYNCHRONIZED_BIT);
            else
                pbo_map = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);

            /* Pixel swizzling in software */
            S9xSetEndianess (ENDIAN_NORMAL);
            S9xConvert (final_buffer,
                        pbo_map,
                        final_pitch,
                        width * 4,
                        width,
                        height,
                        32);

            glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);

            glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
            glTexSubImage2D (GL_TEXTURE_2D,
                             0,
                             0,
                             0,
                             width,
                             height,
                             GL_BGRA,
                             GL_UNSIGNED_BYTE,
                             BUFFER_OFFSET (0));

            glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
        }
    }
    else
    {
        glPixelStorei (GL_UNPACK_ROW_LENGTH, final_pitch / image_bpp);
        glTexSubImage2D (GL_TEXTURE_2D,
                         0,
                         0,
                         0,
                         width,
                         height,
                         GL_RGB,
                         GL_UNSIGNED_SHORT_5_6_5,
                         final_buffer);
    }

    if (using_glsl_shaders)
    {
        glsl_shader->render (texmap, width, height, x, allocation.height - y - h, w, h, S9xViewportCallback);
        swap_buffers ();
        return;
    }

    glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);

    swap_buffers ();
}
void
S9xOpenGLDisplayDriver::update (int width, int height)
{
    GLint filter;
    uint8 *final_buffer = NULL;
    int   final_pitch;
    void  *pboMemory = NULL;
    int   x, y, w, h;

    if (width <= 0)
    {
        gdk_window_hide (gdk_window);
        return;
    }

    GtkAllocation allocation;
    gtk_widget_get_allocation (drawing_area, &allocation);

    if (output_window_width  != allocation.width ||
        output_window_height != allocation.height)
    {
        resize_window (allocation.width, allocation.height);
    }

    /* This avoids messing with the texture parameters every time */
    if (config->bilinear_filter != filtering)
    {
        filter = config->bilinear_filter ? GL_LINEAR : GL_NEAREST;
        glTexParameteri (tex_target, GL_TEXTURE_MAG_FILTER, filter);
        glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, filter);
        glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        filtering = config->bilinear_filter;
    }

    glClear (GL_COLOR_BUFFER_BIT);
    glEnable (tex_target);

    if (config->scale_method > 0)
    {
        uint8 *src_buffer = (uint8 *) padded_buffer[0];
        int   src_pitch = image_width * image_bpp;
        uint8 *dst_buffer;
        int   dst_pitch;

        dst_buffer = (uint8 *) padded_buffer[1];
        dst_pitch = scaled_max_width * image_bpp;
        final_buffer = (uint8 *) padded_buffer[1];
        final_pitch = scaled_max_width * image_bpp;

        S9xFilter (src_buffer,
                   src_pitch,
                   dst_buffer,
                   dst_pitch,
                   width,
                   height);
    }
    else
    {
        final_buffer = (uint8 *) padded_buffer[0];
        final_pitch = image_width * image_bpp;
    }

    x = width; y = height;
    w = allocation.width; h = allocation.height;
    S9xApplyAspect (x, y, w, h);

    glViewport (x, y, w, h);
    window->set_mouseable_area (x, y, w, h);

        update_texture_size (width, height);

        if (using_pbos)
        {
            if (config->pbo_format == PBO_FMT_16)
            {

                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
                glBufferData (GL_PIXEL_UNPACK_BUFFER,
                              width * height * 2,
                              NULL,
                              GL_STREAM_DRAW);
                pboMemory = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);

                for (int y = 0; y < height; y++)
                {
                    memcpy ((uint8 *) pboMemory + (width * y * 2),
                            final_buffer + (y * final_pitch),
                            width * image_bpp);
                }

                glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);

                glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
                glTexSubImage2D (tex_target,
                                 0,
                                 0,
                                 0,
                                 width,
                                 height,
                                 GL_BGRA,
                                 GL_UNSIGNED_SHORT_1_5_5_5_REV,
                                 BUFFER_OFFSET (0));

                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
            }
            else if (config->pbo_format == PBO_FMT_24)
            {
                /* Complement width to next multiple of 4 to force line size to
                 * be a multiple of 4 bytes. Otherwise, packing fails. */
                int width_mul_4 = width + ((4 - (width % 4)) % 4);

                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
                glBufferData (GL_PIXEL_UNPACK_BUFFER,
                              width_mul_4 * height * 3,
                              NULL,
                              GL_STREAM_DRAW);
                pboMemory = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);

                /* Pixel swizzling in software */
                S9xSetEndianess (ENDIAN_MSB);
                S9xConvert (final_buffer,
                            pboMemory,
                            final_pitch,
                            width_mul_4 * 3,
                            width,
                            height,
                            24);

                glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);

                glPixelStorei (GL_UNPACK_ROW_LENGTH, width_mul_4);
                glTexSubImage2D (tex_target,
                                 0,
                                 0,
                                 0,
                                 width,
                                 height,
                                 GL_RGB,
                                 GL_UNSIGNED_BYTE,
                                 BUFFER_OFFSET (0));

                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
            }
            else /* PBO_FMT_32 */
            {
                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
                glBufferData (GL_PIXEL_UNPACK_BUFFER,
                              width * height * 4,
                              NULL,
                              GL_STREAM_DRAW);
                pboMemory = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);

                /* Pixel swizzling in software */
#ifdef __BIG_ENDIAN__
                S9xSetEndianess (ENDIAN_MSB);
#else
                S9xSetEndianess (ENDIAN_LSB);
#endif
                S9xConvert (final_buffer,
                            pboMemory,
                            final_pitch,
                            width * 4,
                            width,
                            height,
                            32);

                glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);

                glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
                glTexSubImage2D (tex_target,
                                 0,
                                 0,
                                 0,
                                 width,
                                 height,
                                 GL_BGRA,
                                 PBO_BGRA_NATIVE_ORDER,
                                 BUFFER_OFFSET (0));

                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
            }
        }
        else
        {
            glPixelStorei (GL_UNPACK_ROW_LENGTH, final_pitch / image_bpp);
            glTexSubImage2D (tex_target,
                             0,
                             0,
                             0,
                             width,
                             height,
                             GL_BGRA,
                             GL_UNSIGNED_SHORT_1_5_5_5_REV,
                             final_buffer);
        }

        if (tex_target == GL_TEXTURE_2D)
        {
            texcoords[1] = (float) (height) / texture_height;
            texcoords[2] = (float) (width) / texture_width;
            texcoords[3] = texcoords[1];
            texcoords[4] = texcoords[2];
        }
        else if (tex_target == GL_TEXTURE_RECTANGLE)
        {
            texcoords[1] = (float) (height);
            texcoords[2] = (float) (width);
            texcoords[3] = texcoords[1];
            texcoords[4] = texcoords[2];
        }

    if (using_shaders)
    {
        GLint location;

        float inputSize[2] = { width, height };
        location = glGetUniformLocation (program, "rubyInputSize");
        glUniform2fv (location, 1, inputSize);

        float outputSize[2] = {w , h };
        location = glGetUniformLocation (program, "rubyOutputSize");
        glUniform2fv (location, 1, outputSize);

        float textureSize[2] = { texture_width, texture_height };
        location = glGetUniformLocation (program, "rubyTextureSize");
        glUniform2fv (location, 1, textureSize);
    }

    glDrawArrays (GL_QUADS, 0, 4);

    gl_swap ();

    return;
}
void
S9xXVDisplayDriver::update (int width, int height)
{
    int   current_width, current_height, final_pitch;
    uint8 *final_buffer;
    int   dst_x, dst_y, dst_width, dst_height;
    GtkAllocation allocation;

    gtk_widget_get_allocation (drawing_area, &allocation);
    current_width = allocation.width;
    current_height = allocation.height;

    if (width <= 0)
    {
        gdk_window_hide (gdk_window);
        return;
    }

    if (output_window_width  != current_width ||
        output_window_height != current_height)
    {
        resize_window (current_width, current_height);
    }

    if (config->scale_method > 0)
    {
        uint8 *src_buffer = (uint8 *) padded_buffer[0];
        uint8 *dst_buffer = (uint8 *) padded_buffer[1];
        int   src_pitch = image_width * image_bpp;
        int   dst_pitch = scaled_max_width * image_bpp;

        S9xFilter (src_buffer,
                   src_pitch,
                   dst_buffer,
                   dst_pitch,
                   width,
                   height);

        final_buffer = (uint8 *) padded_buffer[1];
        final_pitch = dst_pitch;
    }
    else
    {
        final_buffer = (uint8 *) padded_buffer[0];
        final_pitch = image_width * image_bpp;
    }

    update_image_size (width, height);

    if (format == FOURCC_YUY2)
    {
        S9xConvertYUV (final_buffer,
                       (uint8 *) xv_image->data,
                       final_pitch,
                       2 * xv_image->width,
                       width + (width < xv_image->width ? (width % 2) + 4 : 0),
                       height + (height < xv_image->height ? 4 : 0));
    }
    else
    {
        S9xConvertMask (final_buffer,
                        (uint8 *) xv_image->data,
                        final_pitch,
                        bytes_per_pixel * xv_image->width,
                        width + (width < xv_image->width ? (width % 2) + 4 : 0),
                        height + (height < xv_image->height ? 4 : 0),
                        rshift,
                        gshift,
                        bshift,
                        bpp);
    }

    dst_x = width; dst_y = height;
    dst_width = current_width; dst_height = current_height;
    S9xApplyAspect (dst_x, dst_y, dst_width, dst_height);

    if (last_known_width != dst_width || last_known_height != dst_height)
    {
        last_known_width = dst_width;
        last_known_height = dst_height;
        clear ();
    }

    XvShmPutImage (display,
                   xv_portid,
                   xwindow,
                   XDefaultGC (display, XDefaultScreen (display)),
                   xv_image,
                   0,
                   0,
                   width,
                   height,
                   dst_x,
                   dst_y,
                   dst_width,
                   dst_height,
                   False);

    top_level->set_mouseable_area (dst_x, dst_y, dst_width, dst_height);

    XSync (display, False);

    return;
}
void
S9xOpenGLDisplayDriver::update (int width, int height)
{
    GLint filter;
    uint8 *final_buffer = NULL;
    uint8 *final_buffer2 = NULL;
    int   combined_pitch;
    int   c_width, c_height;
    void  *pboMemory = NULL;

    c_width = drawing_area->allocation.width;
    c_height = drawing_area->allocation.height;

    if (width <= 0)
        return;

    gl_lock ();

    /* This avoids messing with the texture parameters every time */
    if (config->bilinear_filter != filtering)
    {
        filter = config->bilinear_filter ? GL_LINEAR : GL_NEAREST;
        glTexParameteri (tex_target, GL_TEXTURE_MAG_FILTER, filter);
        glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, filter);
        glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        filtering = config->bilinear_filter;
    }

    glClear (GL_COLOR_BUFFER_BIT);
    glEnable (tex_target);

    if (config->scale_method > 0)
    {
        /*uint8 *src_buffer = (uint8 *) padded_buffer[0];
        int   src_pitch = image_width * image_bpp;
        uint8 *dst_buffer;
        int   dst_pitch;

        dst_buffer = (uint8 *) padded_buffer[1];
        dst_pitch = scaled_max_width * image_bpp;
        final_buffer = (uint8 *) padded_buffer[1];
        combined_pitch = scaled_max_width * image_bpp;

        S9xFilter (src_buffer,
                   src_pitch,
                   dst_buffer,
                   dst_pitch,
                   width,
                   height);


        src_buffer = (uint8 *) padded_buffer[2];

        dst_buffer = (uint8 *) padded_buffer[3];
        dst_pitch = scaled_max_width * image_bpp;
        final_buffer2 = (uint8 *) padded_buffer[3];

        S9xFilter (src_buffer,
                   src_pitch,
                   dst_buffer,
                   dst_pitch,
                   width,
                   height);
        combine_buffers((uint16*)combined_buffer, (uint16*)final_buffer, (uint16*)final_buffer2, 
          scaled_max_width, scaled_max_height, image_bpp); */
        uint8 *src_buffer = (uint8 *) padded_buffer[0];
        int   src_pitch = image_width * image_bpp;
        uint8 *dst_buffer;
        int   dst_pitch;

        combine_buffers((uint16*)padded_buffer[0], (uint16*)padded_buffer[0], (uint16*)padded_buffer[2], 
          image_width, image_height, image_bpp);

        dst_buffer = (uint8 *) padded_buffer[1];
        dst_pitch = scaled_max_width * image_bpp;
        final_buffer = (uint8 *) padded_buffer[1];
        combined_pitch = scaled_max_width * image_bpp;

        S9xFilter (src_buffer,
                   src_pitch,
                   dst_buffer,
                   dst_pitch,
                   width,
                   height);

        memcpy(combined_buffer, dst_buffer, scaled_max_width * scaled_max_height * image_bpp);
    }
    else
    {
        final_buffer = (uint8 *) padded_buffer[0];
        final_buffer2 = (uint8 *) padded_buffer[2];
        combined_pitch = image_width * image_bpp;
        combine_buffers((uint16*)combined_buffer, (uint16*)final_buffer, (uint16*)final_buffer2, 
          image_width, image_height, image_bpp);
    }


    double screen_aspect = (double) c_width / (double) c_height;
    double snes_aspect = S9xGetAspect ();
    double granularity = 1.0 / (double) MAX (c_width, c_height);

    if (!config->scale_to_fit)
    {
        glViewport ((c_width - width) / 2, (c_height - height) / 2,
                    width, height);

        window->set_mouseable_area ((c_width - width) / 2,
                                       (c_height - height) / 2,
                                       width,
                                       height);
    }

    else if (config->maintain_aspect_ratio &&
            !(screen_aspect <= snes_aspect * (1.0 + granularity) &&
              screen_aspect >= snes_aspect * (1.0 - granularity)))
    {
        if (screen_aspect > snes_aspect)
        {
            glViewport ((c_width - (int)(c_height * snes_aspect)) / 2, 0,
                        (int)(c_height * snes_aspect), c_height);

            window->set_mouseable_area ((c_width -
                    (int) (c_height * snes_aspect)) / 2,
                    0,
                    (int) (c_height * snes_aspect),
                    c_height);
        }

        else
        {
            glViewport (0, (c_height - (int) (c_width / snes_aspect)) / 2,
                        c_width, (int) (c_width / snes_aspect));
            window->set_mouseable_area (0,
                                           (c_height -
                                             (int) (c_width / snes_aspect)) / 2,
                                           c_width,
                                           (int) (c_width / snes_aspect));
        }
    }

    else
    {
        glViewport (0, 0, c_width, c_height);
        window->set_mouseable_area (0, 0, c_width, c_height);
    }

    if (width > 0 && height > 0)
    {
        update_texture_size (width, height);

        if (using_pbos)
        {
            if (config->pbo_format == PBO_FMT_16)
            {

                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
                glBufferData (GL_PIXEL_UNPACK_BUFFER,
                              width * height * 2,
                              NULL,
                              GL_STREAM_DRAW);
                pboMemory = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);

                for (int y = 0; y < height; y++)
                {
                    memcpy ((uint8 *) pboMemory + (width * y * 2),
                            // TODO MIKEL I accidentally deleted the pointer cast here...
                            // I should double check that it's correct, but it should be ok
                            (uint8 *)combined_buffer + (y * combined_pitch),
                            width * image_bpp);
                }

                glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);

                glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
                glTexSubImage2D (tex_target,
                                 0,
                                 0,
                                 0,
                                 width,
                                 height,
                                 GL_BGRA,
                                 GL_UNSIGNED_SHORT_1_5_5_5_REV,
                                 BUFFER_OFFSET (0));

                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
            }
            else if (config->pbo_format == PBO_FMT_24)
            {
                /* Complement width to next multiple of 4 to force line size to
                 * be a multiple of 4 bytes. Otherwise, packing fails. */
                int width_mul_4 = width + ((4 - (width % 4)) % 4);

                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
                glBufferData (GL_PIXEL_UNPACK_BUFFER,
                              width_mul_4 * height * 3,
                              NULL,
                              GL_STREAM_DRAW);
                pboMemory = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);

                /* Pixel swizzling in software */
                S9xSetEndianess (ENDIAN_MSB);
                S9xConvert (combined_buffer,
                            pboMemory,
                            combined_pitch,
                            width_mul_4 * 3,
                            width,
                            height,
                            24);

                glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);

                glPixelStorei (GL_UNPACK_ROW_LENGTH, width_mul_4);
                glTexSubImage2D (tex_target,
                                 0,
                                 0,
                                 0,
                                 width,
                                 height,
                                 GL_RGB,
                                 GL_UNSIGNED_BYTE,
                                 BUFFER_OFFSET (0));

                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
            }
            else /* PBO_FMT_32 */
            {
                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
                glBufferData (GL_PIXEL_UNPACK_BUFFER,
                              width * height * 4,
                              NULL,
                              GL_STREAM_DRAW);
                pboMemory = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);

                /* Pixel swizzling in software */
#ifdef __BIG_ENDIAN__
                S9xSetEndianess (ENDIAN_MSB);
#else
                S9xSetEndianess (ENDIAN_LSB);
#endif
                S9xConvert (combined_buffer,
                            pboMemory,
                            combined_pitch,
                            width * 4,
                            width,
                            height,
                            32);

                glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);

                glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
                glTexSubImage2D (tex_target,
                                 0,
                                 0,
                                 0,
                                 width,
                                 height,
                                 GL_BGRA,
                                 PBO_BGRA_NATIVE_ORDER,
                                 BUFFER_OFFSET (0));

                glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
            }
        }
        else
        {
            glPixelStorei (GL_UNPACK_ROW_LENGTH, combined_pitch / image_bpp);

            glTexSubImage2D (tex_target,
                             0,
                             0,
                             0,
                             width,
                             height,
                             GL_BGRA,
                             GL_UNSIGNED_SHORT_1_5_5_5_REV,
                             combined_buffer);
        }

        if (tex_target == GL_TEXTURE_2D)
        {
            texcoords[1] = (float) (height) / texture_height;
            texcoords[2] = (float) (width) / texture_width;
            texcoords[3] = texcoords[1];
            texcoords[4] = texcoords[2];
        }
        else if (tex_target == GL_TEXTURE_RECTANGLE)
        {
            texcoords[1] = (float) (height);
            texcoords[2] = (float) (width);
            texcoords[3] = texcoords[1];
            texcoords[4] = texcoords[2];
        }

        glDrawArrays (GL_QUADS, 0, 4);
    }

    gl_unlock ();
    gl_swap ();

    return;
}