void agp_resize_rendertarget( struct agp_rendertarget* tgt, size_t neww, size_t newh) { if (!tgt || !tgt->store){ arcan_warning("attempted resize on broken rendertarget\n"); return; } /* same dimensions, no need to resize */ if (tgt->store->w == neww && tgt->store->h == newh) return; erase_store(tgt->store); erase_store(tgt->store_back); struct agp_fenv* env = agp_env(); agp_empty_vstore(tgt->store, neww, newh); if (tgt->store_back) agp_empty_vstore(tgt->store_back, neww, newh); /* we inplace- modify, want the refcounter intact */ env->delete_framebuffers(1,&tgt->fbo); env->delete_renderbuffers(1,&tgt->depth); tgt->fbo = GL_NONE; tgt->depth = GL_NONE; alloc_fbo(tgt, false); }
void agp_resize_rendertarget( struct agp_rendertarget* tgt, size_t neww, size_t newh) { if (!tgt || !tgt->store){ arcan_warning("attempted resize on broken rendertarget\n"); return; } /* same dimensions, no need to resize */ if (tgt->store->w == neww && tgt->store->h == newh) return; struct storage_info_t* os = tgt->store; /* we inplace- modify, want the refcounter intact */ agp_null_vstore(os); arcan_mem_free(os->vinf.text.raw); os->vinf.text.raw = NULL; os->vinf.text.s_raw = 0; agp_empty_vstore(os, neww, newh); glDeleteFramebuffers(1,&tgt->fbo); glDeleteRenderbuffers(1,&tgt->depth); tgt->fbo = GL_NONE; tgt->depth = GL_NONE; alloc_fbo(tgt, tgt->mode); }
struct agp_rendertarget* agp_setup_rendertarget(struct storage_info_t* vstore, enum rendertarget_mode m) { struct agp_rendertarget* r = arcan_alloc_mem(sizeof(struct agp_rendertarget), ARCAN_MEM_VSTRUCT, ARCAN_MEM_BZERO, ARCAN_MEMALIGN_NATURAL); r->store = vstore; r->mode = m; alloc_fbo(r, false); return r; }
struct agp_rendertarget* agp_setup_rendertarget( struct storage_info_t* vstore, enum rendertarget_mode m) { struct agp_rendertarget* r = arcan_alloc_mem(sizeof(struct agp_rendertarget), ARCAN_MEM_VSTRUCT, ARCAN_MEM_BZERO, ARCAN_MEMALIGN_NATURAL); r->store = vstore; r->mode = m; r->clearcol[3] = 1.0; /* need this tracking because there's no external memory management for _back */ r->front_active = true; if (m & RENDERTARGET_DOUBLEBUFFER){ r->store_back = arcan_alloc_mem(sizeof(struct storage_info_t), ARCAN_MEM_VSTRUCT, ARCAN_MEM_BZERO, ARCAN_MEMALIGN_NATURAL); r->store_back->vinf.text.s_fmt = vstore->vinf.text.s_fmt; r->store_back->vinf.text.d_fmt = vstore->vinf.text.d_fmt; agp_empty_vstore(r->store_back, vstore->w, vstore->h); } alloc_fbo(r, false); return r; }
static bool alloc_fbo(struct agp_rendertarget* dst, bool retry) { struct agp_fenv* env = agp_env(); env->gen_framebuffers(1, &dst->fbo); int mode = dst->mode & (~RENDERTARGET_DOUBLEBUFFER); /* need both stencil and depth buffer, but we don't need the data from them */ env->bind_framebuffer(GL_FRAMEBUFFER, dst->fbo); if (mode > RENDERTARGET_DEPTH) { env->framebuffer_texture_2d(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst->store->vinf.text.glid, 0); /* need a Z buffer in the offscreen rendering but don't want * bo store it, so setup a renderbuffer */ if (mode > RENDERTARGET_COLOR){ env->gen_renderbuffers(1, &dst->depth); /* could use GL_DEPTH_COMPONENT only if we'd know that there * wouldn't be any clipping in the active rendertarget */ if (!retry){ env->bind_renderbuffer(GL_RENDERBUFFER, dst->depth); env->renderbuffer_storage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, dst->store->w, dst->store->h); env->bind_renderbuffer(GL_RENDERBUFFER, 0); env->framebuffer_renderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, dst->depth); } } } else { /* DEPTH buffer only (shadowmapping, ...) convert the storage to * contain a depth texture */ size_t w = dst->store->w; size_t h = dst->store->h; agp_drop_vstore(dst->store); struct storage_info_t* store = dst->store; memset(store, '\0', sizeof(struct storage_info_t)); store->txmapped = TXSTATE_DEPTH; store->txu = ARCAN_VTEX_CLAMP; store->txv = ARCAN_VTEX_CLAMP; store->scale = ARCAN_VIMAGE_NOPOW2; store->imageproc = IMAGEPROC_NORMAL; store->filtermode = ARCAN_VFILTER_NONE; store->refcount = 1; store->w = w; store->h = h; /* generate ID etc. special path for TXSTATE_DEPTH */ agp_update_vstore(store, true); env->draw_buffer(GL_NONE); env->read_buffer(GL_NONE); env->framebuffer_texture_2d(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, store->vinf.text.glid, 0); } /* basic error handling / status checking * may be possible that we should cache this in the * rendertarget and only call when / if something changes as * it's not certain that drivers won't stall the pipeline on this */ GLenum status = env->check_framebuffer(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE){ arcan_warning("FBO support broken, couldn't create basic FBO:\n"); switch(status){ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: if (!retry){ arcan_warning("\t Incomplete Attachment, attempting " "simple framebuffer, this will likely break 3D and complex" "clipping operations.\n"); return alloc_fbo(dst, true); } else arcan_warning("\t Simple attachement broke as well " "likely driver issue.\n"); break; #ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: arcan_warning("\t Not all attached buffers have " "the same dimensions.\n"); break; #endif case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: arcan_warning("\t One or several FBO attachment points are missing.\n"); break; case GL_FRAMEBUFFER_UNSUPPORTED: arcan_warning("\t Request formats combination unsupported.\n"); break; } if (dst->fbo != GL_NONE) env->delete_framebuffers(1,&dst->fbo); if (dst->depth != GL_NONE) env->delete_renderbuffers(1,&dst->depth); dst->fbo = dst->depth = GL_NONE; return false; } env->bind_framebuffer(GL_FRAMEBUFFER, 0); return true; }