Terrence Crane (tcrane++at++headcase.esd.sgi.com)
Thu, 13 Feb 1997 01:07:24 -0800
Remi, Dave -
O2 will support 1k square textures. If you plan to render your textures,
the best approach on O2 is to use Digital Media Pbuffers, an addition to
the SGI pbuffer extension. When set up correctly so that the pbuffer and
texture object are the same size and depth, copying the texture can be done
by reference, and you will essentially be able to render directly to texture
memory.
There are brief descriptions in the 6.3 manpages for glXCreateGLXPbufferSGIX,
glXAssociateDMPbufferSGIX, glCopyTexSubImage2DEXT, and dmBufferGetGLPoolParams.
I'll append a simple sample program. If you have trouble adapting it for
your use, let me know.
/Terry
| Terrence Crane | Silicon Graphics, MS 945
| tcrane++at++esd.sgi.com | 2011 N. Shoreline Blvd.
| (415) 933-4047 | Mountain View, CA 94043
/*
**
** A simple example that creates multiple dmpbuffers, renderers
** a texture image to the dmpbuffer, and then copies the pbuffer
** to a GL texture object.
** On O2 systems this path for defining textures can be done at
** hardware rendering or pixel transfer DMA rates, when the following
** conditions are met:
** - The DMbuffer, pbuffer and texture object all match in terms of
** width, height and depth of RGBA components.
** - The texture image is 64x64 or larger.
** - The glCopyTexSubImageEXT command is used to copy the entire
** image from dmpbuffer to texture.
**
**
** cc dmtexobj.c -o dmtexobj -lGL -lX11 -ldmedia
**
*/
#include <dmedia/dm_buffer.h>
#include <dmedia/dm_image.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/keysym.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#define nTEXTURES 2
#define TEX_W 128
#define TEX_H 128
#define WIN_W 300
#define WIN_H 300
Display *dpy;
GLuint width, height;
GLXContext windowCtx, pbufCtx;
GLXPbufferSGIX window, dmpbuf[nTEXTURES];
DMbuffer dmBuf[nTEXTURES];
DMparams *dmParams;
GLuint texObj[nTEXTURES];
GLfloat spin = 0;
GLint spinning = 1;
GLuint texture = 0;
GLuint *pixels, Pixels[TEX_W*TEX_H*2];
GLint updateTextures = 1;
/*
** Define and alloc DMbuffers to be used as pbuffers / textures.
*/
void init_dm(int texelDepth, int mipmap) {
DMparams *poolParams;
DMbufferpool pool;
DMstatus status;
DMpacking dmPacking;
DMimagelayout dmLayout;
int i;
switch(texelDepth) {
case 16:
dmPacking = DM_IMAGE_PACKING_XRGB1555;
texelDepth = 2;
break;
default:
dmPacking = DM_IMAGE_PACKING_RGBA;
texelDepth = 4;
}
switch(mipmap) {
case GL_TRUE:
dmLayout = DM_IMAGE_LAYOUT_MIPMAP;
default:
dmLayout = DM_IMAGE_LAYOUT_GRAPHICS;
}
status = dmParamsCreate(&dmParams);
status = dmSetImageDefaults(dmParams, TEX_W, TEX_H, dmPacking);
status = dmParamsSetEnum(dmParams, DM_IMAGE_LAYOUT, dmLayout);
status = dmParamsCreate(&poolParams);
status = dmBufferSetPoolDefaults(poolParams, nTEXTURES,
(((TEX_W*TEX_H*texelDepth) + 0xffff) & ~0xffff),
DM_FALSE, DM_FALSE);
status = dmBufferGetGLPoolParams(dmParams, poolParams);
status = dmBufferCreatePool(poolParams, &pool);
for(i = 0; i < nTEXTURES; i++) {
status = dmBufferAllocate(pool, &dmBuf[i]);
}
}
/*
** Create dmpbuffers and associate them with a matching DMbuffer.
** Copy the dmpuffer to a texture object to establish the initial
** connection for optimized MakeCurrentReads in future updates.
*/
void init_tex(int texelDepth, int mipmap) {
GLint i, n, redSize, texelFormat, *attrib;
GLXFBConfigSGIX *config;
GLint attrib32[] = {GLX_DOUBLEBUFFER, GL_FALSE,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DRAWABLE_TYPE_SGIX, GLX_PBUFFER_BIT_SGIX,
None};
GLint attrib16[] = {GLX_DOUBLEBUFFER, GL_FALSE,
GLX_RED_SIZE, 5,
GLX_GREEN_SIZE, 5,
GLX_BLUE_SIZE, 5,
GLX_ALPHA_SIZE, 1,
GLX_DRAWABLE_TYPE_SGIX, GLX_PBUFFER_BIT_SGIX,
None};
GLint pbattrib[] = {GLX_DIGITAL_MEDIA_PBUFFER_SGIX, GL_TRUE,
None};
switch(texelDepth) {
case 16:
attrib = attrib16;
redSize = 5;
texelFormat = GL_RGB5_A1_EXT;
break;
default:
attrib = attrib32;
redSize = 8;
texelFormat = GL_RGBA8_EXT;
}
if (!(config = glXChooseFBConfigSGIX(dpy, DefaultScreen(dpy),
attrib, &n))) {
fprintf(stderr, "can't find suitable FBConfig\n");
exit(EXIT_FAILURE);
}
while(n) {
int bits;
glXGetFBConfigAttribSGIX(dpy, *config, GLX_RED_SIZE, &bits);
if (bits == redSize) break;
config++; n--;
}
if (!n) {
fprintf(stderr, "can't find suitable FBConfig\n");
exit(EXIT_FAILURE);
}
if ((pbufCtx = glXCreateContextWithConfigSGIX(dpy, *config,
GLX_RGBA_TYPE_SGIX,
NULL, True)) == NULL) {
fprintf(stderr, "can't create context\n");
exit(EXIT_FAILURE);
}
glGenTexturesEXT(nTEXTURES, texObj);
for(i = 0; i < nTEXTURES; i++) {
dmpbuf[i] = glXCreateGLXPbufferSGIX(dpy, *config, TEX_W, TEX_H,
pbattrib);
/*
** The intial associate must occur before a dmpuffer can
** be made current to a context.
*/
glXAssociateDMPbufferSGIX(dpy, dmpbuf[i], dmParams, dmBuf[i]);
glXMakeCurrent(dpy, dmpbuf[i], pbufCtx);
glViewport(0, 0, TEX_W, TEX_H);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, TEX_W, 0, TEX_H, -1, 1);
glMatrixMode(GL_MODELVIEW);
glRasterPos2f(0, 0);
/*
** Make the dmpbuffer current as a readable, and copy
** it to the texture object of another context.
** When the size and format of the pbuffer and the texture
** are compatible, the O2 implementation allows this copy
** to be done by reference.
*/
glXMakeCurrentReadSGI(dpy, window, dmpbuf[i], windowCtx);
glBindTextureEXT(GL_TEXTURE_2D, texObj[i]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (mipmap) {
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
}
glTexImage2D(GL_TEXTURE_2D, 0, texelFormat, TEX_W, TEX_H, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glCopyTexSubImage2DEXT(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TEX_W, TEX_H);
}
}
static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg) {
return((e->type == MapNotify) && (e->xmap.window == (Window)arg));
}
void init_win(void) {
XVisualInfo *vi;
Colormap cmap;
XSetWindowAttributes swa;
XEvent event;
GLuint i, pix, npixels;
GLint attribRGB[] = {GLX_DOUBLEBUFFER,
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 1,
None};
dpy = XOpenDisplay(0);
if (!dpy) {
fprintf(stderr, "Can't connect to display\n");
exit(EXIT_FAILURE);
}
vi = glXChooseVisual(dpy, DefaultScreen(dpy), attribRGB);
if (!vi) {
fprintf(stderr, "can't find suitable Visual\n");
exit(EXIT_FAILURE);
}
cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual,
AllocNone);
swa.border_pixel = 0;
swa.colormap = cmap;
swa.event_mask = ExposureMask | StructureNotifyMask |
KeyPressMask | KeyReleaseMask;
width = WIN_W;
height = WIN_H;
window = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 10, 10,
WIN_W, WIN_H, 0, vi->depth, InputOutput, vi->visual,
CWBorderPixel|CWColormap|CWEventMask, &swa);
XSetWMColormapWindows(dpy, window, &window, 1);
XMapWindow(dpy, window);
XIfEvent(dpy, &event, WaitForMapNotify, (char*)window);
windowCtx = glXCreateContext(dpy, vi, 0, GL_TRUE);
if (!glXMakeCurrent(dpy, window, windowCtx)) {
fprintf(stderr, "Can't make window current to context\n");
exit(EXIT_FAILURE);
}
glClearColor(0, 0.1, 0, 0);
glColor3f(0, 1, 0);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE_EXT);
npixels = TEX_W * TEX_H * 2;
for (i = 0, pix = 0x7b8c9eaf; i < npixels; i++) {
pix = (pix * 8191) + 0x70615243;
Pixels[i] = ((pix & 0xff)<<24) | ((pix & 0xff00)<< 8) |
((pix & 0xff0000)>>8) | ((pix & 0xff000000)>>24);
}
pixels = Pixels;
}
/*
** Dynamically load texture objects at pixel transfer dma rates,
** by drawing pixels to a dmpbuffer and copying to the texture object.
** Textures can alternately be rendered, or generated in DMbuffer form
** by the video or compression libraries.
*/
void redraw(void) {
int i;
if (updateTextures) {
glXMakeCurrent(dpy, dmpbuf[texture], pbufCtx);
glDrawPixels(TEX_W, TEX_H, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
if (pixels == &Pixels[TEX_W*TEX_H]) {
pixels = Pixels;
} else {
pixels += 2;
}
}
glXMakeCurrentReadSGI(dpy, window, dmpbuf[texture], windowCtx);
glClear(GL_COLOR_BUFFER_BIT);
glBindTextureEXT(GL_TEXTURE_2D, texObj[texture]);
glCopyTexSubImage2DEXT(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TEX_W, TEX_H);
glPushMatrix();
glRotatef(spin, 0, 0, 1);
glBegin(GL_POLYGON);
glTexCoord2f(0, 0); glVertex2f(-0.72, -0.72);
glTexCoord2f(1, 0); glVertex2f( 0.72, -0.72);
glTexCoord2f(1, 1); glVertex2f( 0.72, 0.72);
glTexCoord2f(0, 1); glVertex2f(-0.72, 0.72);
glEnd();
glPopMatrix();
glPushMatrix();
glRotatef(-spin, 0, 0, 1);
glBegin(GL_POLYGON);
glTexCoord2f(1, 1); glVertex2f(-0.72, -0.72);
glTexCoord2f(0, 1); glVertex2f( 0.72, -0.72);
glTexCoord2f(0, 0); glVertex2f( 0.72, 0.72);
glTexCoord2f(1, 0); glVertex2f(-0.72, 0.72);
glEnd();
glPopMatrix();
glXSwapBuffers(dpy, window);
if (spinning) spin += 0.5;
if (spin > 360.0) spin -= 360.0;
texture = ++texture % nTEXTURES;
}
int main(int argc, char **argv) {
int i;
int texelDepth = 32;
int mipmap = 0;
width = WIN_W;
height = WIN_H;
init_win();
init_dm(texelDepth, mipmap);
init_tex(texelDepth, mipmap);
while (1) {
if (XPending(dpy)) {
XEvent event;
KeySym ks;
XNextEvent(dpy, &event);
switch(event.type) {
case KeyPress:
XLookupString(&event.xkey, NULL, 0, &ks, NULL);
switch(ks) {
case XK_Escape :
exit(EXIT_SUCCESS);
case XK_s:
spinning = !spinning;
break;
case XK_u:
updateTextures = !updateTextures;
break;
}
break;
case ConfigureNotify:
width = event.xconfigure.width;
height = event.xconfigure.height;
glViewport(0, 0, width, height);
break;
default:
break;
}
}
redraw();
}
}
/*****************************************************************************/
--======================================================================= List Archives, FAQ, FTP: http://www.sgi.com/Technology/Performer/ Submissions: info-performer++at++sgi.com Admin. requests: info-performer-request++at++sgi.com
This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:54:39 PDT