Subversion Repositories Kolibri OS

Rev

Rev 4495 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/time.h>
  5.  
  6. #define EGL_EGLEXT_PROTOTYPES
  7. #define GL_GLEXT_PROTOTYPES
  8.  
  9. #include "EGL/egl.h"
  10. #include "EGL/eglext.h"
  11. #include "GL/gl.h"
  12. #include "gbm.h"
  13. #include <i915_drm.h>
  14. #include <kos32sys.h>
  15. #include <pixlib2.h>
  16.  
  17. enum px_buffer
  18. {
  19.     PX_FRONT = 0,
  20.     PX_BACK  = 1
  21. };
  22.  
  23. struct render
  24. {
  25.     EGLDisplay dpy;
  26.     EGLContext context;
  27.     GLuint framebuffer;
  28.     EGLImageKHR front, back, screen;
  29.     GLuint tx_buffers[2];
  30.     GLuint tx_screen;
  31.     int back_buffer;
  32.     GLuint blit_prog;
  33.     GLint sampler;
  34.     float vertices[8], texcoords[8];
  35. };
  36.  
  37.  
  38. EGLImageKHR px_create_image(EGLDisplay display, EGLContext context,
  39.                          int width, int height, int stride, int name);
  40. GLuint create_framebuffer(int width, int height, GLuint *tex);
  41. GLint create_shader(GLenum type, const char *source);
  42. struct render* create_render(EGLDisplay dpy, EGLSurface surface);
  43. void blit_texture(struct render *render, GLuint tex, int x, int y, int w, int h);
  44. void render_swap_buffers(struct render *render, int x, int y, int w, int h);
  45.  
  46. int main()
  47. {
  48.     struct gbm_device *gbm;
  49.     struct gbm_surface  *gs;
  50.     struct render *render;
  51.  
  52.     EGLDisplay dpy;
  53.     EGLint major, minor;
  54.  
  55.     EGLContext context;
  56.     EGLSurface surface;
  57.  
  58.     EGLConfig config;
  59.  
  60.     EGLint config_attribs[32];
  61.     EGLint num_configs, i;
  62.  
  63.     int fd;
  64.  
  65.     fd = get_service("DISPLAY");
  66.     gbm = gbm_create_device(fd);
  67.     if( gbm == NULL){
  68.         printf("failed to initialize GBM device");
  69.         return 1;
  70.     };
  71.  
  72.     init_pixlib(HW_BIT_BLIT);
  73.  
  74.     dpy = eglGetDisplay((EGLNativeDisplayType)gbm);
  75.  
  76.     if (!eglInitialize(dpy, &major, &minor))
  77.         printf("failed to initialize EGL display");
  78.  
  79.     printf("EGL_VERSION = %s\n", eglQueryString(dpy, EGL_VERSION));
  80.     printf("EGL_VENDOR = %s\n", eglQueryString(dpy, EGL_VENDOR));
  81.     printf("EGL_EXTENSIONS = %s\n", eglQueryString(dpy, EGL_EXTENSIONS));
  82.     printf("EGL_CLIENT_APIS = %s\n",eglQueryString(dpy, EGL_CLIENT_APIS));
  83.  
  84.     i = 0;
  85.     config_attribs[i++] = EGL_RED_SIZE;
  86.     config_attribs[i++] = 1;
  87.     config_attribs[i++] = EGL_GREEN_SIZE;
  88.     config_attribs[i++] = 1;
  89.     config_attribs[i++] = EGL_BLUE_SIZE;
  90.     config_attribs[i++] = 1;
  91.     config_attribs[i++] = EGL_DEPTH_SIZE;
  92.     config_attribs[i++] = 1;
  93.  
  94.     config_attribs[i++] = EGL_SURFACE_TYPE;
  95.     config_attribs[i++] = EGL_WINDOW_BIT;
  96.  
  97.     config_attribs[i++] = EGL_RENDERABLE_TYPE;
  98.     config_attribs[i++] = EGL_OPENGL_BIT;
  99.     config_attribs[i] = EGL_NONE;
  100.  
  101.     if (!eglChooseConfig(dpy,config_attribs, &config, 1, &num_configs) || !num_configs)
  102.         printf("failed to choose a config");
  103.  
  104.     eglBindAPI(EGL_OPENGL_API);
  105.     context = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL);
  106.     if (!context)
  107.         printf("failed to create context");
  108.  
  109.     gs = gbm_surface_create(gbm, 400, 300, GBM_BO_FORMAT_ARGB8888, GBM_BO_USE_RENDERING);
  110.  
  111.     BeginDraw();
  112.     DrawWindow(20, 20, 400+9, 300+24, "gl-render", 0x000000, 0x74);
  113.     EndDraw();
  114.  
  115.     surface = eglCreateWindowSurface(dpy,config, (EGLNativeWindowType)gs, NULL);
  116.     if (surface == EGL_NO_SURFACE)
  117.         printf("failed to create surface");
  118.  
  119.     if (!eglMakeCurrent(dpy, surface, surface, context))
  120.         printf("failed to make window current");
  121.  
  122.  
  123.  
  124.     glMatrixMode(GL_PROJECTION);
  125.         glLoadIdentity();
  126.     glOrtho(-1.0, 1.0, -1.0, 1.0, -0.5, 1000.0);
  127.         glMatrixMode(GL_MODELVIEW);
  128.         glLoadIdentity();
  129.  
  130.         glViewport(0, 0, 400, 300);
  131.  
  132.     glClearColor( 0, 0, 0, 1);
  133.  
  134.     glClear(GL_COLOR_BUFFER_BIT);
  135.  
  136.     glBegin(GL_QUADS);
  137.     glColor3f(1,0,0);
  138.     glVertex3f( 0.9, -0.9, -30.0);
  139.     glColor3f(1,1,0);
  140.     glVertex3f( 0.9,  0.9, -30.0);
  141.  
  142.     glColor3f(1,1,1);
  143.     glVertex3f( 0.1,  0.9, -30.0);
  144.     glColor3f(1,0,1);
  145.     glVertex3f( 0.1, -0.9, -30.0);
  146.     glEnd();
  147.  
  148.     glFlush();
  149.  
  150.   asm volatile ("int3");
  151.  
  152.     render = create_render(dpy, surface);
  153.         glViewport(0, 0, 1024, 768);
  154.     glMatrixMode(GL_PROJECTION);
  155.         glLoadIdentity();
  156.         glMatrixMode(GL_MODELVIEW);
  157.         glLoadIdentity();
  158.  
  159.     render_swap_buffers(render, 20, 20, 400, 300);
  160.  
  161.     glFinish();
  162.     eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  163. //    eglDestroySurface(dpy, surface);
  164.   //  gbm_surface_destroy(gs);
  165.     eglDestroyContext(dpy, context);
  166.     eglTerminate(dpy);
  167.  
  168.     while(1)
  169.     {
  170.         delay(1);
  171.     }
  172.  
  173.     return 0;
  174. }
  175.  
  176. int drmIoctl(int fd, unsigned long request, void *arg)
  177. {
  178.     ioctl_t  io;
  179.  
  180.     io.handle   = fd;
  181.     io.io_code  = request;
  182.     io.input    = arg;
  183.     io.inp_size = 64;
  184.     io.output   = NULL;
  185.     io.out_size = 0;
  186.  
  187.     return call_service(&io);
  188. }
  189.  
  190. EGLImageKHR px_create_image(EGLDisplay display, EGLContext context,
  191.                          int width, int height, int stride, int name)
  192. {
  193.         EGLImageKHR image;
  194.         EGLint attribs[] = {
  195.                 EGL_WIDTH, 0,
  196.                 EGL_HEIGHT, 0,
  197.                 EGL_DRM_BUFFER_STRIDE_MESA, 0,
  198.                 EGL_DRM_BUFFER_FORMAT_MESA,
  199.                 EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
  200.                 EGL_DRM_BUFFER_USE_MESA,
  201.                 EGL_DRM_BUFFER_USE_SHARE_MESA |
  202.                     EGL_DRM_BUFFER_USE_SCANOUT_MESA,
  203.                 EGL_NONE
  204.         };
  205.         attribs[1] = width;
  206.         attribs[3] = height;
  207.         attribs[5] = stride/4;
  208.  
  209.     printf("%s w:%d :%d pitch:%d handle %d\n", __FUNCTION__,
  210.            width, height, stride, name);
  211.  
  212.         image = eglCreateImageKHR(display, context, EGL_DRM_BUFFER_MESA,
  213.                                                  (void *) (uintptr_t)name, attribs);
  214.  
  215.         return image;
  216. }
  217.  
  218. GLint create_shader(GLenum type, const char *source)
  219. {
  220.         GLint ok;
  221.     GLint shader;
  222.  
  223.     shader = glCreateShader(type);
  224.     if(shader == 0)
  225.         goto err;
  226.  
  227.     glShaderSource(shader, 1, (const GLchar **) &source, NULL);
  228.     glCompileShader(shader);
  229.     glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
  230.         if (!ok) {
  231.                 GLchar *info;
  232.                 GLint size;
  233.  
  234.         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
  235.                 info = malloc(size);
  236.  
  237.         glGetShaderInfoLog(shader, size, NULL, info);
  238.                 printf("Failed to compile %s: %s\n",
  239.                 type == GL_FRAGMENT_SHADER ? "FS" : "VS",info);
  240.                 printf("Program source:\n%s", source);
  241.                 printf("GLSL compile failure\n");
  242.         free(info);
  243.         glDeleteProgram(shader);
  244.         shader = 0;
  245.         }
  246. err:
  247.     return shader;
  248. }
  249.  
  250.  
  251. struct render* create_render(EGLDisplay dpy, EGLSurface surface)
  252. {
  253.     const char *vs_src =
  254.             "attribute vec4 v_position;\n"
  255.             "attribute vec4 v_texcoord0;\n"
  256.             "varying vec2 source_texture;\n"
  257.             "void main()\n"
  258.             "{\n"
  259.             "   gl_Position = v_position;\n"
  260.             "   source_texture = v_texcoord0.xy;\n"
  261.             "}\n";
  262.  
  263.         const char *fs_src =
  264. //          "precision mediump float;\n"
  265.             "varying vec2 source_texture;\n"
  266.             "uniform sampler2D sampler;\n"
  267.             "void main()\n"
  268.             "{\n"
  269.             "   vec3 cg = texture2D(sampler, source_texture).rgb;\n"
  270.             "   gl_FragColor = vec4(cg.r,cg.g,cg.b,1.0);\n"
  271.             "}\n";
  272.     EGLint config_attribs[14];
  273.     EGLConfig config;
  274.     EGLint num_configs;
  275.  
  276.     EGLContext context;
  277.  
  278.     struct drm_i915_fb_info fb;
  279.     GLint  vs_shader, fs_shader;
  280.     GLenum status;
  281.     GLint ret;
  282.     int fd;
  283.     struct render *render;
  284.  
  285.  
  286.  
  287.     fd = get_service("DISPLAY");
  288.  
  289.     memset(&fb, 0, sizeof(fb));
  290.     ret = drmIoctl(fd, SRV_FBINFO, &fb);
  291.     if( ret != 0 )
  292.     {   printf("failed to get framebuffer info\n");
  293.         goto err;
  294.     };
  295.  
  296.     render = (struct render*)malloc(sizeof(struct render));
  297.     if(render == NULL)
  298.         goto err;
  299.  
  300.     render->dpy = dpy;
  301.  
  302.     render->front = eglGetBufferImage(dpy, surface, EGL_DRM_BUFFER_FRONT);
  303.     if(render->front == EGL_NO_IMAGE_KHR)
  304.         goto err1;
  305.  
  306.     render->back  = eglGetBufferImage(dpy, surface, EGL_DRM_BUFFER_BACK);
  307.     if( render->back == EGL_NO_IMAGE_KHR)
  308.         goto err2;
  309.  
  310.     glGenTextures(2, render->tx_buffers);
  311.     if(glGetError() != GL_NO_ERROR)
  312.        goto err3;
  313.  
  314.     glBindTexture(GL_TEXTURE_2D, render->tx_buffers[EGL_DRM_BUFFER_FRONT]);
  315.     if(glGetError() != GL_NO_ERROR)
  316.        goto err4;
  317.  
  318.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  319.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  320.     glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,render->front);
  321.     if(glGetError() != GL_NO_ERROR)
  322.        goto err4;
  323.  
  324.     glBindTexture(GL_TEXTURE_2D, render->tx_buffers[EGL_DRM_BUFFER_BACK]);
  325.     if(glGetError() != GL_NO_ERROR)
  326.        goto err4;
  327.  
  328.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  329.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  330.     glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,render->back);
  331.     if(glGetError() != GL_NO_ERROR)
  332.        goto err4;
  333.  
  334.     glBindTexture(GL_TEXTURE_2D, 0);
  335.  
  336.     render->back_buffer = EGL_DRM_BUFFER_BACK;
  337.  
  338.     context = eglGetCurrentContext();
  339.  
  340.     config_attribs[0] = EGL_RED_SIZE;
  341.     config_attribs[1] = 1;
  342.     config_attribs[2] = EGL_GREEN_SIZE;
  343.     config_attribs[3] = 1;
  344.     config_attribs[4] = EGL_BLUE_SIZE;
  345.     config_attribs[5] = 1;
  346.     config_attribs[6] = EGL_DEPTH_SIZE;
  347.     config_attribs[7] = 1;
  348.  
  349.     config_attribs[8] = EGL_SURFACE_TYPE;
  350.     config_attribs[9] = EGL_WINDOW_BIT;
  351.  
  352.     config_attribs[10] = EGL_RENDERABLE_TYPE;
  353.     config_attribs[11] = EGL_OPENGL_BIT;
  354.     config_attribs[12] = EGL_NONE;
  355.  
  356.     if (!eglChooseConfig(dpy,config_attribs, &config, 1, &num_configs) || !num_configs)
  357.     {
  358.         printf("failed to choose a config");
  359.         goto err4;
  360.     }
  361.  
  362.     render->context = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL);
  363.     if (!context)
  364.     {
  365.         printf("failed to create context");
  366.         goto err4;
  367.     };
  368.  
  369.     if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, render->context))
  370.     {
  371.         printf("failed to make window current");
  372.         goto err5;
  373.     };
  374.  
  375.     render->screen = px_create_image(dpy,context,fb.width,fb.height,
  376.                                      fb.pitch,fb.name);
  377.     if(render->screen == EGL_NO_IMAGE_KHR)
  378.         goto err6;
  379.  
  380.     glGenTextures(1, &render->tx_screen);
  381.     if(glGetError() != GL_NO_ERROR)
  382.        goto err6;
  383.  
  384.     glBindTexture(GL_TEXTURE_2D, render->tx_screen);
  385.     if(glGetError() != GL_NO_ERROR)
  386.        goto err7;
  387.  
  388.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  389.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  390.     glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,render->screen);
  391.     if(glGetError() != GL_NO_ERROR)
  392.        goto err7;
  393.  
  394.     glBindTexture(GL_TEXTURE_2D, 0);
  395.  
  396.     glGenFramebuffers(1, &render->framebuffer);
  397.     if(glGetError() != GL_NO_ERROR)
  398.        goto err8;
  399.  
  400.     glBindFramebuffer(GL_FRAMEBUFFER, render->framebuffer);
  401.     if(glGetError() != GL_NO_ERROR)
  402.        goto err9;
  403.  
  404.     glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,
  405.                            GL_TEXTURE_2D, render->tx_screen,0);
  406.  
  407.     status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  408.     if (status != GL_FRAMEBUFFER_COMPLETE)
  409.     {
  410.         const char *str;
  411.         switch (status)
  412.         {
  413.             case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
  414.                  str = "incomplete attachment";
  415.                  break;
  416.             case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
  417.                 str = "incomplete/missing attachment";
  418.                 break;
  419.             case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
  420.                 str = "incomplete draw buffer";
  421.                 break;
  422.             case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
  423.                 str = "incomplete read buffer";
  424.                 break;
  425.             case GL_FRAMEBUFFER_UNSUPPORTED:
  426.                 str = "unsupported";
  427.                 break;
  428.             case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
  429.                 str = "incomplete multiple";
  430.                 break;
  431.             default:
  432.                 str = "unknown error";
  433.                 break;
  434.         }
  435.         printf("destination is framebuffer incomplete: %s [%#x]\n", str, status);
  436.         goto err9;
  437.     }
  438.  
  439.     render->blit_prog = glCreateProgram();
  440.     if(render->blit_prog == 0)
  441.         goto err9;
  442.  
  443.     vs_shader = create_shader(GL_VERTEX_SHADER,vs_src);
  444.     if(vs_shader == 0)
  445.         goto err10;
  446.  
  447.     fs_shader = create_shader(GL_FRAGMENT_SHADER, fs_src);
  448.     if(fs_shader == 0)
  449.         goto err11;
  450.  
  451.     glAttachShader(render->blit_prog, vs_shader);
  452.     glAttachShader(render->blit_prog, fs_shader);
  453.     glBindAttribLocation(render->blit_prog, 0, "v_position");
  454.     glBindAttribLocation(render->blit_prog, 1, "v_texcoord0");
  455.     glLinkProgram(render->blit_prog);
  456.  
  457.     glGetProgramiv(render->blit_prog, GL_LINK_STATUS, &ret);
  458.     if (!ret)
  459.     {
  460.         GLchar *info;
  461.         GLint size;
  462.  
  463.         glGetProgramiv(render->blit_prog, GL_INFO_LOG_LENGTH, &size);
  464.         info = malloc(size);
  465.  
  466.         glGetProgramInfoLog(render->blit_prog, size, NULL, info);
  467.         printf("Failed to link: %s\n", info);
  468.         printf("GLSL link failure\n");
  469.         free(info);
  470.     }
  471.  
  472.     render->sampler = glGetUniformLocation(render->blit_prog,"sampler");
  473.  
  474.     eglMakeCurrent(dpy, surface, surface, context);
  475.  
  476.     return render;
  477.  
  478. err11:
  479.     glDeleteShader(vs_shader);
  480. err10:
  481.     glDeleteProgram(render->blit_prog);
  482. err9:
  483.     glDeleteFramebuffers(1, &render->framebuffer);
  484. err8:
  485.     eglDestroyImageKHR(dpy, render->screen);
  486. err7:
  487.     glDeleteTextures(1, &render->tx_screen);
  488. err6:
  489.     eglMakeCurrent(dpy, surface, surface, context);
  490. err5:
  491.     eglDestroyContext(dpy, render->context);
  492. err4:
  493.     glDeleteTextures(2, render->tx_buffers);
  494. err3:
  495.     eglDestroyImageKHR(dpy, render->back);
  496. err2:
  497.     eglDestroyImageKHR(dpy, render->front);
  498. err1:
  499.     free(render);
  500. err:
  501.     return NULL;
  502. };
  503.  
  504. void render_swap_buffers(struct render *render, int x, int y, int w, int h)
  505. {
  506.     EGLContext context;
  507.     EGLSurface draw, read;
  508.  
  509.     float dst_xscale, dst_yscale;
  510.     float *vertices  = render->vertices;
  511.     float *texcoords = render->texcoords;
  512.     int r, b;
  513.  
  514.     if(render == NULL)
  515.         return;
  516.  
  517.     context = eglGetCurrentContext();
  518.     draw = eglGetCurrentSurface(EGL_DRAW);
  519.     read = eglGetCurrentSurface(EGL_READ);
  520.  
  521.     eglSwapBuffers(render->dpy,draw);
  522.  
  523.     if (!eglMakeCurrent(render->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, render->context))
  524.     {
  525.         printf("failed to make window current");
  526.         goto err1;
  527.     };
  528.  
  529.     glUseProgram(render->blit_prog);
  530.     glUniform1i(render->sampler, 0);
  531.  
  532.     glVertexAttribPointer(0, 2, GL_FLOAT,GL_FALSE, 2 * sizeof(float),render->vertices);
  533.     glEnableVertexAttribArray(0);
  534.  
  535.     glActiveTexture(GL_TEXTURE0);
  536.     glBindTexture(GL_TEXTURE_2D, render->tx_buffers[render->back_buffer]);
  537.     glTexParameteri(GL_TEXTURE_2D,
  538.                   GL_TEXTURE_MIN_FILTER,
  539.                   GL_NEAREST);
  540.     glTexParameteri(GL_TEXTURE_2D,
  541.                   GL_TEXTURE_MAG_FILTER,
  542.                   GL_NEAREST);
  543.  
  544.     glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float),render->texcoords);
  545.     glEnableVertexAttribArray(1);
  546.  
  547.     dst_xscale = 1.0/1024;
  548.     dst_yscale = 1.0/768;
  549.  
  550.     r = x+w-1;
  551.     b = y+h-1;
  552.  
  553.     float t0, t1, t2, t5;
  554.  
  555.     vertices[0]     = t0 = 2*x*dst_xscale - 1.0;
  556.     vertices[1 * 2] = t2 = 2*r*dst_xscale - 1.0;
  557.  
  558.     vertices[2 * 2] = t2;
  559.     vertices[3 * 2] = t0;
  560.  
  561.     vertices[1]     = t1 = 2*y*dst_yscale - 1.0;
  562.     vertices[2*2+1] = t5 = 2*b*dst_yscale - 1.0;
  563.     vertices[1*2+1] = t1;
  564.     vertices[3*2+1] = t5;
  565.  
  566.     texcoords[0]    = 0.0;
  567.     texcoords[1]    = 0.0;
  568.     texcoords[1*2]  = 1.0;
  569.     texcoords[1*2+1]= 0.0;
  570.     texcoords[2*2]  = 1.0;
  571.     texcoords[2*2+1]= 1.0;
  572.     texcoords[3*2]  = 0.0;
  573.     texcoords[3*2+1]= 1.0;
  574.  
  575.     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
  576.  
  577.     glDisableVertexAttribArray(0);
  578.     glDisableVertexAttribArray(1);
  579.     glDisable(GL_TEXTURE_2D);
  580.     glUseProgram(0);
  581.  
  582.     render->back_buffer++;
  583.     render->back_buffer&=1;
  584.  
  585. err1:
  586.     eglMakeCurrent(render->dpy, draw, read, context);
  587. }
  588.  
  589. #if 0
  590. GLuint create_framebuffer(int width, int height, GLuint *tex)
  591. {
  592.     GLuint buffer;
  593.  
  594.     glGenTextures(1, tex);
  595.     glBindTexture(GL_TEXTURE_2D, *tex);
  596.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  597.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  598.  
  599.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
  600.                                GL_UNSIGNED_BYTE, NULL);
  601.     glBindTexture(GL_TEXTURE_2D, 0);
  602.  
  603.     glGenFramebuffers(1, &buffer);
  604.     glBindFramebuffer(GL_FRAMEBUFFER, buffer);
  605.     glFramebufferTexture2D(GL_FRAMEBUFFER,
  606.                                          GL_COLOR_ATTACHMENT0,
  607.                                          GL_TEXTURE_2D, *tex,0);
  608.    return buffer;
  609. }
  610. #endif
  611.