add support for render-to-texture

This commit is contained in:
David Rose 2005-03-01 01:08:57 +00:00
parent 2e58c8d9d8
commit 7f609122ff
6 changed files with 308 additions and 157 deletions

View File

@ -43,6 +43,7 @@ wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
// Since the pbuffer never gets flipped, we get screenshots from the // Since the pbuffer never gets flipped, we get screenshots from the
// same buffer we draw into. // same buffer we draw into.
_screenshot_buffer_type = _draw_buffer_type; _screenshot_buffer_type = _draw_buffer_type;
_render_texture = false;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -72,6 +73,12 @@ begin_frame() {
wglGraphicsStateGuardian *wglgsg; wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_R(wglgsg, _gsg, false); DCAST_INTO_R(wglgsg, _gsg, false);
if (_render_texture) {
// Release the texture so we can render into the pbuffer.
// wglgsg->_wglReleaseTexImageARB(_pbuffer, get_draw_buffer_type() == RenderBuffer::T_back ? WGL_BACK_LEFT_ARB : WGL_FRONT_LEFT_ARB);
wglgsg->_wglReleaseTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
}
if (_pbuffer_dc) { if (_pbuffer_dc) {
int flag = 0; int flag = 0;
wglgsg->_wglQueryPbufferARB(_pbuffer, WGL_PBUFFER_LOST_ARB, &flag); wglgsg->_wglQueryPbufferARB(_pbuffer, WGL_PBUFFER_LOST_ARB, &flag);
@ -100,6 +107,7 @@ end_frame() {
nassertv(_gsg != (GraphicsStateGuardian *)NULL); nassertv(_gsg != (GraphicsStateGuardian *)NULL);
_gsg->end_frame(); _gsg->end_frame();
if (_copy_texture) { if (_copy_texture) {
wglGraphicsStateGuardian *wglgsg; wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_V(wglgsg, _gsg); DCAST_INTO_V(wglgsg, _gsg);
@ -118,15 +126,29 @@ end_frame() {
} }
} }
// For now, we copy the framebuffer to the texture every frame.
// Eventually we can take advantage of the render_texture
// extension, if it is available, to render directly into a
// texture in the first place (but I don't have a card that
// supports that right now).
nassertv(has_texture()); nassertv(has_texture());
Texture *tex = get_texture();
RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type()); if (_render_texture) {
_gsg->copy_texture(get_texture(), _default_display_region, buffer); // Bind the pbuffer to our associated texture. This is a newer
// extension that might allow us to use the same memory directly
// without having to pay for a copy operation. But we can't
// render again to the pbuffer while the texture is valid.
TextureContext *tc = tex->prepare_now(wglgsg->get_prepared_objects(), wglgsg);
nassertv(tc != (TextureContext *)NULL);
wglgsg->bind_texture(tc);
// wglgsg->_wglBindTexImageARB(_pbuffer, get_draw_buffer_type() == RenderBuffer::T_back ? WGL_BACK_LEFT_ARB : WGL_FRONT_LEFT_ARB);
wglgsg->_wglBindTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
} else {
// Copy the contents of the frame buffer to our associated
// texture. This is an older interface that guarantees a copy
// operation will take place, and it might even require
// reformatting pixels on the way, so it may be slower.
RenderBuffer buffer = wglgsg->get_render_buffer(get_draw_buffer_type());
wglgsg->copy_texture(tex, _default_display_region, buffer);
}
} }
} }
@ -245,6 +267,13 @@ open_buffer() {
if (wgldisplay_cat.is_debug()) { if (wgldisplay_cat.is_debug()) {
wgldisplay_cat.debug() wgldisplay_cat.debug()
<< "Created PBuffer " << _pbuffer << ", DC " << _pbuffer_dc << "\n"; << "Created PBuffer " << _pbuffer << ", DC " << _pbuffer_dc << "\n";
if (_render_texture) {
wgldisplay_cat.debug()
<< "pbuffer renders directly to texture.\n";
} else if (_copy_texture) {
wgldisplay_cat.debug()
<< "pbuffer copies indirectly into texture.\n";
}
} }
wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc)); wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc));
@ -277,8 +306,90 @@ make_pbuffer(HDC twindow_dc) {
int pbformat = wglgsg->get_pfnum(); int pbformat = wglgsg->get_pfnum();
if (wglgsg->_supports_pixel_format) { if (wglgsg->_supports_pixel_format) {
// Select a suitable pixel format that matches the GSG's existing bool got_pbuffer_format = false;
// format, and also is appropriate for a pixel buffer.
if (_copy_texture && wglgsg->_supports_render_texture) {
// First, try to get a pbuffer format that supports
// render-to-texture.
int new_pbformat = choose_pbuffer_format(twindow_dc, true);
if (new_pbformat != 0) {
pbformat = new_pbformat;
got_pbuffer_format = true;
_render_texture = true;
}
}
if (!got_pbuffer_format) {
// Failing that, just get a matching pbuffer format.
int new_pbformat = choose_pbuffer_format(twindow_dc, false);
if (new_pbformat != 0) {
pbformat = new_pbformat;
got_pbuffer_format = true;
}
}
if (wgldisplay_cat.is_debug()) {
FrameBufferProperties properties;
wglGraphicsPipe::get_properties_advanced(properties, wglgsg,
twindow_dc, pbformat);
wgldisplay_cat.debug()
<< "Chose pixfmt #" << pbformat << " for pbuffer = "
<< properties << "\n";
}
}
static const int max_attrib_list = 64;
int iattrib_list[max_attrib_list];
int ni = 0;
if (_render_texture) {
if (_gsg->get_properties().get_frame_buffer_mode() & FrameBufferProperties::FM_alpha) {
iattrib_list[ni++] = WGL_TEXTURE_FORMAT_ARB;
iattrib_list[ni++] = WGL_TEXTURE_RGBA_ARB;
} else {
iattrib_list[ni++] = WGL_TEXTURE_FORMAT_ARB;
iattrib_list[ni++] = WGL_TEXTURE_RGB_ARB;
}
iattrib_list[ni++] = WGL_TEXTURE_TARGET_ARB;
iattrib_list[ni++] = WGL_TEXTURE_2D_ARB;
}
// Terminate the list.
nassertr(ni <= max_attrib_list, false);
iattrib_list[ni] = 0;
_pbuffer = wglgsg->_wglCreatePbufferARB(twindow_dc, pbformat,
_x_size, _y_size, iattrib_list);
if (_pbuffer == 0) {
wgldisplay_cat.info()
<< "Attempt to create pbuffer failed.\n";
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsBuffer::choose_pbuffer_format
// Access: Private
// Description: Select a suitable pixel format that matches the GSG's
// existing format, and also is appropriate for a pixel
// buffer. Returns the selected pfnum if successful, or
// 0 on failure.
////////////////////////////////////////////////////////////////////
int wglGraphicsBuffer::
choose_pbuffer_format(HDC twindow_dc, bool draw_to_texture) {
if (wgldisplay_cat.is_debug()) {
wgldisplay_cat.debug()
<< "choose_pbuffer_format(twindow_dc, draw_to_texture = "
<< draw_to_texture << ")\n";
}
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_R(wglgsg, _gsg, false);
int pbformat = wglgsg->get_pfnum();
static const int max_attrib_list = 64; static const int max_attrib_list = 64;
int iattrib_list[max_attrib_list]; int iattrib_list[max_attrib_list];
@ -316,7 +427,11 @@ make_pbuffer(HDC twindow_dc) {
if (!wglgsg->_wglGetPixelFormatAttribivARB(twindow_dc, pbformat, 0, if (!wglgsg->_wglGetPixelFormatAttribivARB(twindow_dc, pbformat, 0,
ni, iattrib_list, ivalue_list)) { ni, iattrib_list, ivalue_list)) {
return false; if (wgldisplay_cat.is_debug()) {
wgldisplay_cat.debug()
<< "Could not query old format " << pbformat << ".\n";
}
return 0;
} }
ni = 0; ni = 0;
@ -330,6 +445,17 @@ make_pbuffer(HDC twindow_dc) {
iattrib_list[ni++] = WGL_SUPPORT_OPENGL_ARB; iattrib_list[ni++] = WGL_SUPPORT_OPENGL_ARB;
iattrib_list[ni++] = true; iattrib_list[ni++] = true;
if (draw_to_texture) {
// If we want to be able to render-to-texture, request that.
if (_gsg->get_properties().get_frame_buffer_mode() & FrameBufferProperties::FM_alpha) {
iattrib_list[ni++] = WGL_BIND_TO_TEXTURE_RGBA_ARB;
iattrib_list[ni++] = true;
} else {
iattrib_list[ni++] = WGL_BIND_TO_TEXTURE_RGB_ARB;
iattrib_list[ni++] = true;
}
}
// Match up the framebuffer bits. // Match up the framebuffer bits.
iattrib_list[ni++] = WGL_RED_BITS_ARB; iattrib_list[ni++] = WGL_RED_BITS_ARB;
iattrib_list[ni++] = ivalue_list[red_bits_i]; iattrib_list[ni++] = ivalue_list[red_bits_i];
@ -382,9 +508,11 @@ make_pbuffer(HDC twindow_dc) {
if (!wglgsg->_wglChoosePixelFormatARB(twindow_dc, iattrib_list, fattrib_list, if (!wglgsg->_wglChoosePixelFormatARB(twindow_dc, iattrib_list, fattrib_list,
max_pformats, pformat, &nformats) max_pformats, pformat, &nformats)
|| nformats == 0) { || nformats == 0) {
wgldisplay_cat.info() if (wgldisplay_cat.is_debug()) {
<< "Couldn't find a suitable pixel format for creating a pbuffer.\n"; wgldisplay_cat.debug()
return false; << "No formats meet the criteria.\n";
}
return 0;
} }
nformats = min(nformats, max_pformats); nformats = min(nformats, max_pformats);
@ -412,27 +540,8 @@ make_pbuffer(HDC twindow_dc) {
// Otherwise, pick any of them. // Otherwise, pick any of them.
pbformat = pformat[0]; pbformat = pformat[0];
} }
}
if (wgldisplay_cat.is_debug()) { return pbformat;
wgldisplay_cat.debug()
<< "Chose pixfmt #" << pbformat << " for pbuffer\n";
}
int attrib_list[] = {
0,
};
_pbuffer = wglgsg->_wglCreatePbufferARB(twindow_dc, pbformat,
_x_size, _y_size, attrib_list);
if (_pbuffer == 0) {
wgldisplay_cat.info()
<< "Attempt to create pbuffer failed.\n";
return false;
}
return true;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -60,11 +60,13 @@ protected:
private: private:
bool make_pbuffer(HDC window_dc); bool make_pbuffer(HDC window_dc);
int choose_pbuffer_format(HDC twindow_dc, bool draw_to_texture);
static void process_1_event(); static void process_1_event();
HPBUFFERARB _pbuffer; HPBUFFERARB _pbuffer;
HDC _pbuffer_dc; HDC _pbuffer_dc;
bool _render_texture;
public: public:
static TypeHandle get_class_type() { static TypeHandle get_class_type() {

View File

@ -329,6 +329,18 @@ int wglGraphicsPipe::
try_for_pfnum(HDC hdc, bool hardware, bool software, int frame_buffer_mode, try_for_pfnum(HDC hdc, bool hardware, bool software, int frame_buffer_mode,
int want_depth_bits, int want_color_bits, int want_depth_bits, int want_color_bits,
int want_alpha_bits, int want_stencil_bits) { int want_alpha_bits, int want_stencil_bits) {
if (wgldisplay_cat.is_debug()) {
wgldisplay_cat.debug()
<< "try_for_pfnum(hdc, hardware = " << hardware
<< ", software = " << software
<< ", frame_buffer_mode = 0x" << hex << frame_buffer_mode << dec
<< ", want_depth_bits = " << want_depth_bits
<< ", want_color_bits = " << want_color_bits
<< ", want_alpha_bits = " << want_alpha_bits
<< ", want_stencil_bits = " << want_stencil_bits
<< ")\n";
}
PIXELFORMATDESCRIPTOR pfd; PIXELFORMATDESCRIPTOR pfd;
ZeroMemory(&pfd,sizeof(PIXELFORMATDESCRIPTOR)); ZeroMemory(&pfd,sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
@ -348,16 +360,6 @@ try_for_pfnum(HDC hdc, bool hardware, bool software, int frame_buffer_mode,
break; break;
} }
wgldisplay_cat.debug()
<< "try_for_pfnum(hdc, hardware = " << hardware
<< ", software = " << software
<< ", frame_buffer_mode = 0x" << hex << frame_buffer_mode << dec
<< ", want_depth_bits = " << want_depth_bits
<< ", want_color_bits = " << want_color_bits
<< ", want_alpha_bits = " << want_alpha_bits
<< ", want_stencil_bits = " << want_stencil_bits
<< ")\n";
// We have to call DescribePixelFormat() once just to get the // We have to call DescribePixelFormat() once just to get the
// highest pfnum available. Then we can iterate through all of the // highest pfnum available. Then we can iterate through all of the
// pfnums. // pfnums.
@ -647,6 +649,18 @@ try_for_pfnum_advanced(int orig_pfnum, const wglGraphicsStateGuardian *wglgsg,
int want_depth_bits, int want_color_bits, int want_depth_bits, int want_color_bits,
int want_alpha_bits, int want_stencil_bits, int want_alpha_bits, int want_stencil_bits,
int want_multisamples) { int want_multisamples) {
if (wgldisplay_cat.is_debug()) {
wgldisplay_cat.debug()
<< "try_for_pfnum_advanced(orig_pfnum = " << orig_pfnum
<< ", wglgsg, window_dc, frame_buffer_mode = 0x" << hex << frame_buffer_mode << dec
<< ", want_depth_bits = " << want_depth_bits
<< ", want_color_bits = " << want_color_bits
<< ", want_alpha_bits = " << want_alpha_bits
<< ", want_stencil_bits = " << want_stencil_bits
<< ", want_multisamples = " << want_multisamples
<< ")\n";
}
static const int max_attrib_list = 32; static const int max_attrib_list = 32;
int iattrib_list[max_attrib_list]; int iattrib_list[max_attrib_list];
float fattrib_list[max_attrib_list]; float fattrib_list[max_attrib_list];
@ -727,8 +741,8 @@ try_for_pfnum_advanced(int orig_pfnum, const wglGraphicsStateGuardian *wglgsg,
max_pformats, pformat, &nformats) || max_pformats, pformat, &nformats) ||
nformats == 0) { nformats == 0) {
if (wgldisplay_cat.is_debug()) { if (wgldisplay_cat.is_debug()) {
wgldisplay_cat.info() wgldisplay_cat.debug()
<< "Couldn't find a suitable advanced pixel format.\n"; << "No formats meet the criteria.\n";
} }
return 0; return 0;
} }

View File

@ -86,6 +86,8 @@ public:
private: private:
static TypeHandle _type_handle; static TypeHandle _type_handle;
friend class wglGraphicsBuffer;
}; };
#include "wglGraphicsPipe.I" #include "wglGraphicsPipe.I"

View File

@ -46,6 +46,7 @@ wglGraphicsStateGuardian(const FrameBufferProperties &properties,
_supports_pbuffer = false; _supports_pbuffer = false;
_supports_pixel_format = false; _supports_pixel_format = false;
_supports_wgl_multisample = false; _supports_wgl_multisample = false;
_supports_render_texture = false;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -75,6 +76,7 @@ reset() {
_supports_pbuffer = has_extension("WGL_ARB_pbuffer"); _supports_pbuffer = has_extension("WGL_ARB_pbuffer");
_supports_pixel_format = has_extension("WGL_ARB_pixel_format"); _supports_pixel_format = has_extension("WGL_ARB_pixel_format");
_supports_wgl_multisample = has_extension("WGL_ARB_multisample"); _supports_wgl_multisample = has_extension("WGL_ARB_multisample");
_supports_render_texture = has_extension("WGL_ARB_render_texture");
_wglCreatePbufferARB = _wglCreatePbufferARB =
(PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB"); (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
@ -115,6 +117,23 @@ reset() {
_supports_pixel_format = false; _supports_pixel_format = false;
} }
} }
_wglBindTexImageARB =
(PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress("wglBindTexImageARB");
_wglReleaseTexImageARB =
(PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress("wglReleaseTexImageARB");
_wglSetPbufferAttribARB =
(PFNWGLSETPBUFFERATTRIBARBPROC)wglGetProcAddress("wglSetPbufferAttribARB");
if (_supports_render_texture) {
if (_wglBindTexImageARB == NULL ||
_wglReleaseTexImageARB == NULL ||
_wglSetPbufferAttribARB == NULL) {
wgldisplay_cat.error()
<< "Driver claims to support WGL_ARB_render_texture, but does not define all functions.\n";
_supports_render_texture = false;
}
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -82,7 +82,6 @@ private:
public: public:
bool _supports_pbuffer; bool _supports_pbuffer;
PFNWGLCREATEPBUFFERARBPROC _wglCreatePbufferARB; PFNWGLCREATEPBUFFERARBPROC _wglCreatePbufferARB;
PFNWGLGETPBUFFERDCARBPROC _wglGetPbufferDCARB; PFNWGLGETPBUFFERDCARBPROC _wglGetPbufferDCARB;
PFNWGLRELEASEPBUFFERDCARBPROC _wglReleasePbufferDCARB; PFNWGLRELEASEPBUFFERDCARBPROC _wglReleasePbufferDCARB;
@ -90,13 +89,17 @@ public:
PFNWGLQUERYPBUFFERARBPROC _wglQueryPbufferARB; PFNWGLQUERYPBUFFERARBPROC _wglQueryPbufferARB;
bool _supports_pixel_format; bool _supports_pixel_format;
PFNWGLGETPIXELFORMATATTRIBIVARBPROC _wglGetPixelFormatAttribivARB; PFNWGLGETPIXELFORMATATTRIBIVARBPROC _wglGetPixelFormatAttribivARB;
PFNWGLGETPIXELFORMATATTRIBFVARBPROC _wglGetPixelFormatAttribfvARB; PFNWGLGETPIXELFORMATATTRIBFVARBPROC _wglGetPixelFormatAttribfvARB;
PFNWGLCHOOSEPIXELFORMATARBPROC _wglChoosePixelFormatARB; PFNWGLCHOOSEPIXELFORMATARBPROC _wglChoosePixelFormatARB;
bool _supports_wgl_multisample; bool _supports_wgl_multisample;
bool _supports_render_texture;
PFNWGLBINDTEXIMAGEARBPROC _wglBindTexImageARB;
PFNWGLRELEASETEXIMAGEARBPROC _wglReleaseTexImageARB;
PFNWGLSETPBUFFERATTRIBARBPROC _wglSetPbufferAttribARB;
public: public:
static TypeHandle get_class_type() { static TypeHandle get_class_type() {
return _type_handle; return _type_handle;
@ -113,6 +116,8 @@ public:
private: private:
static TypeHandle _type_handle; static TypeHandle _type_handle;
friend class wglGraphicsBuffer;
}; };
#include "wglGraphicsStateGuardian.I" #include "wglGraphicsStateGuardian.I"