提交 e5912569 编写于 作者: J jp9000

add FBOs and render target loading

上级 83ddb920
......@@ -55,8 +55,8 @@ bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels,
}
bool gl_copy_texture(struct gs_device *device,
GLuint src, GLenum src_target,
GLuint dst, GLenum dst_target,
GLuint src, GLenum src_target,
uint32_t width, uint32_t height)
{
bool success = false;
......
......@@ -78,6 +78,12 @@ static inline bool gl_bind_renderbuffer(GLenum target, GLuint buffer)
return gl_success("glBindRendebuffer");
}
static inline bool gl_bind_framebuffer(GLenum target, GLuint buffer)
{
glBindFramebuffer(target, buffer);
return gl_success("glBindFramebuffer");
}
static inline bool gl_tex_param_f(GLenum target, GLenum param, GLfloat val)
{
glTexParameterf(target, param, val);
......@@ -101,8 +107,8 @@ extern bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels,
uint32_t width, uint32_t height, uint32_t size, void ***p_data);
extern bool gl_copy_texture(struct gs_device *device,
GLuint src, GLenum src_target,
GLuint dst, GLenum dst_target,
GLuint src, GLenum src_target,
uint32_t width, uint32_t height);
extern bool gl_create_buffer(GLenum target, GLuint *buffer, GLsizeiptr size,
......
......@@ -126,8 +126,8 @@ void device_stage_texture(device_t device, stagesurf_t dst, texture_t src)
if (!can_stage(dst, tex2d))
goto failed;
if (!gl_copy_texture(device, tex2d->base.texture, GL_TEXTURE_2D,
dst->texture, GL_TEXTURE_2D,
if (!gl_copy_texture(device, dst->texture, GL_TEXTURE_2D,
tex2d->base.texture, GL_TEXTURE_2D,
dst->width, dst->height))
goto failed;
......
......@@ -56,8 +56,14 @@ fail:
void device_destroy(device_t device)
{
if (device) {
size_t i;
for (i = 0; i < device->fbos.num; i++)
fbo_info_destroy(device->fbos.array[i]);
if (device->pipeline)
glDeleteProgramPipelines(1, &device->pipeline);
da_free(device->fbos);
gl_platform_destroy(device->plat);
bfree(device);
}
......@@ -348,18 +354,229 @@ zstencil_t device_getzstenciltarget(device_t device)
return device->cur_zstencil_buffer;
}
void device_setrendertarget(device_t device, texture_t tex,
zstencil_t zstencil)
static bool get_tex_dimensions(texture_t tex, uint32_t *width, uint32_t *height)
{
if (tex->type == GS_TEXTURE_2D) {
struct gs_texture_2d *tex2d = (struct gs_texture_2d*)tex;
*width = tex2d->width;
*height = tex2d->height;
return true;
} else if (tex->type == GS_TEXTURE_CUBE) {
struct gs_texture_cube *cube = (struct gs_texture_cube*)tex;
*width = cube->size;
*height = cube->size;
return true;
}
blog(LOG_ERROR, "Texture must be 2D or cubemap");
return false;
}
/*
* This automatically manages FBOs so that render targets are always given
* an FBO that matches their width/height/format to maximize optimization
*/
static struct fbo_info *get_fbo(struct gs_device *device, texture_t tex)
{
size_t i;
uint32_t width, height;
GLuint fbo;
struct fbo_info *ptr;
if (!get_tex_dimensions(tex, &width, &height))
return NULL;
for (i = 0; i < device->fbos.num; i++) {
ptr = device->fbos.array[i];
if (ptr->width == width && ptr->height == height &&
ptr->format == tex->format)
return ptr;
}
glGenFramebuffers(1, &fbo);
if (!gl_success("glGenFramebuffers"))
return NULL;
ptr = bmalloc(sizeof(struct fbo_info));
ptr->fbo = fbo;
ptr->width = width;
ptr->height = height;
ptr->format = tex->format;
ptr->cur_render_target = NULL;
ptr->cur_render_side = 0;
ptr->cur_zstencil_buffer = NULL;
da_push_back(device->fbos, &ptr);
return ptr;
}
static bool set_current_fbo(device_t device, struct fbo_info *fbo)
{
if (device->cur_fbo != fbo) {
GLuint fbo_obj = fbo ? fbo->fbo : 0;
if (!gl_bind_framebuffer(GL_DRAW_FRAMEBUFFER, fbo_obj))
return false;
}
device->cur_fbo = fbo;
return true;
}
static bool attach_rendertarget(struct fbo_info *fbo, texture_t tex, int side)
{
if (fbo->cur_render_target == tex)
return true;
fbo->cur_render_target = tex;
if (tex->type == GS_TEXTURE_2D) {
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
tex->texture, 0);
} else if (tex->type == GS_TEXTURE_CUBE) {
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_CUBE_MAP_POSITIVE_X + side,
tex->texture, 0);
} else {
return false;
}
return gl_success("glFramebufferTexture2D");
}
static bool attach_zstencil(struct fbo_info *fbo, zstencil_t zs)
{
GLuint zsbuffer = 0;
GLenum zs_attachment = GL_DEPTH_STENCIL_ATTACHMENT;
if (fbo->cur_zstencil_buffer == zs)
return true;
fbo->cur_zstencil_buffer = zs;
if (zs) {
zsbuffer = zs->buffer;
zs_attachment = zs->attachment;
}
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
zs_attachment, GL_RENDERBUFFER, zsbuffer);
if (!gl_success("glFramebufferRenderbuffer"))
return false;
return true;
}
static bool set_target(device_t device, texture_t tex, int side, zstencil_t zs)
{
struct fbo_info *fbo;
if (device->cur_render_target == tex &&
device->cur_zstencil_buffer == zs &&
device->cur_render_side == side)
return true;
device->cur_render_target = tex;
device->cur_render_side = side;
device->cur_zstencil_buffer = zs;
if (!tex)
return set_current_fbo(device, NULL);
fbo = get_fbo(device, tex);
if (!fbo)
return false;
set_current_fbo(device, fbo);
if (!attach_rendertarget(fbo, tex, side))
return false;
if (!attach_zstencil(fbo, zs))
return false;
return true;
}
void device_setrendertarget(device_t device, texture_t tex, zstencil_t zstencil)
{
if (tex->type != GS_TEXTURE_2D) {
blog(LOG_ERROR, "Texture is not a 2D texture");
goto fail;
}
if (!tex->is_render_target) {
blog(LOG_ERROR, "Texture is not a render target");
goto fail;
}
if (!set_target(device, tex, 0, zstencil))
goto fail;
return;
fail:
blog(LOG_ERROR, "device_setrendertarget (GL) failed");
}
void device_setcuberendertarget(device_t device, texture_t cubetex,
int side, zstencil_t zstencil)
{
if (cubetex->type != GS_TEXTURE_CUBE) {
blog(LOG_ERROR, "Texture is not a cube texture");
goto fail;
}
if (!cubetex->is_render_target) {
blog(LOG_ERROR, "Texture is not a render target");
goto fail;
}
if (!set_target(device, cubetex, side, zstencil))
goto fail;
return;
fail:
blog(LOG_ERROR, "device_setcuberendertarget (GL) failed");
}
void device_copy_texture(device_t device, texture_t dst, texture_t src)
{
struct gs_texture_2d *src2d = (struct gs_texture_2d*)src;
struct gs_texture_2d *dst2d = (struct gs_texture_2d*)dst;
if (dst->format != src->format) {
blog(LOG_ERROR, "Source and destination texture formats do "
"not match");
goto fail;
}
if (dst->type != GS_TEXTURE_2D || src->type != GS_TEXTURE_2D) {
blog(LOG_ERROR, "Source and destination textures must be 2D "
"textures");
goto fail;
}
if (dst2d->width != src2d->width || dst2d->height != src2d->height) {
blog(LOG_ERROR, "Source and destination textures must have "
"the same dimensions");
goto fail;
}
if (!gl_copy_texture(device, dst->texture, dst->gl_target,
src->texture, src->gl_target,
src2d->width, src2d->height))
goto fail;
return;
fail:
blog(LOG_ERROR, "device_copy_texture (GL) failed");
}
void device_beginscene(device_t device)
......
......@@ -326,6 +326,7 @@ struct gs_stage_surface {
struct gs_zstencil_buffer {
device_t device;
GLuint buffer;
GLuint attachment;
GLenum format;
};
......@@ -335,6 +336,23 @@ struct gs_swap_chain {
struct gs_init_data info;
};
struct fbo_info {
GLuint fbo;
uint32_t width;
uint32_t height;
enum gs_color_format format;
texture_t cur_render_target;
int cur_render_side;
zstencil_t cur_zstencil_buffer;
};
static inline void fbo_info_destroy(struct fbo_info *fbo)
{
glDeleteFramebuffers(1, &fbo->fbo);
gl_success("glDeleteFramebuffers");
}
struct gs_device {
struct gl_platform *plat;
GLuint pipeline;
......@@ -351,7 +369,8 @@ struct gs_device {
shader_t cur_pixel_shader;
swapchain_t cur_swap;
bool texture_changed[GS_MAX_TEXTURES];
DARRAY(struct fbo_info*) fbos;
struct fbo_info *cur_fbo;
};
extern struct gl_platform *gl_platform_create(device_t device,
......
......@@ -35,6 +35,17 @@ static bool gl_init_zsbuffer(struct gs_zstencil_buffer *zs, uint32_t width,
return true;
}
static inline GLenum get_attachment(enum gs_zstencil_format format)
{
switch (format) {
case GS_Z16: return GL_DEPTH_ATTACHMENT;
case GS_Z24_S8: return GL_DEPTH_STENCIL_ATTACHMENT;
case GS_Z32F: return GL_DEPTH_ATTACHMENT;
case GS_Z32F_S8X24: return GL_DEPTH_STENCIL_ATTACHMENT;
default: return 0;
}
}
zstencil_t device_create_zstencil(device_t device, uint32_t width,
uint32_t height, enum gs_zstencil_format format)
{
......@@ -42,7 +53,8 @@ zstencil_t device_create_zstencil(device_t device, uint32_t width,
zs = bmalloc(sizeof(struct gs_zstencil_buffer));
memset(zs, 0, sizeof(struct gs_zstencil_buffer));
zs->format = convert_zstencil_format(format);
zs->format = convert_zstencil_format(format);
zs->attachment = get_attachment(format);
if (!gl_init_zsbuffer(zs, width, height)) {
blog(LOG_ERROR, "device_create_zstencil (GL) failed");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册