/**
 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
 * These values are computed from the buffer's width and height and
 * the scissor box, if it's enabled.
 * \param ctx  the GL context.
 */
void
_mesa_update_draw_buffer_bounds(struct gl_context *ctx)
{
   struct gl_framebuffer *buffer = ctx->DrawBuffer;

   if (!buffer)
      return;

   if (_mesa_is_user_fbo(buffer)) {
      /* user-created framebuffer size depends on the renderbuffers */
      update_framebuffer_size(ctx, buffer);
   }

   buffer->_Xmin = 0;
   buffer->_Ymin = 0;
   buffer->_Xmax = buffer->Width;
   buffer->_Ymax = buffer->Height;

   if (ctx->Scissor.Enabled) {
      if (ctx->Scissor.X > buffer->_Xmin) {
	 buffer->_Xmin = ctx->Scissor.X;
      }
      if (ctx->Scissor.Y > buffer->_Ymin) {
	 buffer->_Ymin = ctx->Scissor.Y;
      }
      if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
	 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
      }
      if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
	 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
      }
      /* finally, check for empty region */
      if (buffer->_Xmin > buffer->_Xmax) {
         buffer->_Xmin = buffer->_Xmax;
      }
      if (buffer->_Ymin > buffer->_Ymax) {
         buffer->_Ymin = buffer->_Ymax;
      }
   }

   ASSERT(buffer->_Xmin <= buffer->_Xmax);
   ASSERT(buffer->_Ymin <= buffer->_Ymax);
}
/**
 * Update framebuffer state (color, depth, stencil, etc. buffers)
 */
void
st_update_framebuffer_state( struct st_context *st )
{
   struct pipe_framebuffer_state framebuffer;
   struct gl_framebuffer *fb = st->ctx->DrawBuffer;
   struct st_renderbuffer *strb;
   GLuint i;

   st_flush_bitmap_cache(st);
   st_invalidate_readpix_cache(st);

   st->state.fb_orientation = st_fb_orientation(fb);

   /**
    * Quantize the derived default number of samples:
    *
    * A query to the driver of supported MSAA values the
    * hardware supports is done as to legalize the number
    * of application requested samples, NumSamples.
    * See commit eb9cf3c for more information.
    */
   fb->DefaultGeometry._NumSamples =
      framebuffer_quantize_num_samples(st, fb->DefaultGeometry.NumSamples);

   framebuffer.width  = _mesa_geometric_width(fb);
   framebuffer.height = _mesa_geometric_height(fb);
   framebuffer.samples = _mesa_geometric_samples(fb);
   framebuffer.layers = _mesa_geometric_layers(fb);

   /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state
    * to determine which surfaces to draw to
    */
   framebuffer.nr_cbufs = fb->_NumColorDrawBuffers;

   for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
      framebuffer.cbufs[i] = NULL;
      strb = st_renderbuffer(fb->_ColorDrawBuffers[i]);

      if (strb) {
         if (strb->is_rtt || (strb->texture &&
             _mesa_get_format_color_encoding(strb->Base.Format) == GL_SRGB)) {
            /* rendering to a GL texture, may have to update surface */
            st_update_renderbuffer_surface(st, strb);
         }

         if (strb->surface) {
            framebuffer.cbufs[i] = strb->surface;
            update_framebuffer_size(&framebuffer, strb->surface);
         }
         strb->defined = GL_TRUE; /* we'll be drawing something */
      }
   }

   for (i = framebuffer.nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) {
      framebuffer.cbufs[i] = NULL;
   }

   /* Remove trailing GL_NONE draw buffers. */
   while (framebuffer.nr_cbufs &&
          !framebuffer.cbufs[framebuffer.nr_cbufs-1]) {
      framebuffer.nr_cbufs--;
   }

   /*
    * Depth/Stencil renderbuffer/surface.
    */
   strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
   if (!strb)
      strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer);

   if (strb) {
      if (strb->is_rtt) {
         /* rendering to a GL texture, may have to update surface */
         st_update_renderbuffer_surface(st, strb);
      }
      framebuffer.zsbuf = strb->surface;
      update_framebuffer_size(&framebuffer, strb->surface);
   }
   else
      framebuffer.zsbuf = NULL;

#ifdef DEBUG
   /* Make sure the resource binding flags were set properly */
   for (i = 0; i < framebuffer.nr_cbufs; i++) {
      assert(!framebuffer.cbufs[i] ||
             framebuffer.cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET);
   }
   if (framebuffer.zsbuf) {
      assert(framebuffer.zsbuf->texture->bind & PIPE_BIND_DEPTH_STENCIL);
   }
#endif

   if (framebuffer.width == USHRT_MAX)
      framebuffer.width = 0;
   if (framebuffer.height == USHRT_MAX)
      framebuffer.height = 0;

   cso_set_framebuffer(st->cso_context, &framebuffer);

   st->state.fb_width = framebuffer.width;
   st->state.fb_height = framebuffer.height;
   st->state.fb_num_samples = util_framebuffer_get_num_samples(&framebuffer);
   st->state.fb_num_layers = util_framebuffer_get_num_layers(&framebuffer);
   st->state.fb_num_cb = framebuffer.nr_cbufs;
}