Search
lxdream.org :: lxdream/src/drivers/video_gl.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/video_gl.c
changeset 1262:4baa34eee6fc
prev1260:8207695d908c
next1282:9f445c5e252b
author nkeynes
date Mon Mar 05 22:20:33 2012 +1000 (12 years ago)
permissions -rw-r--r--
last change Fix boundary of the first vertical gap in view
file annotate diff log raw
nkeynes@635
     1
/**
nkeynes@635
     2
 * $Id$
nkeynes@635
     3
 *
nkeynes@635
     4
 * Common GL code that doesn't depend on a specific implementation
nkeynes@635
     5
 *
nkeynes@635
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@635
     7
 *
nkeynes@635
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@635
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@635
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@635
    11
 * (at your option) any later version.
nkeynes@635
    12
 *
nkeynes@635
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@635
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@635
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@635
    16
 * GNU General Public License for more details.
nkeynes@635
    17
 */
nkeynes@635
    18
nkeynes@635
    19
#include <sys/time.h>
nkeynes@635
    20
nkeynes@635
    21
#include "display.h"
nkeynes@635
    22
#include "pvr2/pvr2.h"
nkeynes@1236
    23
#include "pvr2/glutil.h"
nkeynes@1240
    24
#include "pvr2/shaders.h"
nkeynes@635
    25
#include "drivers/video_gl.h"
nkeynes@635
    26
nkeynes@1239
    27
/* FIXME: Need to actually handle this case */
nkeynes@1239
    28
#ifndef GL_PACK_ROW_LENGTH
nkeynes@1239
    29
#define glPixelStorei(key,val)
nkeynes@1239
    30
#endif
nkeynes@1239
    31
nkeynes@1236
    32
uint32_t video_width, video_height;
nkeynes@1236
    33
struct video_vertex {
nkeynes@1236
    34
    float x,y;
nkeynes@1236
    35
    float u,v;
nkeynes@1240
    36
    float r,g,b,a;
nkeynes@1236
    37
};
nkeynes@1236
    38
nkeynes@1236
    39
static struct video_box_t {
nkeynes@1236
    40
    float viewMatrix[16];
nkeynes@1236
    41
    struct video_vertex gap1[4];
nkeynes@1236
    42
    struct video_vertex gap2[4];
nkeynes@1236
    43
    struct video_vertex video_view[4];
nkeynes@1236
    44
    struct video_vertex invert_view[4];
nkeynes@1236
    45
} video_box;
nkeynes@1236
    46
nkeynes@1251
    47
void gl_set_video_size( uint32_t width, uint32_t height, int flipped )
nkeynes@1236
    48
{
nkeynes@1236
    49
    video_width = width;
nkeynes@1236
    50
    video_height = height;
nkeynes@1236
    51
nkeynes@1236
    52
    int x1=0,y1=0,x2=video_width,y2=video_height;
nkeynes@1251
    53
    int top = 0, bottom = 1;
nkeynes@1251
    54
nkeynes@1251
    55
    if( flipped ) {
nkeynes@1251
    56
        top = 1;
nkeynes@1251
    57
        bottom = 0;
nkeynes@1251
    58
    }
nkeynes@1236
    59
nkeynes@1236
    60
    int ah = video_width * 0.75;
nkeynes@1236
    61
nkeynes@1236
    62
    if( ah > video_height ) {
nkeynes@1236
    63
        int w = (video_height/0.75);
nkeynes@1236
    64
        x1 = (video_width - w)/2;
nkeynes@1236
    65
        x2 -= x1;
nkeynes@1236
    66
        video_box.gap1[0].x = 0; video_box.gap1[0].y = 0;
nkeynes@1236
    67
        video_box.gap1[1].x = x1; video_box.gap1[1].y = 0;
nkeynes@1262
    68
        video_box.gap1[2].x = x1; video_box.gap1[2].y = video_height;
nkeynes@1259
    69
        video_box.gap1[3].x = 0; video_box.gap1[3].y = video_height;
nkeynes@1236
    70
        video_box.gap2[0].x = x2; video_box.gap2[0].y = 0;
nkeynes@1236
    71
        video_box.gap2[1].x = video_width; video_box.gap2[1].y = 0;
nkeynes@1259
    72
        video_box.gap2[2].x = video_width; video_box.gap2[2].y = video_height;
nkeynes@1259
    73
        video_box.gap2[3].x = x2; video_box.gap2[3].y = video_height;
nkeynes@1236
    74
    } else if( ah < video_height ) {
nkeynes@1236
    75
        y1 = (video_height - ah)/2;
nkeynes@1236
    76
        y2 -= y1;
nkeynes@1236
    77
nkeynes@1236
    78
        video_box.gap1[0].x = 0; video_box.gap1[0].y = 0;
nkeynes@1236
    79
        video_box.gap1[1].x = video_width; video_box.gap1[1].y = 0;
nkeynes@1259
    80
        video_box.gap1[2].x = video_width; video_box.gap1[2].y = y1;
nkeynes@1259
    81
        video_box.gap1[3].x = 0; video_box.gap1[3].y = y1;
nkeynes@1236
    82
        video_box.gap2[0].x = 0; video_box.gap2[0].y = y2;
nkeynes@1236
    83
        video_box.gap2[1].x = video_width; video_box.gap2[1].y = y2;
nkeynes@1259
    84
        video_box.gap2[2].x = video_width; video_box.gap2[2].y = video_height;
nkeynes@1259
    85
        video_box.gap2[3].x = 0; video_box.gap2[3].y = video_height;
nkeynes@1236
    86
    }
nkeynes@1236
    87
nkeynes@1236
    88
    video_box.video_view[0].x = x1; video_box.video_view[0].y = y1;
nkeynes@1259
    89
    video_box.video_view[0].u = 0; video_box.video_view[0].v = top;
nkeynes@1236
    90
    video_box.video_view[1].x = x2; video_box.video_view[1].y = y1;
nkeynes@1259
    91
    video_box.video_view[1].u = 1; video_box.video_view[1].v = top;
nkeynes@1259
    92
    video_box.video_view[2].x = x2; video_box.video_view[2].y = y2;
nkeynes@1259
    93
    video_box.video_view[2].u = 1; video_box.video_view[2].v = bottom;
nkeynes@1259
    94
    video_box.video_view[3].x = x1; video_box.video_view[3].y = y2;
nkeynes@1259
    95
    video_box.video_view[3].u = 0; video_box.video_view[3].v = bottom;
nkeynes@1236
    96
nkeynes@1236
    97
    memcpy( &video_box.invert_view, &video_box.video_view, sizeof(video_box.video_view) );
nkeynes@1251
    98
    video_box.invert_view[0].v = bottom; video_box.invert_view[1].v = bottom;
nkeynes@1251
    99
    video_box.invert_view[2].v = top; video_box.invert_view[3].v = top;
nkeynes@1236
   100
nkeynes@1236
   101
    defineOrthoMatrix(video_box.viewMatrix, video_width, video_height, 0, 65535);
nkeynes@1236
   102
}
nkeynes@635
   103
nkeynes@1239
   104
#ifdef HAVE_OPENGL_FIXEDFUNC
nkeynes@635
   105
/**
nkeynes@1236
   106
 * Setup the gl context for writes to the display output.
nkeynes@635
   107
 */
nkeynes@1246
   108
void gl_framebuffer_setup()
nkeynes@635
   109
{
nkeynes@1239
   110
    glViewport( 0, 0, video_width, video_height );
nkeynes@1236
   111
    glLoadMatrixf(video_box.viewMatrix);
nkeynes@1236
   112
    glBlendFunc( GL_ONE, GL_ZERO );
nkeynes@1236
   113
    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
nkeynes@1236
   114
    glVertexPointer(2, GL_FLOAT, sizeof(struct video_vertex), &video_box.gap1[0].x);
nkeynes@1236
   115
    glColorPointer(3, GL_FLOAT, sizeof(struct video_vertex), &video_box.gap1[0].r);
nkeynes@1236
   116
    glTexCoordPointer(2, GL_FLOAT, sizeof(struct video_vertex), &video_box.gap1[0].u);
nkeynes@1236
   117
    glEnableClientState( GL_VERTEX_ARRAY );
nkeynes@1236
   118
    glEnableClientState( GL_COLOR_ARRAY );
nkeynes@1236
   119
    glEnableClientState( GL_TEXTURE_COORD_ARRAY );
nkeynes@635
   120
}
nkeynes@635
   121
nkeynes@1246
   122
void gl_framebuffer_cleanup()
nkeynes@1240
   123
{
nkeynes@1240
   124
    glDisableClientState( GL_VERTEX_ARRAY );
nkeynes@1240
   125
    glDisableClientState( GL_COLOR_ARRAY );
nkeynes@1240
   126
    glDisableClientState( GL_TEXTURE_COORD_ARRAY );
nkeynes@1240
   127
}
nkeynes@1239
   128
#else
nkeynes@1246
   129
void gl_framebuffer_setup()
nkeynes@1239
   130
{
nkeynes@1240
   131
    glViewport( 0, 0, video_width, video_height );
nkeynes@1240
   132
    glBlendFunc( GL_ONE, GL_ZERO );
nkeynes@1240
   133
    glsl_use_basic_shader();
nkeynes@1240
   134
    glsl_set_basic_shader_view_matrix(video_box.viewMatrix);
nkeynes@1240
   135
    glsl_set_basic_shader_in_vertex_pointer(&video_box.gap1[0].x, sizeof(struct video_vertex));
nkeynes@1240
   136
    glsl_set_basic_shader_in_colour_pointer(&video_box.gap1[0].r, sizeof(struct video_vertex));
nkeynes@1240
   137
    glsl_set_basic_shader_in_texcoord_pointer(&video_box.gap1[0].u, sizeof(struct video_vertex));
nkeynes@1240
   138
    glsl_set_basic_shader_primary_texture(0);
nkeynes@1240
   139
}
nkeynes@1240
   140
nkeynes@1246
   141
void gl_framebuffer_cleanup()
nkeynes@1240
   142
{
nkeynes@1240
   143
    glsl_clear_shader();
nkeynes@1239
   144
}
nkeynes@1239
   145
#endif
nkeynes@1239
   146
nkeynes@635
   147
void gl_display_render_buffer( render_buffer_t buffer )
nkeynes@635
   148
{
nkeynes@635
   149
    gl_texture_window( buffer->width, buffer->height, buffer->buf_id, buffer->inverted );
nkeynes@635
   150
}
nkeynes@635
   151
nkeynes@854
   152
/**
nkeynes@854
   153
 * Convert window coordinates to dreamcast device coords (640x480) using the 
nkeynes@854
   154
 * same viewable area as gl_texture_window.
nkeynes@854
   155
 * If the coordinates are outside the viewable area, the result is -1,-1.
nkeynes@854
   156
 */ 
nkeynes@854
   157
void gl_window_to_system_coords( int *x, int *y )
nkeynes@854
   158
{
nkeynes@854
   159
    int x1=0,y1=0,x2=video_width,y2=video_height;
nkeynes@854
   160
nkeynes@854
   161
    int ah = video_width * 0.75;
nkeynes@854
   162
nkeynes@854
   163
    if( ah > video_height ) {
nkeynes@854
   164
        int w = (video_height/0.75);
nkeynes@854
   165
        x1 = (video_width - w)/2;
nkeynes@854
   166
        x2 -= x1;
nkeynes@854
   167
    } else if( ah < video_height ) {
nkeynes@854
   168
        y1 = (video_height - ah)/2;
nkeynes@854
   169
        y2 -= y1;
nkeynes@854
   170
    }
nkeynes@854
   171
    if( *x < x1 || *x >= x2 || *y < y1 || *y >= y2 ) {
nkeynes@854
   172
        *x = -1;
nkeynes@854
   173
        *y = -1;
nkeynes@854
   174
    } else {
nkeynes@854
   175
        *x = (*x - x1) * DISPLAY_WIDTH / (x2-x1);
nkeynes@854
   176
        *y = (*y - y1) * DISPLAY_HEIGHT / (y2-y1);
nkeynes@854
   177
    }
nkeynes@854
   178
}
nkeynes@854
   179
nkeynes@1259
   180
/**
nkeynes@1259
   181
 * Use quads if we have them, otherwise tri-fans.
nkeynes@1259
   182
 */
nkeynes@1259
   183
#ifndef GL_QUADS
nkeynes@1260
   184
#define GL_QUADS GL_TRIANGLE_FAN
nkeynes@1259
   185
#endif
nkeynes@1259
   186
nkeynes@635
   187
void gl_texture_window( int width, int height, int tex_id, gboolean inverted )
nkeynes@635
   188
{
nkeynes@1240
   189
    /* Set video box tex alpha to 1 */
nkeynes@1240
   190
    video_box.video_view[0].a = video_box.video_view[1].a = video_box.video_view[2].a = video_box.video_view[3].a = 1;
nkeynes@1251
   191
    video_box.invert_view[0].a = video_box.invert_view[1].a = video_box.invert_view[2].a = video_box.invert_view[3].a = 1;
nkeynes@1240
   192
nkeynes@635
   193
    /* Reset display parameters */
nkeynes@1236
   194
    gl_framebuffer_setup();
nkeynes@1259
   195
    glDrawArrays(GL_QUADS, 0, 4);
nkeynes@1259
   196
    glDrawArrays(GL_QUADS, 4, 4);
nkeynes@1236
   197
    glEnable(GL_TEXTURE_2D);
nkeynes@1236
   198
    glBindTexture(GL_TEXTURE_2D,tex_id);
nkeynes@1222
   199
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nkeynes@1222
   200
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nkeynes@1259
   201
    glDrawArrays(GL_QUADS, inverted ? 12 : 8, 4);
nkeynes@1236
   202
    glDisable(GL_TEXTURE_2D);
nkeynes@1251
   203
    gl_framebuffer_cleanup();
nkeynes@635
   204
    glFlush();
nkeynes@635
   205
}
nkeynes@635
   206
nkeynes@635
   207
gboolean gl_load_frame_buffer( frame_buffer_t frame, int tex_id )
nkeynes@635
   208
{
nkeynes@635
   209
    GLenum type = colour_formats[frame->colour_format].type;
nkeynes@635
   210
    GLenum format = colour_formats[frame->colour_format].format;
nkeynes@635
   211
    int bpp = colour_formats[frame->colour_format].bpp;
nkeynes@635
   212
    int rowstride = (frame->rowstride / bpp) - frame->width;
nkeynes@736
   213
nkeynes@635
   214
    glPixelStorei( GL_UNPACK_ROW_LENGTH, rowstride );
nkeynes@1222
   215
    glBindTexture( GL_TEXTURE_2D, tex_id );
nkeynes@1222
   216
    glTexSubImage2D( GL_TEXTURE_2D, 0, 0,0,
nkeynes@736
   217
                     frame->width, frame->height, format, type, frame->data );
nkeynes@1236
   218
    glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
nkeynes@635
   219
    return TRUE;
nkeynes@635
   220
}
nkeynes@635
   221
nkeynes@669
   222
void gl_display_blank( uint32_t colour )
nkeynes@635
   223
{
nkeynes@1236
   224
    /* Set the video_box background colour */
nkeynes@1236
   225
    video_box.video_view[0].r = ((float)(((colour >> 16) & 0xFF) + 1)) / 256.0;
nkeynes@1236
   226
    video_box.video_view[0].g = ((float)(((colour >> 8) & 0xFF) + 1)) / 256.0;
nkeynes@1236
   227
    video_box.video_view[0].b = ((float)((colour & 0xFF) + 1)) / 256.0;
nkeynes@1240
   228
    video_box.video_view[0].a = 0;
nkeynes@1236
   229
    memcpy( &video_box.video_view[1].r, &video_box.video_view[0].r, sizeof(float)*3 );
nkeynes@1236
   230
    memcpy( &video_box.video_view[2].r, &video_box.video_view[0].r, sizeof(float)*3 );
nkeynes@1236
   231
    memcpy( &video_box.video_view[3].r, &video_box.video_view[0].r, sizeof(float)*3 );
nkeynes@1236
   232
nkeynes@1236
   233
    /* And render */
nkeynes@1236
   234
    gl_framebuffer_setup();
nkeynes@1259
   235
    glDrawArrays(GL_QUADS, 0, 4);
nkeynes@1259
   236
    glDrawArrays(GL_QUADS, 4, 4);
nkeynes@1259
   237
    glDrawArrays(GL_QUADS, 8, 4);
nkeynes@1251
   238
    gl_framebuffer_cleanup();
nkeynes@635
   239
    glFlush();
nkeynes@635
   240
}
nkeynes@635
   241
nkeynes@635
   242
/**
nkeynes@635
   243
 * Generic GL read_render_buffer. This function assumes that the caller
nkeynes@635
   244
 * has already set the appropriate glReadBuffer(); in other words, unless
nkeynes@635
   245
 * there's only one buffer this needs to be wrapped.
nkeynes@635
   246
 */
nkeynes@635
   247
gboolean gl_read_render_buffer( unsigned char *target, render_buffer_t buffer, 
nkeynes@736
   248
                                int rowstride, int colour_format ) 
nkeynes@635
   249
{
nkeynes@635
   250
    glFinish();
nkeynes@635
   251
    GLenum type = colour_formats[colour_format].type;
nkeynes@635
   252
    GLenum format = colour_formats[colour_format].format;
nkeynes@635
   253
    // int line_size = buffer->width * colour_formats[colour_format].bpp;
nkeynes@635
   254
    // int size = line_size * buffer->height;
nkeynes@635
   255
    int glrowstride = (rowstride / colour_formats[colour_format].bpp) - buffer->width;
nkeynes@635
   256
    glPixelStorei( GL_PACK_ROW_LENGTH, glrowstride );
nkeynes@635
   257
    glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
nkeynes@1236
   258
    glPixelStorei( GL_PACK_ROW_LENGTH, 0 );
nkeynes@635
   259
    return TRUE;
nkeynes@635
   260
}
nkeynes@1244
   261
nkeynes@1258
   262
gboolean gl_init_driver( display_driver_t driver, gboolean need_fbo )
nkeynes@1258
   263
{
nkeynes@1258
   264
    /* Use framebuffer objects if available */
nkeynes@1258
   265
    if( gl_fbo_is_supported() ) {
nkeynes@1258
   266
        gl_fbo_init(driver);
nkeynes@1258
   267
    } else if( need_fbo ) {
nkeynes@1258
   268
        ERROR( "Framebuffer objects not supported - unable to construct an off-screen buffer" );
nkeynes@1258
   269
        return FALSE;
nkeynes@1258
   270
    }
nkeynes@1258
   271
nkeynes@1258
   272
    /* Use SL shaders if available */
nkeynes@1258
   273
    gboolean have_shaders = glsl_init(driver);
nkeynes@1258
   274
#ifndef HAVE_OPENGL_FIXEDFUNC
nkeynes@1258
   275
    if( !have_shaders ) { /* Shaders are required if we don't have fixed-functionality */
nkeynes@1258
   276
        gl_fbo_shutdown();
nkeynes@1258
   277
        return FALSE;
nkeynes@1258
   278
    }
nkeynes@1258
   279
#endif
nkeynes@1258
   280
nkeynes@1258
   281
    /* Use vertex arrays, VBOs, etc, if we have them */
nkeynes@1258
   282
    gl_vbo_init(driver);
nkeynes@1258
   283
nkeynes@1258
   284
    driver->capabilities.has_gl = TRUE;
nkeynes@1258
   285
    return TRUE;
nkeynes@1258
   286
}
nkeynes@1258
   287
nkeynes@1244
   288
static gboolean video_gl_init();
nkeynes@1244
   289
nkeynes@1244
   290
/**
nkeynes@1244
   291
 * Minimal GL driver (assuming that the GL context is already set up externally)
nkeynes@1244
   292
 * This requires FBO support (since otherwise we have no way to get a render buffer)
nkeynes@1244
   293
 */
nkeynes@1244
   294
struct display_driver display_gl_driver = {
nkeynes@1244
   295
        "gl", N_("OpenGL driver"), video_gl_init, NULL,
nkeynes@1244
   296
        NULL, NULL, NULL,
nkeynes@1244
   297
        NULL, NULL, NULL, NULL,
nkeynes@1244
   298
        gl_load_frame_buffer, gl_display_render_buffer, gl_display_blank,
nkeynes@1244
   299
        NULL, gl_read_render_buffer, NULL, NULL
nkeynes@1244
   300
};
nkeynes@1244
   301
nkeynes@1244
   302
static gboolean video_gl_init()
nkeynes@1244
   303
{
nkeynes@1258
   304
    return gl_init_driver(&display_gl_driver, TRUE);
nkeynes@1244
   305
}
.