Example #1
0
/**
 * Apply depth (Z) buffer testing to the span.
 * \return approx number of pixels that passed (only zero is reliable)
 */
GLuint
_swrast_depth_test_span(struct gl_context *ctx, SWspan *span)
{
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
   const GLint bpp = _mesa_get_format_bytes(rb->Format);
   void *zStart;
   const GLuint count = span->end;
   const GLuint *fragZ = span->array->z;
   GLubyte *mask = span->array->mask;
   void *zBufferVals;
   GLuint *zBufferTemp = NULL;
   GLuint passed;
   GLuint zBits = _mesa_get_format_bits(rb->Format, GL_DEPTH_BITS);
   GLboolean ztest16 = GL_FALSE;

   if (span->arrayMask & SPAN_XY)
      zStart = NULL;
   else
      zStart = _swrast_pixel_address(rb, span->x, span->y);

   if (rb->Format == MESA_FORMAT_Z_UNORM16 && !(span->arrayMask & SPAN_XY)) {
      /* directly read/write row of 16-bit Z values */
      zBufferVals = zStart;
      ztest16 = GL_TRUE;
   }
   else if (rb->Format == MESA_FORMAT_Z_UNORM32 && !(span->arrayMask & SPAN_XY)) {
      /* directly read/write row of 32-bit Z values */
      zBufferVals = zStart;
   }
   else {
      if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED) {
         _mesa_problem(ctx, "Incorrectly writing swrast's integer depth "
                       "values to %s depth buffer",
                       _mesa_get_format_name(rb->Format));
      }

      /* copy Z buffer values into temp buffer (32-bit Z values) */
      zBufferTemp = malloc(count * sizeof(GLuint));
      if (!zBufferTemp)
         return 0;

      if (span->arrayMask & SPAN_XY) {
         get_z32_values(ctx, rb, count,
                        span->array->x, span->array->y, zBufferTemp);
      }
      else {
         _mesa_unpack_uint_z_row(rb->Format, count, zStart, zBufferTemp);
      }

      if (zBits == 24) {
         GLuint i;
         /* Convert depth buffer values from 32 to 24 bits to match the
          * fragment Z values generated by rasterization.
          */
         for (i = 0; i < count; i++) {
            zBufferTemp[i] >>= 8;
         }
      }
      else if (zBits == 16) {
Example #2
0
/**
 * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc).
 * Compressed textures are handled here as well.
 */
static void
get_tex_rgba(struct gl_context *ctx, GLuint dimensions,
             GLenum format, GLenum type, GLvoid *pixels,
             struct gl_texture_image *texImage)
{
   const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
   GLbitfield transferOps = 0x0;

   /* In general, clamping does not apply to glGetTexImage, except when
    * the returned type of the image can't hold negative values.
    */
   if (type_needs_clamping(type)) {
      /* the returned image type can't have negative values */
      if (dataType == GL_FLOAT ||
          dataType == GL_SIGNED_NORMALIZED ||
          format == GL_LUMINANCE ||
          format == GL_LUMINANCE_ALPHA) {
         transferOps |= IMAGE_CLAMP_BIT;
      }
   }
   /* This applies to RGB, RGBA textures. if the format is either LUMINANCE
    * or LUMINANCE ALPHA, luminance (L) is computed as L=R+G+B .we need to
    * clamp the sum to [0,1].
    */
   else if ((format == GL_LUMINANCE ||
            format == GL_LUMINANCE_ALPHA) &&
            dataType == GL_UNSIGNED_NORMALIZED) {
      transferOps |= IMAGE_CLAMP_BIT;
   }
   get_tex_rgba_uncompressed(ctx, dimensions, format, type,
                             pixels, texImage, transferOps);
}
Example #3
0
/**
 * Used to answer the GL_IMPLEMENTATION_COLOR_READ_TYPE_OES query.
 */
GLenum
_mesa_get_color_read_type(struct gl_context *ctx)
{
   if (!ctx->ReadBuffer || !ctx->ReadBuffer->_ColorReadBuffer) {
      /* The spec is unclear how to handle this case, but NVIDIA's
       * driver generates GL_INVALID_OPERATION.
       */
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE: "
                  "no GL_READ_BUFFER)");
      return GL_NONE;
   }
   else {
      const GLenum format = ctx->ReadBuffer->_ColorReadBuffer->Format;
      const GLenum data_type = _mesa_get_format_datatype(format);

      if (format == MESA_FORMAT_RGB565)
         return GL_UNSIGNED_SHORT_5_6_5_REV;

      switch (data_type) {
      case GL_SIGNED_NORMALIZED:
         return GL_BYTE;
      case GL_UNSIGNED_INT:
      case GL_INT:
      case GL_FLOAT:
         return data_type;
      case GL_UNSIGNED_NORMALIZED:
      default:
         return GL_UNSIGNED_BYTE;
      }
   }
}
/**
 * Used to answer the GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES queries (using
 * GetIntegerv, GetFramebufferParameteriv, etc)
 *
 * If @fb is NULL, the method returns the value for the current bound
 * framebuffer.
 */
GLenum
_mesa_get_color_read_format(struct gl_context *ctx,
                            struct gl_framebuffer *fb,
                            const char *caller)
{
   if (ctx->NewState)
      _mesa_update_state(ctx);

   if (fb == NULL)
      fb = ctx->ReadBuffer;

   if (!fb || !fb->_ColorReadBuffer) {
      /*
       * From OpenGL 4.5 spec, section 18.2.2 "ReadPixels":
       *
       *    "An INVALID_OPERATION error is generated by GetIntegerv if pname
       *     is IMPLEMENTATION_COLOR_READ_FORMAT or IMPLEMENTATION_COLOR_-
       *     READ_TYPE and any of:
       *      * the read framebuffer is not framebuffer complete.
       *      * the read framebuffer is a framebuffer object, and the selected
       *        read buffer (see section 18.2.1) has no image attached.
       *      * the selected read buffer is NONE."
       *
       * There is not equivalent quote for GetFramebufferParameteriv or
       * GetNamedFramebufferParameteriv, but from section 9.2.3 "Framebuffer
       * Object Queries":
       *
       *    "Values of framebuffer-dependent state are identical to those that
       *     would be obtained were the framebuffer object bound and queried
       *     using the simple state queries in that table."
       *
       * Where "using the simple state queries" refer to use GetIntegerv. So
       * we will assume that on that situation the same error should be
       * triggered too.
       */
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "%s(GL_IMPLEMENTATION_COLOR_READ_FORMAT: no GL_READ_BUFFER)",
                  caller);
      return GL_NONE;
   }
   else {
      const mesa_format format = fb->_ColorReadBuffer->Format;
      const GLenum data_type = _mesa_get_format_datatype(format);

      if (format == MESA_FORMAT_B8G8R8A8_UNORM)
         return GL_BGRA;
      else if (format == MESA_FORMAT_B5G6R5_UNORM)
         return GL_RGB;
      else if (format == MESA_FORMAT_R_UNORM8)
         return GL_RED;

      switch (data_type) {
      case GL_UNSIGNED_INT:
      case GL_INT:
         return GL_RGBA_INTEGER;
      default:
         return GL_RGBA;
      }
   }
}
/**
 * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc).
 * Compressed textures are handled here as well.
 */
static void
get_tex_rgba(struct gl_context *ctx, GLuint dimensions,
             GLenum format, GLenum type, GLvoid *pixels,
             struct gl_texture_image *texImage)
{
   const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
   GLbitfield transferOps = 0x0;

   /* In general, clamping does not apply to glGetTexImage, except when
    * the returned type of the image can't hold negative values.
    */
   if (type_needs_clamping(type)) {
      /* the returned image type can't have negative values */
      if (dataType == GL_FLOAT ||
          dataType == GL_SIGNED_NORMALIZED ||
          format == GL_LUMINANCE ||
          format == GL_LUMINANCE_ALPHA) {
         transferOps |= IMAGE_CLAMP_BIT;
      }
   }

   if (_mesa_is_format_compressed(texImage->TexFormat)) {
      get_tex_rgba_compressed(ctx, dimensions, format, type,
                              pixels, texImage, transferOps);
   }
   else {
      get_tex_rgba_uncompressed(ctx, dimensions, format, type,
                                pixels, texImage, transferOps);
   }
}
Example #6
0
GLboolean
_mesa_texstore_needs_transfer_ops(struct gl_context *ctx,
                                  GLenum baseInternalFormat,
                                  mesa_format dstFormat)
{
   GLenum dstType;

   /* There are different rules depending on the base format. */
   switch (baseInternalFormat) {
   case GL_DEPTH_COMPONENT:
   case GL_DEPTH_STENCIL:
      return ctx->Pixel.DepthScale != 1.0f ||
             ctx->Pixel.DepthBias != 0.0f;

   case GL_STENCIL_INDEX:
      return GL_FALSE;

   default:
      /* Color formats.
       * Pixel transfer ops (scale, bias, table lookup) do not apply
       * to integer formats.
       */
      dstType = _mesa_get_format_datatype(dstFormat);

      return dstType != GL_INT && dstType != GL_UNSIGNED_INT &&
             ctx->_ImageTransferState;
   }
}
Example #7
0
/**
 * For non-float-depth and stencil buffers being read as 24/8 depth/stencil,
 * copy the integer data directly instead of converting depth to float and
 * re-packing.
 */
static GLboolean
fast_read_depth_stencil_pixels_separate(struct gl_context *ctx,
					GLint x, GLint y,
					GLsizei width, GLsizei height,
					uint32_t *dst, int dstStride)
{
   struct gl_framebuffer *fb = ctx->ReadBuffer;
   struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
   struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
   GLubyte *depthMap, *stencilMap, *stencilVals;
   int depthStride, stencilStride, i, j;

   if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED)
      return GL_FALSE;

   ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
			       GL_MAP_READ_BIT, &depthMap, &depthStride);
   if (!depthMap) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
      return GL_TRUE;  /* don't bother trying the slow path */
   }

   ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
			       GL_MAP_READ_BIT, &stencilMap, &stencilStride);
   if (!stencilMap) {
      ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
      return GL_TRUE;  /* don't bother trying the slow path */
   }

   stencilVals = malloc(width * sizeof(GLubyte));

   if (stencilVals) {
      for (j = 0; j < height; j++) {
         _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst);
         _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
                                        stencilMap, stencilVals);

         for (i = 0; i < width; i++) {
            dst[i] = (dst[i] & 0xffffff00) | stencilVals[i];
         }

         depthMap += depthStride;
         stencilMap += stencilStride;
         dst += dstStride / 4;
      }
   }
   else {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
   }

   free(stencilVals);

   ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
   ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);

   return GL_TRUE;
}
Example #8
0
/**
 * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the
 * mapping.
 */
static GLboolean
fast_read_depth_pixels( struct gl_context *ctx,
			GLint x, GLint y,
			GLsizei width, GLsizei height,
			GLenum type, GLvoid *pixels,
			const struct gl_pixelstore_attrib *packing )
{
   struct gl_framebuffer *fb = ctx->ReadBuffer;
   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
   GLubyte *map, *dst;
   int stride, dstStride, j;

   if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0)
      return GL_FALSE;

   if (packing->SwapBytes)
      return GL_FALSE;

   if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED)
      return GL_FALSE;

   if (!((type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16) ||
	 type == GL_UNSIGNED_INT))
      return GL_FALSE;

   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
			       &map, &stride);

   if (!map) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
      return GL_TRUE;  /* don't bother trying the slow path */
   }

   dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
					   GL_DEPTH_COMPONENT, type, 0, 0);

   for (j = 0; j < height; j++) {
      if (type == GL_UNSIGNED_INT) {
	 _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst);
      } else {
	 ASSERT(type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16);
	 memcpy(dst, map, width * 2);
      }

      map += stride;
      dst += dstStride;
   }
   ctx->Driver.UnmapRenderbuffer(ctx, rb);

   return GL_TRUE;
}
Example #9
0
/**
 * Return true if memcpy cannot be used for ReadPixels.
 *
 * If uses_blit is true, the function returns true if a simple 3D engine blit
 * cannot be used for ReadPixels packing.
 *
 * NOTE: This doesn't take swizzling and format conversions between
 *       the readbuffer and the pixel pack buffer into account.
 */
GLboolean
_mesa_readpixels_needs_slow_path(const struct gl_context *ctx, GLenum format,
                                 GLenum type, GLboolean uses_blit)
{
   struct gl_renderbuffer *rb =
         _mesa_get_read_renderbuffer_for_format(ctx, format);
   GLenum srcType;

   ASSERT(rb);

   /* There are different rules depending on the base format. */
   switch (format) {
   case GL_DEPTH_STENCIL:
      return !_mesa_has_depthstencil_combined(ctx->ReadBuffer) ||
             ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f ||
             ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset ||
             ctx->Pixel.MapStencilFlag;

   case GL_DEPTH_COMPONENT:
      return ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f;

   case GL_STENCIL_INDEX:
      return ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset ||
             ctx->Pixel.MapStencilFlag;

   default:
      /* Color formats. */
      if (need_rgb_to_luminance_conversion(rb->Format, format)) {
         return GL_TRUE;
      }

      /* Conversion between signed and unsigned integers needs masking
       * (it isn't just memcpy). */
      srcType = _mesa_get_format_datatype(rb->Format);

      if ((srcType == GL_INT &&
           (type == GL_UNSIGNED_INT ||
            type == GL_UNSIGNED_SHORT ||
            type == GL_UNSIGNED_BYTE)) ||
          (srcType == GL_UNSIGNED_INT &&
           (type == GL_INT ||
            type == GL_SHORT ||
            type == GL_BYTE))) {
         return GL_TRUE;
      }

      /* And finally, see if there are any transfer ops. */
      return get_readpixels_transfer_ops(ctx, rb->Format, format, type,
                                         uses_blit) != 0;
   }
   return GL_FALSE;
}
Example #10
0
/**
 * Return transfer op flags for this ReadPixels operation.
 */
GLbitfield
_mesa_get_readpixels_transfer_ops(const struct gl_context *ctx,
                                  mesa_format texFormat,
                                  GLenum format, GLenum type,
                                  GLboolean uses_blit)
{
   GLbitfield transferOps = ctx->_ImageTransferState;
   GLenum srcBaseFormat = _mesa_get_format_base_format(texFormat);
   GLenum dstBaseFormat = _mesa_unpack_format_to_base_format(format);

   if (format == GL_DEPTH_COMPONENT ||
       format == GL_DEPTH_STENCIL ||
       format == GL_STENCIL_INDEX) {
      return 0;
   }

   /* Pixel transfer ops (scale, bias, table lookup) do not apply
    * to integer formats.
    */
   if (_mesa_is_enum_format_integer(format)) {
      return 0;
   }

   if (uses_blit) {
      /* For blit-based ReadPixels packing, the clamping is done automatically
       * unless the type is float. */
      if (_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) &&
          (type == GL_FLOAT || type == GL_HALF_FLOAT)) {
         transferOps |= IMAGE_CLAMP_BIT;
      }
   }
   else {
      /* For CPU-based ReadPixels packing, the clamping must always be done
       * for non-float types, */
      if (_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) ||
          (type != GL_FLOAT && type != GL_HALF_FLOAT)) {
         transferOps |= IMAGE_CLAMP_BIT;
      }
   }

   /* If the format is unsigned normalized, we can ignore clamping
    * because the values are already in the range [0,1] so it won't
    * have any effect anyway.
    */
   if (_mesa_get_format_datatype(texFormat) == GL_UNSIGNED_NORMALIZED &&
       !_mesa_need_rgb_to_luminance_conversion(srcBaseFormat, dstBaseFormat)) {
      transferOps &= ~IMAGE_CLAMP_BIT;
   }

   return transferOps;
}
Example #11
0
File: blit.c Project: airlied/mesa
/**
 * Helper function for checking if the datatypes of color buffers are
 * compatible for glBlitFramebuffer.  From the 3.1 spec, page 198:
 *
 * "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT
 *  and any of the following conditions hold:
 *   - The read buffer contains fixed-point or floating-point values and any
 *     draw buffer contains neither fixed-point nor floating-point values.
 *   - The read buffer contains unsigned integer values and any draw buffer
 *     does not contain unsigned integer values.
 *   - The read buffer contains signed integer values and any draw buffer
 *     does not contain signed integer values."
 */
static GLboolean
compatible_color_datatypes(mesa_format srcFormat, mesa_format dstFormat)
{
   GLenum srcType = _mesa_get_format_datatype(srcFormat);
   GLenum dstType = _mesa_get_format_datatype(dstFormat);

   if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) {
      assert(srcType == GL_UNSIGNED_NORMALIZED ||
             srcType == GL_SIGNED_NORMALIZED ||
             srcType == GL_FLOAT);
      /* Boil any of those types down to GL_FLOAT */
      srcType = GL_FLOAT;
   }

   if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) {
      assert(dstType == GL_UNSIGNED_NORMALIZED ||
             dstType == GL_SIGNED_NORMALIZED ||
             dstType == GL_FLOAT);
      /* Boil any of those types down to GL_FLOAT */
      dstType = GL_FLOAT;
   }

   return srcType == dstType;
}
Example #12
0
/**
 * Determine what type to use (ubyte vs. float) for span colors for the
 * given renderbuffer.
 * See also _swrast_write_rgba_span().
 */
static void
find_renderbuffer_colortype(struct gl_renderbuffer *rb)
{
   struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
   GLuint rbMaxBits = _mesa_get_format_max_bits(rb->Format);
   GLenum rbDatatype = _mesa_get_format_datatype(rb->Format);

   if (rbDatatype == GL_UNSIGNED_NORMALIZED && rbMaxBits <= 8) {
      /* the buffer's values fit in GLubyte values */
      srb->ColorType = GL_UNSIGNED_BYTE;
   }
   else {
      /* use floats otherwise */
      srb->ColorType = GL_FLOAT;
   }
}
Example #13
0
static GLenum
read_pixels_es3_error_check(GLenum format, GLenum type,
                            const struct gl_renderbuffer *rb)
{
   const GLenum internalFormat = rb->InternalFormat;
   const GLenum data_type = _mesa_get_format_datatype(rb->Format);
   GLboolean is_unsigned_int = GL_FALSE;
   GLboolean is_signed_int = GL_FALSE;

   if (!_mesa_is_color_format(internalFormat)) {
      return GL_INVALID_OPERATION;
   }

   is_unsigned_int = _mesa_is_enum_format_unsigned_int(internalFormat);
   if (!is_unsigned_int) {
      is_signed_int = _mesa_is_enum_format_signed_int(internalFormat);
   }

   switch (format) {
   case GL_RGBA:
      if (type == GL_FLOAT && data_type == GL_FLOAT)
         return GL_NO_ERROR; /* EXT_color_buffer_float */
      if (type == GL_UNSIGNED_BYTE && data_type == GL_UNSIGNED_NORMALIZED)
         return GL_NO_ERROR;
      if (internalFormat == GL_RGB10_A2 &&
          type == GL_UNSIGNED_INT_2_10_10_10_REV)
         return GL_NO_ERROR;
      if (internalFormat == GL_RGB10_A2UI && type == GL_UNSIGNED_BYTE)
         return GL_NO_ERROR;
      break;
   case GL_BGRA:
      /* GL_EXT_read_format_bgra */
      if (type == GL_UNSIGNED_BYTE ||
          type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
          type == GL_UNSIGNED_SHORT_1_5_5_5_REV)
         return GL_NO_ERROR;
      break;
   case GL_RGBA_INTEGER:
      if ((is_signed_int && type == GL_INT) ||
          (is_unsigned_int && type == GL_UNSIGNED_INT))
         return GL_NO_ERROR;
      break;
   }

   return GL_INVALID_OPERATION;
}
Example #14
0
static bool
need_signed_unsigned_int_conversion(mesa_format mesaFormat,
                                    GLenum format, GLenum type)
{
   const GLenum mesaFormatType = _mesa_get_format_datatype(mesaFormat);
   const bool is_format_integer = _mesa_is_enum_format_integer(format);
   return (mesaFormatType == GL_INT &&
           is_format_integer &&
           (type == GL_UNSIGNED_INT ||
            type == GL_UNSIGNED_SHORT ||
            type == GL_UNSIGNED_BYTE)) ||
          (mesaFormatType == GL_UNSIGNED_INT &&
           is_format_integer &&
           (type == GL_INT ||
            type == GL_SHORT ||
            type == GL_BYTE));
}
/**
 * Used to answer the GL_IMPLEMENTATION_COLOR_READ_TYPE_OES queries (using
 * GetIntegerv, GetFramebufferParameteriv, etc)
 *
 * If @fb is NULL, the method returns the value for the current bound
 * framebuffer.
 */
GLenum
_mesa_get_color_read_type(struct gl_context *ctx,
                          struct gl_framebuffer *fb,
                          const char *caller)
{
   if (ctx->NewState)
      _mesa_update_state(ctx);

   if (fb == NULL)
      fb = ctx->ReadBuffer;

   if (!fb || !fb->_ColorReadBuffer) {
      /*
       * See comment on _mesa_get_color_read_format
       */
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "%s(GL_IMPLEMENTATION_COLOR_READ_TYPE: no GL_READ_BUFFER)",
                  caller);
      return GL_NONE;
   }
   else {
      const GLenum format = fb->_ColorReadBuffer->Format;
      const GLenum data_type = _mesa_get_format_datatype(format);

      if (format == MESA_FORMAT_B5G6R5_UNORM)
         return GL_UNSIGNED_SHORT_5_6_5;

      switch (data_type) {
      case GL_SIGNED_NORMALIZED:
         return GL_BYTE;
      case GL_UNSIGNED_INT:
      case GL_INT:
      case GL_FLOAT:
         return data_type;
      case GL_UNSIGNED_NORMALIZED:
      default:
         return GL_UNSIGNED_BYTE;
      }
   }
}
Example #16
0
static boolean
needs_integer_signed_unsigned_conversion(const struct gl_context *ctx,
                                         GLenum format, GLenum type)
{
   struct gl_renderbuffer *rb =
      _mesa_get_read_renderbuffer_for_format(ctx, format);

   assert(rb);

   GLenum srcType = _mesa_get_format_datatype(rb->Format);

    if ((srcType == GL_INT &&
        (type == GL_UNSIGNED_INT ||
         type == GL_UNSIGNED_SHORT ||
         type == GL_UNSIGNED_BYTE)) ||
       (srcType == GL_UNSIGNED_INT &&
        (type == GL_INT ||
         type == GL_SHORT ||
         type == GL_BYTE))) {
      return TRUE;
   }

   return FALSE;
}
Example #17
0
File: blit.c Project: airlied/mesa
void
_mesa_blit_framebuffer(struct gl_context *ctx,
                       struct gl_framebuffer *readFb,
                       struct gl_framebuffer *drawFb,
                       GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
                       GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
                       GLbitfield mask, GLenum filter, const char *func)
{
   const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
                                     GL_DEPTH_BUFFER_BIT |
                                     GL_STENCIL_BUFFER_BIT);

   FLUSH_VERTICES(ctx, 0);

   /* Update completeness status of readFb and drawFb. */
   _mesa_update_framebuffer(ctx, readFb, drawFb);

   /* Make sure drawFb has an initialized bounding box. */
   _mesa_update_draw_buffer_bounds(ctx, drawFb);

   if (!readFb || !drawFb) {
      /* This will normally never happen but someday we may want to
       * support MakeCurrent() with no drawables.
       */
      return;
   }

   /* check for complete framebuffers */
   if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
       readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
                  "%s(incomplete draw/read buffers)", func);
      return;
   }

   if (!is_valid_blit_filter(ctx, filter)) {
      _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid filter %s)", func,
                  _mesa_enum_to_string(filter));
      return;
   }

   if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT ||
        filter == GL_SCALED_RESOLVE_NICEST_EXT) &&
        (readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s: invalid samples)", func,
                  _mesa_enum_to_string(filter));
      return;
   }

   if (mask & ~legalMaskBits) {
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid mask bits set)", func);
      return;
   }

   /* depth/stencil must be blitted with nearest filtering */
   if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
        && filter != GL_NEAREST) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
             "%s(depth/stencil requires GL_NEAREST filter)", func);
      return;
   }

   /* get color read/draw renderbuffers */
   if (mask & GL_COLOR_BUFFER_BIT) {
      const GLuint numColorDrawBuffers = drawFb->_NumColorDrawBuffers;
      const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
      const struct gl_renderbuffer *colorDrawRb = NULL;
      GLuint i;

      /* From the EXT_framebuffer_object spec:
       *
       *     "If a buffer is specified in <mask> and does not exist in both
       *     the read and draw framebuffers, the corresponding bit is silently
       *     ignored."
       */
      if (!colorReadRb || numColorDrawBuffers == 0) {
         mask &= ~GL_COLOR_BUFFER_BIT;
      }
      else {
         for (i = 0; i < numColorDrawBuffers; i++) {
            colorDrawRb = drawFb->_ColorDrawBuffers[i];
            if (!colorDrawRb)
               continue;

            /* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL
             * ES 3.0.1 spec says:
             *
             *     "If the source and destination buffers are identical, an
             *     INVALID_OPERATION error is generated. Different mipmap
             *     levels of a texture, different layers of a three-
             *     dimensional texture or two-dimensional array texture, and
             *     different faces of a cube map texture do not constitute
             *     identical buffers."
             */
            if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) {
               _mesa_error(ctx, GL_INVALID_OPERATION,
                           "%s(source and destination color "
                           "buffer cannot be the same)", func);
               return;
            }

            if (!compatible_color_datatypes(colorReadRb->Format,
                                            colorDrawRb->Format)) {
               _mesa_error(ctx, GL_INVALID_OPERATION,
                           "%s(color buffer datatypes mismatch)", func);
               return;
            }
            /* extra checks for multisample copies... */
            if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
               /* color formats must match on GLES. This isn't checked on
                * desktop GL because the GL 4.4 spec was changed to allow it.
                * In the section entitled “Changes in the released
                * Specification of July 22, 2013” it says:
                *
                * “Relax BlitFramebuffer in section 18.3.1 so that format
                *  conversion can take place during multisample blits, since
                *  drivers already allow this and some apps depend on it.”
                */
               if (_mesa_is_gles(ctx) &&
                   !compatible_resolve_formats(colorReadRb, colorDrawRb)) {
                  _mesa_error(ctx, GL_INVALID_OPERATION,
                         "%s(bad src/dst multisample pixel formats)", func);
                  return;
               }
            }
         }
         if (filter != GL_NEAREST) {
            /* From EXT_framebuffer_multisample_blit_scaled specification:
             * "Calling BlitFramebuffer will result in an INVALID_OPERATION error
             * if filter is not NEAREST and read buffer contains integer data."
             */
            GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
            if (type == GL_INT || type == GL_UNSIGNED_INT) {
               _mesa_error(ctx, GL_INVALID_OPERATION,
                           "%s(integer color type)", func);
               return;
            }
         }
      }
   }

   if (mask & GL_STENCIL_BUFFER_BIT) {
      struct gl_renderbuffer *readRb =
         readFb->Attachment[BUFFER_STENCIL].Renderbuffer;
      struct gl_renderbuffer *drawRb =
         drawFb->Attachment[BUFFER_STENCIL].Renderbuffer;

      /* From the EXT_framebuffer_object spec:
       *
       *     "If a buffer is specified in <mask> and does not exist in both
       *     the read and draw framebuffers, the corresponding bit is silently
       *     ignored."
       */
      if ((readRb == NULL) || (drawRb == NULL)) {
         mask &= ~GL_STENCIL_BUFFER_BIT;
      }
      else {
         int read_z_bits, draw_z_bits;

         if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
            _mesa_error(ctx, GL_INVALID_OPERATION,
                        "%s(source and destination stencil "
                        "buffer cannot be the same)", func);
            return;
         }

         if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
             _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
            /* There is no need to check the stencil datatype here, because
             * there is only one: GL_UNSIGNED_INT.
             */
            _mesa_error(ctx, GL_INVALID_OPERATION,
                        "%s(stencil attachment format mismatch)", func);
            return;
         }

         read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS);
         draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS);

         /* If both buffers also have depth data, the depth formats must match
          * as well.  If one doesn't have depth, it's not blitted, so we should
          * ignore the depth format check.
          */
         if (read_z_bits > 0 && draw_z_bits > 0 &&
             (read_z_bits != draw_z_bits ||
              _mesa_get_format_datatype(readRb->Format) !=
              _mesa_get_format_datatype(drawRb->Format))) {

            _mesa_error(ctx, GL_INVALID_OPERATION,
                        "%s(stencil attachment depth format mismatch)", func);
            return;
         }
      }
   }

   if (mask & GL_DEPTH_BUFFER_BIT) {
      struct gl_renderbuffer *readRb =
         readFb->Attachment[BUFFER_DEPTH].Renderbuffer;
      struct gl_renderbuffer *drawRb =
         drawFb->Attachment[BUFFER_DEPTH].Renderbuffer;

      /* From the EXT_framebuffer_object spec:
       *
       *     "If a buffer is specified in <mask> and does not exist in both
       *     the read and draw framebuffers, the corresponding bit is silently
       *     ignored."
       */
      if ((readRb == NULL) || (drawRb == NULL)) {
         mask &= ~GL_DEPTH_BUFFER_BIT;
      }
      else {
         int read_s_bit, draw_s_bit;

         if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
            _mesa_error(ctx, GL_INVALID_OPERATION,
                        "%s(source and destination depth "
                        "buffer cannot be the same)", func);
            return;
         }

         if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
              _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) ||
             (_mesa_get_format_datatype(readRb->Format) !=
              _mesa_get_format_datatype(drawRb->Format))) {
            _mesa_error(ctx, GL_INVALID_OPERATION,
                        "%s(depth attachment format mismatch)", func);
            return;
         }

         read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS);
         draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS);

         /* If both buffers also have stencil data, the stencil formats must
          * match as well.  If one doesn't have stencil, it's not blitted, so
          * we should ignore the stencil format check.
          */
         if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) {
            _mesa_error(ctx, GL_INVALID_OPERATION,
                        "%s(depth attachment stencil bits mismatch)", func);
            return;
         }
      }
   }


   if (_mesa_is_gles3(ctx)) {
      /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
       * 3.0.1 spec says:
       *
       *     "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero,
       *     an INVALID_OPERATION error is generated."
       */
      if (drawFb->Visual.samples > 0) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "%s(destination samples must be 0)", func);
         return;
      }

      /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
       * 3.0.1 spec says:
       *
       *     "If SAMPLE_BUFFERS for the read framebuffer is greater than zero,
       *     no copy is performed and an INVALID_OPERATION error is generated
       *     if the formats of the read and draw framebuffers are not
       *     identical or if the source and destination rectangles are not
       *     defined with the same (X0, Y0) and (X1, Y1) bounds."
       *
       * The format check was made above because desktop OpenGL has the same
       * requirement.
       */
      if (readFb->Visual.samples > 0
          && (srcX0 != dstX0 || srcY0 != dstY0
              || srcX1 != dstX1 || srcY1 != dstY1)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "%s(bad src/dst multisample region)", func);
         return;
      }
   } else {
      if (readFb->Visual.samples > 0 &&
          drawFb->Visual.samples > 0 &&
          readFb->Visual.samples != drawFb->Visual.samples) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "%s(mismatched samples)", func);
         return;
      }

      /* extra checks for multisample copies... */
      if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) &&
          (filter == GL_NEAREST || filter == GL_LINEAR)) {
         /* src and dest region sizes must be the same */
         if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) ||
             abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) {
            _mesa_error(ctx, GL_INVALID_OPERATION,
                        "%s(bad src/dst multisample region sizes)", func);
            return;
         }
      }
   }

   /* Debug code */
   if (DEBUG_BLIT) {
      const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
      const struct gl_renderbuffer *colorDrawRb = NULL;
      GLuint i = 0;

      printf("%s(%d, %d, %d, %d,  %d, %d, %d, %d,"
             " 0x%x, 0x%x)\n", func,
             srcX0, srcY0, srcX1, srcY1,
             dstX0, dstY0, dstX1, dstY1,
             mask, filter);

      if (colorReadRb) {
         const struct gl_renderbuffer_attachment *att;

         att = find_attachment(readFb, colorReadRb);
         printf("  Src FBO %u  RB %u (%dx%d)  ",
                readFb->Name, colorReadRb->Name,
                colorReadRb->Width, colorReadRb->Height);
         if (att && att->Texture) {
            printf("Tex %u  tgt 0x%x  level %u  face %u",
                   att->Texture->Name,
                   att->Texture->Target,
                   att->TextureLevel,
                   att->CubeMapFace);
         }
         printf("\n");

         /* Print all active color render buffers */
         for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
            colorDrawRb = drawFb->_ColorDrawBuffers[i];
            if (!colorDrawRb)
               continue;

            att = find_attachment(drawFb, colorDrawRb);
            printf("  Dst FBO %u  RB %u (%dx%d)  ",
                   drawFb->Name, colorDrawRb->Name,
                   colorDrawRb->Width, colorDrawRb->Height);
            if (att && att->Texture) {
               printf("Tex %u  tgt 0x%x  level %u  face %u",
                      att->Texture->Name,
                      att->Texture->Target,
                      att->TextureLevel,
                      att->CubeMapFace);
            }
            printf("\n");
         }
      }
   }

   if (!mask ||
       (srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 ||
       (dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) {
      return;
   }

   assert(ctx->Driver.BlitFramebuffer);
   ctx->Driver.BlitFramebuffer(ctx, readFb, drawFb,
                               srcX0, srcY0, srcX1, srcY1,
                               dstX0, dstY0, dstX1, dstY1,
                               mask, filter);
}
Example #18
0
/**
 * Bilinear filtered blit (color only, non-integer values).
 */
static void
blit_linear(struct gl_context *ctx,
            GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
            GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
{
   struct gl_renderbuffer *readRb = ctx->ReadBuffer->_ColorReadBuffer;
   struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];

   const GLint srcWidth = ABS(srcX1 - srcX0);
   const GLint dstWidth = ABS(dstX1 - dstX0);
   const GLint srcHeight = ABS(srcY1 - srcY0);
   const GLint dstHeight = ABS(dstY1 - dstY0);
   const GLfloat dstHeightF = (GLfloat) dstHeight;

   const GLint srcXpos = MIN2(srcX0, srcX1);
   const GLint srcYpos = MIN2(srcY0, srcY1);
   const GLint dstXpos = MIN2(dstX0, dstX1);
   const GLint dstYpos = MIN2(dstY0, dstY1);

   const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
   const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);

   GLint dstRow;

   GLint pixelSize;
   GLvoid *srcBuffer0, *srcBuffer1;
   GLint srcBufferY0 = -1, srcBufferY1 = -1;
   GLvoid *dstBuffer;

   gl_format readFormat = _mesa_get_srgb_format_linear(readRb->Format);
   gl_format drawFormat = _mesa_get_srgb_format_linear(drawRb->Format);
   GLuint bpp = _mesa_get_format_bytes(readFormat);

   GLenum pixelType;

   GLubyte *srcMap, *dstMap;
   GLint srcRowStride, dstRowStride;


   /* Determine datatype for resampling */
   if (_mesa_get_format_max_bits(readFormat) == 8 &&
       _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) {
      pixelType = GL_UNSIGNED_BYTE;
      pixelSize = 4 * sizeof(GLubyte);
   }
   else {
      pixelType = GL_FLOAT;
      pixelSize = 4 * sizeof(GLfloat);
   }

   /* Allocate the src/dst row buffers.
    * Keep two adjacent src rows around for bilinear sampling.
    */
   srcBuffer0 = malloc(pixelSize * srcWidth);
   if (!srcBuffer0) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
      return;
   }
   srcBuffer1 = malloc(pixelSize * srcWidth);
   if (!srcBuffer1) {
      free(srcBuffer0);
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
      return;
   }
   dstBuffer = malloc(pixelSize * dstWidth);
   if (!dstBuffer) {
      free(srcBuffer0);
      free(srcBuffer1);
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
      return;
   }

   /*
    * Map src / dst renderbuffers
    */
   if (readRb == drawRb) {
      /* map whole buffer for read/write */
      ctx->Driver.MapRenderbuffer(ctx, readRb,
                                  0, 0, readRb->Width, readRb->Height,
                                  GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
                                  &srcMap, &srcRowStride);
      if (!srcMap) {
         free(srcBuffer0);
         free(srcBuffer1);
         free(dstBuffer);
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
         return;
      }

      dstMap = srcMap;
      dstRowStride = srcRowStride;
   }
   else {
      /* different src/dst buffers */
      /* XXX with a bit of work we could just map the regions to be
       * read/written instead of the whole buffers.
       */
      ctx->Driver.MapRenderbuffer(ctx, readRb,
				  0, 0, readRb->Width, readRb->Height,
                                  GL_MAP_READ_BIT, &srcMap, &srcRowStride);
      if (!srcMap) {
         free(srcBuffer0);
         free(srcBuffer1);
         free(dstBuffer);
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
         return;
      }
      ctx->Driver.MapRenderbuffer(ctx, drawRb,
                                  0, 0, drawRb->Width, drawRb->Height,
                                  GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
      if (!dstMap) {
         ctx->Driver.UnmapRenderbuffer(ctx, readRb);
         free(srcBuffer0);
         free(srcBuffer1);
         free(dstBuffer);
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
         return;
      }
   }

   for (dstRow = 0; dstRow < dstHeight; dstRow++) {
      const GLint dstY = dstYpos + dstRow;
      const GLfloat srcRow = (dstRow * srcHeight) / dstHeightF;
      GLint srcRow0 = IFLOOR(srcRow);
      GLint srcRow1 = srcRow0 + 1;
      GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */

      ASSERT(srcRow >= 0);
      ASSERT(srcRow < srcHeight);

      if (srcRow1 == srcHeight) {
         /* last row fudge */
         srcRow1 = srcRow0;
         rowWeight = 0.0;
      }

      if (invertY) {
         srcRow0 = srcHeight - 1 - srcRow0;
         srcRow1 = srcHeight - 1 - srcRow1;
      }

      srcY0 = srcYpos + srcRow0;
      srcY1 = srcYpos + srcRow1;

      /* get the two source rows */
      if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
         /* use same source row buffers again */
      }
      else if (srcY0 == srcBufferY1) {
         /* move buffer1 into buffer0 by swapping pointers */
         GLvoid *tmp = srcBuffer0;
         srcBuffer0 = srcBuffer1;
         srcBuffer1 = tmp;
         /* get y1 row */
         {
            GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
            if (pixelType == GL_UNSIGNED_BYTE) {
               _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
                                           src, srcBuffer1);
            }
            else {
               _mesa_unpack_rgba_row(readFormat, srcWidth,
                                     src, srcBuffer1);
            }
         }            
         srcBufferY0 = srcY0;
         srcBufferY1 = srcY1;
      }
      else {
         /* get both new rows */
         {
            GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
            GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
            if (pixelType == GL_UNSIGNED_BYTE) {
               _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
                                           src0, srcBuffer0);
               _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
                                           src1, srcBuffer1);
            }
            else {
               _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
               _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
            }
         }
         srcBufferY0 = srcY0;
         srcBufferY1 = srcY1;
      }

      if (pixelType == GL_UNSIGNED_BYTE) {
         resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
                                dstBuffer, invertX, rowWeight);
      }
      else {
         resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
                                   dstBuffer, invertX, rowWeight);
      }

      /* store pixel row in destination */
      {
         GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
         if (pixelType == GL_UNSIGNED_BYTE) {
            _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
         }
         else {
            _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
         }
      }
   }

   free(srcBuffer0);
   free(srcBuffer1);
   free(dstBuffer);

   ctx->Driver.UnmapRenderbuffer(ctx, readRb);
   if (drawRb != readRb) {
      ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
   }
}
Example #19
0
/**
 * Software fallback for generate mipmap levels.
 */
static void
fallback_generate_mipmap(struct gl_context *ctx, GLenum target,
                         struct gl_texture_object *texObj)
{
   struct pipe_context *pipe = st_context(ctx)->pipe;
   struct pipe_resource *pt = st_get_texobj_resource(texObj);
   const uint baseLevel = texObj->BaseLevel;
   const uint lastLevel = pt->last_level;
   const uint face = _mesa_tex_target_to_face(target);
   uint dstLevel;
   GLenum datatype;
   GLuint comps;
   GLboolean compressed;

   if (ST_DEBUG & DEBUG_FALLBACK)
      debug_printf("%s: fallback processing\n", __FUNCTION__);

   assert(target != GL_TEXTURE_3D); /* not done yet */

   compressed =
      _mesa_is_format_compressed(texObj->Image[face][baseLevel]->TexFormat);

   if (compressed) {
      GLenum type =
         _mesa_get_format_datatype(texObj->Image[face][baseLevel]->TexFormat);

      datatype = type == GL_UNSIGNED_NORMALIZED ? GL_UNSIGNED_BYTE : GL_FLOAT;
      comps = 4;
   }
   else {
      _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat,
                                     &datatype, &comps);
      assert(comps > 0 && "bad texture format in fallback_generate_mipmap()");
   }

   for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
      const uint srcLevel = dstLevel - 1;
      const uint srcWidth = u_minify(pt->width0, srcLevel);
      const uint srcHeight = u_minify(pt->height0, srcLevel);
      const uint srcDepth = u_minify(pt->depth0, srcLevel);
      const uint dstWidth = u_minify(pt->width0, dstLevel);
      const uint dstHeight = u_minify(pt->height0, dstLevel);
      const uint dstDepth = u_minify(pt->depth0, dstLevel);
      struct pipe_transfer *srcTrans, *dstTrans;
      const ubyte *srcData;
      ubyte *dstData;
      int srcStride, dstStride;

      srcTrans = pipe_get_transfer(pipe, pt, srcLevel,
                                   face,
                                   PIPE_TRANSFER_READ, 0, 0,
                                   srcWidth, srcHeight);

      dstTrans = pipe_get_transfer(pipe, pt, dstLevel,
                                   face,
                                   PIPE_TRANSFER_WRITE, 0, 0,
                                   dstWidth, dstHeight);

      srcData = (ubyte *) pipe_transfer_map(pipe, srcTrans);
      dstData = (ubyte *) pipe_transfer_map(pipe, dstTrans);

      srcStride = srcTrans->stride / util_format_get_blocksize(srcTrans->resource->format);
      dstStride = dstTrans->stride / util_format_get_blocksize(dstTrans->resource->format);

     /* this cannot work correctly for 3d since it does
        not respect layerStride. */
      if (compressed) {
         const enum pipe_format format = pt->format;
         const uint bw = util_format_get_blockwidth(format);
         const uint bh = util_format_get_blockheight(format);
         const uint srcWidth2 = align(srcWidth, bw);
         const uint srcHeight2 = align(srcHeight, bh);
         const uint dstWidth2 = align(dstWidth, bw);
         const uint dstHeight2 = align(dstHeight, bh);
         uint8_t *srcTemp, *dstTemp;

         assert(comps == 4);

         srcTemp = malloc(srcWidth2 * srcHeight2 * comps * (datatype == GL_FLOAT ? 4 : 1));
         dstTemp = malloc(dstWidth2 * dstHeight2 * comps * (datatype == GL_FLOAT ? 4 : 1));

         /* decompress the src image: srcData -> srcTemp */
         decompress_image(format, datatype, srcData, srcTemp, srcWidth2, srcHeight2, srcTrans->stride);

         _mesa_generate_mipmap_level(target, datatype, comps,
                                     0 /*border*/,
                                     srcWidth2, srcHeight2, srcDepth,
                                     srcTemp,
                                     srcWidth2, /* stride in texels */
                                     dstWidth2, dstHeight2, dstDepth,
                                     dstTemp,
                                     dstWidth2); /* stride in texels */

         /* compress the new image: dstTemp -> dstData */
         compress_image(format, datatype, dstTemp, dstData, dstWidth2, dstHeight2, dstTrans->stride);

         free(srcTemp);
         free(dstTemp);
      }
      else {
         _mesa_generate_mipmap_level(target, datatype, comps,
                                     0 /*border*/,
                                     srcWidth, srcHeight, srcDepth,
                                     srcData,
                                     srcStride, /* stride in texels */
                                     dstWidth, dstHeight, dstDepth,
                                     dstData,
                                     dstStride); /* stride in texels */
      }

      pipe_transfer_unmap(pipe, srcTrans);
      pipe_transfer_unmap(pipe, dstTrans);

      pipe->transfer_destroy(pipe, srcTrans);
      pipe->transfer_destroy(pipe, dstTrans);
   }
}
Example #20
0
/**
 * Convert the given color to a bitfield suitable for ORing into DWORD 7 of
 * SURFACE_STATE (DWORD 12-15 on SKL+).
 */
union isl_color_value
brw_meta_convert_fast_clear_color(const struct brw_context *brw,
                                  const struct intel_mipmap_tree *mt,
                                  const union gl_color_union *color)
{
   union isl_color_value override_color = {
      .u32 = {
         color->ui[0],
         color->ui[1],
         color->ui[2],
         color->ui[3],
      },
   };

   /* The sampler doesn't look at the format of the surface when the fast
    * clear color is used so we need to implement luminance, intensity and
    * missing components manually.
    */
   switch (_mesa_get_format_base_format(mt->format)) {
   case GL_INTENSITY:
      override_color.u32[3] = override_color.u32[0];
      /* flow through */
   case GL_LUMINANCE:
   case GL_LUMINANCE_ALPHA:
      override_color.u32[1] = override_color.u32[0];
      override_color.u32[2] = override_color.u32[0];
      break;
   default:
      for (int i = 0; i < 3; i++) {
         if (!_mesa_format_has_color_component(mt->format, i))
            override_color.u32[i] = 0;
      }
      break;
   }

   switch (_mesa_get_format_datatype(mt->format)) {
   case GL_UNSIGNED_NORMALIZED:
      for (int i = 0; i < 4; i++)
         override_color.f32[i] = CLAMP(override_color.f32[i], 0.0f, 1.0f);
      break;

   case GL_SIGNED_NORMALIZED:
      for (int i = 0; i < 4; i++)
         override_color.f32[i] = CLAMP(override_color.f32[i], -1.0f, 1.0f);
      break;

   case GL_UNSIGNED_INT:
      for (int i = 0; i < 4; i++) {
         unsigned bits = _mesa_get_format_bits(mt->format, GL_RED_BITS + i);
         if (bits < 32) {
            uint32_t max = (1u << bits) - 1;
            override_color.u32[i] = MIN2(override_color.u32[i], max);
         }
      }
      break;

   case GL_INT:
      for (int i = 0; i < 4; i++) {
         unsigned bits = _mesa_get_format_bits(mt->format, GL_RED_BITS + i);
         if (bits < 32) {
            int32_t max = (1 << (bits - 1)) - 1;
            int32_t min = -(1 << (bits - 1));
            override_color.i32[i] = CLAMP(override_color.i32[i], min, max);
         }
      }
      break;

   case GL_FLOAT:
      if (!_mesa_is_format_signed(mt->format)) {
         for (int i = 0; i < 4; i++)
            override_color.f32[i] = MAX2(override_color.f32[i], 0.0f);
      }
      break;
   }

   if (!_mesa_format_has_color_component(mt->format, 3)) {
      if (_mesa_is_format_integer_color(mt->format))
         override_color.u32[3] = 1;
      else
         override_color.f32[3] = 1.0f;
   }

   /* Handle linear to SRGB conversion */
   if (brw->ctx.Color.sRGBEnabled &&
       _mesa_get_srgb_format_linear(mt->format) != mt->format) {
      for (int i = 0; i < 3; i++) {
         override_color.f32[i] =
            util_format_linear_to_srgb_float(override_color.f32[i]);
      }
   }

   return override_color;
}
/**
 * The glGet queries of the framebuffer red/green/blue size, stencil size,
 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual.  These can
 * change depending on the renderbuffer bindings.  This function updates
 * the given framebuffer's Visual from the current renderbuffer bindings.
 *
 * This may apply to user-created framebuffers or window system framebuffers.
 *
 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
 * The former one is used to convert floating point depth values into
 * integer Z values.
 */
void
_mesa_update_framebuffer_visual(struct gl_context *ctx,
				struct gl_framebuffer *fb)
{
   GLuint i;

   memset(&fb->Visual, 0, sizeof(fb->Visual));
   fb->Visual.rgbMode = GL_TRUE; /* assume this */

   /* find first RGB renderbuffer */
   for (i = 0; i < BUFFER_COUNT; i++) {
      if (fb->Attachment[i].Renderbuffer) {
         const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
         const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
         const mesa_format fmt = rb->Format;

         /* Grab samples and sampleBuffers from any attachment point (assuming
          * the framebuffer is complete, we'll get the same answer from all
          * attachments).
          */
         fb->Visual.samples = rb->NumSamples;
         fb->Visual.sampleBuffers = rb->NumSamples > 0 ? 1 : 0;

         if (_mesa_is_legal_color_format(ctx, baseFormat)) {
            fb->Visual.redBits = _mesa_get_format_bits(fmt, GL_RED_BITS);
            fb->Visual.greenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS);
            fb->Visual.blueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS);
            fb->Visual.alphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS);
            fb->Visual.rgbBits = fb->Visual.redBits
               + fb->Visual.greenBits + fb->Visual.blueBits;
            if (_mesa_get_format_color_encoding(fmt) == GL_SRGB)
                fb->Visual.sRGBCapable = ctx->Extensions.EXT_framebuffer_sRGB;
            break;
         }
      }
   }

   fb->Visual.floatMode = GL_FALSE;
   for (i = 0; i < BUFFER_COUNT; i++) {
      if (fb->Attachment[i].Renderbuffer) {
         const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
         const mesa_format fmt = rb->Format;

         if (_mesa_get_format_datatype(fmt) == GL_FLOAT) {
            fb->Visual.floatMode = GL_TRUE;
            break;
         }
      }
   }

   if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
      const struct gl_renderbuffer *rb =
         fb->Attachment[BUFFER_DEPTH].Renderbuffer;
      const mesa_format fmt = rb->Format;
      fb->Visual.haveDepthBuffer = GL_TRUE;
      fb->Visual.depthBits = _mesa_get_format_bits(fmt, GL_DEPTH_BITS);
   }

   if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
      const struct gl_renderbuffer *rb =
         fb->Attachment[BUFFER_STENCIL].Renderbuffer;
      const mesa_format fmt = rb->Format;
      fb->Visual.haveStencilBuffer = GL_TRUE;
      fb->Visual.stencilBits = _mesa_get_format_bits(fmt, GL_STENCIL_BITS);
   }

   if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
      const struct gl_renderbuffer *rb =
         fb->Attachment[BUFFER_ACCUM].Renderbuffer;
      const mesa_format fmt = rb->Format;
      fb->Visual.haveAccumBuffer = GL_TRUE;
      fb->Visual.accumRedBits = _mesa_get_format_bits(fmt, GL_RED_BITS);
      fb->Visual.accumGreenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS);
      fb->Visual.accumBlueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS);
      fb->Visual.accumAlphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS);
   }

   compute_depth_max(fb);
}
Example #22
0
void GLAPIENTRY
_mesa_GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname,
                          GLsizei bufSize, GLint *params)
{
   GLint buffer[16];
   GET_CURRENT_CONTEXT(ctx);

   ASSERT_OUTSIDE_BEGIN_END(ctx);

   /* ARB_internalformat_query is also mandatory for ARB_internalformat_query2 */
   if (!(_mesa_has_ARB_internalformat_query(ctx) ||
         _mesa_is_gles3(ctx))) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInternalformativ");
      return;
   }

   assert(ctx->Driver.QueryInternalFormat != NULL);

   if (!_legal_parameters(ctx, target, internalformat, pname, bufSize, params))
      return;

   /* initialize the contents of the temporary buffer */
   memcpy(buffer, params, MIN2(bufSize, 16) * sizeof(GLint));

   /* Use the 'unsupported' response defined by the spec for every pname
    * as the default answer.
    */
   _set_default_response(pname, buffer);

   if (!_is_target_supported(ctx, target) ||
       !_is_internalformat_supported(ctx, target, internalformat) ||
       !_is_resource_supported(ctx, target, internalformat, pname))
      goto end;

   switch (pname) {
   case GL_SAMPLES:
      /* fall-through */
   case GL_NUM_SAMPLE_COUNTS:
      /* The ARB_internalformat_query2 sets the response as 'unsupported' for
       * SAMPLES and NUM_SAMPLE_COUNTS:
       *
       *     "If <internalformat> is not color-renderable, depth-renderable, or
       *     stencil-renderable (as defined in section 4.4.4), or if <target>
       *     does not support multiple samples (ie other than
       *     TEXTURE_2D_MULTISAMPLE,  TEXTURE_2D_MULTISAMPLE_ARRAY,
       *     or RENDERBUFFER)."
       */
      if ((target != GL_RENDERBUFFER &&
           target != GL_TEXTURE_2D_MULTISAMPLE &&
           target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ||
          !_is_renderable(ctx, internalformat))
         goto end;

      /* The GL ES 3.0 specification, section 6.1.15 page 236 says:
       *
       *     "Since multisampling is not supported for signed and unsigned
       *     integer internal formats, the value of NUM_SAMPLE_COUNTS will be
       *     zero for such formats.
       *
       * Since OpenGL ES 3.1 adds support for multisampled integer formats, we
       * have to check the version for 30 exactly.
       */
      if (pname == GL_NUM_SAMPLE_COUNTS && ctx->API == API_OPENGLES2 &&
          ctx->Version == 30 && _mesa_is_enum_format_integer(internalformat)) {
         goto end;
      }

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_INTERNALFORMAT_SUPPORTED:
      /* Having a supported <internalformat> is implemented as a prerequisite
       * for all the <pnames>. Thus,  if we reach this point, the internalformat is
       * supported.
       */
      buffer[0] = GL_TRUE;
      break;

   case GL_INTERNALFORMAT_PREFERRED:
      /* The ARB_internalformat_query2 spec says:
       *
       *     "- INTERNALFORMAT_PREFERRED: The implementation-preferred internal
       *     format for representing resources of the specified <internalformat> is
       *     returned in <params>.
       *
       * Therefore, we let the driver answer. Note that if we reach this
       * point, it means that the internalformat is supported, so the driver
       * is called just to try to get a preferred format. If not supported,
       * GL_NONE was already returned and the driver is not called.
       */
      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_INTERNALFORMAT_RED_SIZE:
   case GL_INTERNALFORMAT_GREEN_SIZE:
   case GL_INTERNALFORMAT_BLUE_SIZE:
   case GL_INTERNALFORMAT_ALPHA_SIZE:
   case GL_INTERNALFORMAT_DEPTH_SIZE:
   case GL_INTERNALFORMAT_STENCIL_SIZE:
   case GL_INTERNALFORMAT_SHARED_SIZE:
   case GL_INTERNALFORMAT_RED_TYPE:
   case GL_INTERNALFORMAT_GREEN_TYPE:
   case GL_INTERNALFORMAT_BLUE_TYPE:
   case GL_INTERNALFORMAT_ALPHA_TYPE:
   case GL_INTERNALFORMAT_DEPTH_TYPE:
   case GL_INTERNALFORMAT_STENCIL_TYPE: {
      GLint baseformat;
      mesa_format texformat;

      if (target != GL_RENDERBUFFER) {
         if (!_mesa_legal_get_tex_level_parameter_target(ctx, target, true))
            goto end;

         baseformat = _mesa_base_tex_format(ctx, internalformat);
      } else {
         baseformat = _mesa_base_fbo_format(ctx, internalformat);
      }

      /* Let the driver choose the texture format.
       *
       * Disclaimer: I am considering that drivers use for renderbuffers the
       * same format-choice logic as for textures.
       */
      texformat = ctx->Driver.ChooseTextureFormat(ctx, target, internalformat,
                                                  GL_NONE /*format */, GL_NONE /* type */);

      if (texformat == MESA_FORMAT_NONE || baseformat <= 0)
         goto end;

      /* Implementation based on what Mesa does for glGetTexLevelParameteriv
       * and glGetRenderbufferParameteriv functions.
       */
      if (pname == GL_INTERNALFORMAT_SHARED_SIZE) {
         if (_mesa_has_EXT_texture_shared_exponent(ctx) &&
             target != GL_TEXTURE_BUFFER &&
             target != GL_RENDERBUFFER &&
             texformat == MESA_FORMAT_R9G9B9E5_FLOAT) {
            buffer[0] = 5;
         }
         goto end;
      }

      if (!_mesa_base_format_has_channel(baseformat, pname))
         goto end;

      switch (pname) {
      case GL_INTERNALFORMAT_DEPTH_SIZE:
         if (ctx->API != API_OPENGL_CORE &&
             !_mesa_has_ARB_depth_texture(ctx) &&
             target != GL_RENDERBUFFER &&
             target != GL_TEXTURE_BUFFER)
            goto end;
         /* fallthrough */
      case GL_INTERNALFORMAT_RED_SIZE:
      case GL_INTERNALFORMAT_GREEN_SIZE:
      case GL_INTERNALFORMAT_BLUE_SIZE:
      case GL_INTERNALFORMAT_ALPHA_SIZE:
      case GL_INTERNALFORMAT_STENCIL_SIZE:
         buffer[0] = _mesa_get_format_bits(texformat, pname);
         break;

      case GL_INTERNALFORMAT_DEPTH_TYPE:
         if (!_mesa_has_ARB_texture_float(ctx))
            goto end;
         /* fallthrough */
      case GL_INTERNALFORMAT_RED_TYPE:
      case GL_INTERNALFORMAT_GREEN_TYPE:
      case GL_INTERNALFORMAT_BLUE_TYPE:
      case GL_INTERNALFORMAT_ALPHA_TYPE:
      case GL_INTERNALFORMAT_STENCIL_TYPE:
         buffer[0]  = _mesa_get_format_datatype(texformat);
         break;

      default:
         break;

      }
      break;
   }

      /* For WIDTH/HEIGHT/DEPTH/LAYERS there is no reason to think that the
       * returned values should be different to the values returned by
       * GetInteger with MAX_TEXTURE_SIZE, MAX_3D_TEXTURE_SIZE, etc.*/
   case GL_MAX_WIDTH:
   case GL_MAX_HEIGHT:
   case GL_MAX_DEPTH: {
      GLenum get_pname;
      GLint dimensions;
      GLint min_dimensions;

      /* From query2:MAX_HEIGHT spec (as example):
       *
       * "If the resource does not have at least two dimensions, or if the
       * resource is unsupported, zero is returned."
       */
      dimensions = _get_target_dimensions(target);
      min_dimensions = _get_min_dimensions(pname);
      if (dimensions < min_dimensions)
         goto end;

      get_pname = _equivalent_size_pname(target, pname);
      if (get_pname == 0)
         goto end;

      _mesa_GetIntegerv(get_pname, buffer);
      break;
   }

   case GL_MAX_LAYERS:
      if (!_mesa_has_EXT_texture_array(ctx))
         goto end;

      if (!_mesa_is_array_texture(target))
         goto end;

      _mesa_GetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, buffer);
      break;

   case GL_MAX_COMBINED_DIMENSIONS:{
      GLint64 combined_value = 1;
      GLenum max_dimensions_pnames[] = {
         GL_MAX_WIDTH,
         GL_MAX_HEIGHT,
         GL_MAX_DEPTH,
         GL_SAMPLES
      };
      unsigned i;
      GLint current_value;

      /* Combining the dimensions. Note that for array targets, this would
       * automatically include the value of MAX_LAYERS, as that value is
       * returned as MAX_HEIGHT or MAX_DEPTH */
      for (i = 0; i < 4; i++) {
         if (max_dimensions_pnames[i] == GL_SAMPLES &&
             !_is_multisample_target(target))
            continue;

         _mesa_GetInternalformativ(target, internalformat,
                                   max_dimensions_pnames[i],
                                   1, &current_value);

         if (current_value != 0)
            combined_value *= current_value;
      }

      if (_mesa_is_cube_map_texture(target))
         combined_value *= 6;

      /* We pack the 64-bit value on two 32-bit values. Calling the 32-bit
       * query, this would work as far as the value can be hold on a 32-bit
       * signed integer. For the 64-bit query, the wrapper around the 32-bit
       * query will unpack the value */
      memcpy(buffer, &combined_value, sizeof(GLint64));
      break;
   }

   case GL_COLOR_COMPONENTS:
      /* The ARB_internalformat_query2 spec says:
       *
       *     "- COLOR_COMPONENTS: If the internal format contains any color
       *     components (R, G, B, or A), TRUE is returned in <params>.
       *     If the internal format is unsupported or contains no color
       *     components, FALSE is returned."
       */
      if (_mesa_is_color_format(internalformat))
         buffer[0] = GL_TRUE;
      break;

   case GL_DEPTH_COMPONENTS:
      /* The ARB_internalformat_query2 spec says:
       *
       *     "- DEPTH_COMPONENTS: If the internal format contains a depth
       *     component (D), TRUE is returned in <params>. If the internal format
       *     is unsupported or contains no depth component, FALSE is returned."
       */
      if (_mesa_is_depth_format(internalformat) ||
          _mesa_is_depthstencil_format(internalformat))
         buffer[0] = GL_TRUE;
      break;

   case GL_STENCIL_COMPONENTS:
      /* The ARB_internalformat_query2 spec says:
       *
       *     "- STENCIL_COMPONENTS: If the internal format contains a stencil
       *     component (S), TRUE is returned in <params>. If the internal format
       *     is unsupported or contains no stencil component, FALSE is returned.
       */
      if (_mesa_is_stencil_format(internalformat) ||
          _mesa_is_depthstencil_format(internalformat))
         buffer[0] = GL_TRUE;
      break;

   case GL_COLOR_RENDERABLE:
   case GL_DEPTH_RENDERABLE:
   case GL_STENCIL_RENDERABLE:
      if (!_is_renderable(ctx, internalformat))
         goto end;

      if (pname == GL_COLOR_RENDERABLE) {
         if (!_mesa_is_color_format(internalformat))
            goto end;
      } else {
         GLenum baseFormat = _mesa_base_fbo_format(ctx, internalformat);
         if (baseFormat != GL_DEPTH_STENCIL &&
             ((pname == GL_DEPTH_RENDERABLE && baseFormat != GL_DEPTH_COMPONENT) ||
              (pname == GL_STENCIL_RENDERABLE && baseFormat != GL_STENCIL_INDEX)))
            goto end;
      }

      buffer[0] = GL_TRUE;
      break;

   case GL_FRAMEBUFFER_RENDERABLE_LAYERED:
      if (!_mesa_has_EXT_texture_array(ctx) ||
          _legal_target_for_framebuffer_texture_layer(ctx, target))
         goto end;
      /* fallthrough */
   case GL_FRAMEBUFFER_RENDERABLE:
   case GL_FRAMEBUFFER_BLEND:
      if (!_mesa_has_ARB_framebuffer_object(ctx))
         goto end;

      if (target == GL_TEXTURE_BUFFER ||
          !_is_renderable(ctx, internalformat))
         goto end;

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_READ_PIXELS:
   case GL_READ_PIXELS_FORMAT:
   case GL_READ_PIXELS_TYPE:
      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_TEXTURE_IMAGE_FORMAT:
   case GL_GET_TEXTURE_IMAGE_FORMAT:
   case GL_TEXTURE_IMAGE_TYPE:
   case GL_GET_TEXTURE_IMAGE_TYPE:
      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_MIPMAP:
   case GL_MANUAL_GENERATE_MIPMAP:
   case GL_AUTO_GENERATE_MIPMAP:
      if (!_mesa_is_valid_generate_texture_mipmap_target(ctx, target) ||
          !_mesa_is_valid_generate_texture_mipmap_internalformat(ctx,
                                                              internalformat)) {
         goto end;
      }

      if (pname == GL_MIPMAP) {
         buffer[0] = GL_TRUE;
         goto end;
      }
      else if (pname == GL_MANUAL_GENERATE_MIPMAP) {
         if (!_mesa_has_ARB_framebuffer_object(ctx))
            goto end;
      }
      else {
         /* From ARB_internalformat_query2:
          *    "Dependencies on OpenGL 3.2 (Core Profile)
          *     In core profiles for OpenGL 3.2 and later versions, queries
          *     for the AUTO_GENERATE_MIPMAP <pname> return the appropriate
          *     unsupported response."
          */
         if (_mesa_is_desktop_gl(ctx) && ctx->Version >= 32)
            goto end;
      }

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_COLOR_ENCODING:
      if (!_mesa_is_color_format(internalformat))
         goto end;

      if (_mesa_is_srgb_format(internalformat))
         buffer[0] = GL_SRGB;
      else
         buffer[0] = GL_LINEAR;
      break;

   case GL_SRGB_READ:
      if (!_mesa_has_EXT_texture_sRGB(ctx) ||
          !_mesa_is_srgb_format(internalformat)) {
         goto end;
      }

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_SRGB_WRITE:
      if (!_mesa_has_EXT_framebuffer_sRGB(ctx) ||
          !_mesa_is_color_format(internalformat)) {
         goto end;
      }

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_SRGB_DECODE_ARB:
      /* Presence of EXT_texture_sRGB_decode was already verified */
      if (!_mesa_has_EXT_texture_sRGB(ctx) ||
          target == GL_RENDERBUFFER ||
          !_mesa_is_srgb_format(internalformat)) {
         goto end;
      }

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_FILTER:
      /* If it doesn't allow to set sampler parameters then it would not allow
       * to set a filter different to GL_NEAREST. In practice, this method
       * only filters out MULTISAMPLE/MULTISAMPLE_ARRAY */
      if (!_mesa_target_allows_setting_sampler_parameters(target))
         goto end;

      if (_mesa_is_enum_format_integer(internalformat))
         goto end;

      if (target == GL_TEXTURE_BUFFER)
         goto end;

      /* At this point we know that multi-texel filtering is supported. We
       * need to call the driver to know if it is CAVEAT_SUPPORT or
       * FULL_SUPPORT.
       */
      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_VERTEX_TEXTURE:
   case GL_TESS_CONTROL_TEXTURE:
   case GL_TESS_EVALUATION_TEXTURE:
   case GL_GEOMETRY_TEXTURE:
   case GL_FRAGMENT_TEXTURE:
   case GL_COMPUTE_TEXTURE:
      if (target == GL_RENDERBUFFER)
         goto end;

      if ((pname == GL_TESS_CONTROL_TEXTURE ||
           pname == GL_TESS_EVALUATION_TEXTURE) &&
          !_mesa_has_tessellation(ctx))
         goto end;

      if (pname == GL_GEOMETRY_TEXTURE && !_mesa_has_geometry_shaders(ctx))
         goto end;

      if (pname == GL_COMPUTE_TEXTURE && !_mesa_has_compute_shaders(ctx))
         goto end;

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_TEXTURE_GATHER:
   case GL_TEXTURE_GATHER_SHADOW:
      if (!_mesa_has_ARB_texture_gather(ctx))
         goto end;

      /* fallthrough */
   case GL_TEXTURE_SHADOW:
      /* Only depth or depth-stencil image formats make sense in shadow
         samplers */
      if (pname != GL_TEXTURE_GATHER &&
          !_mesa_is_depth_format(internalformat) &&
          !_mesa_is_depthstencil_format(internalformat))
         goto end;

      /* Validate the target for shadow and gather operations */
      switch (target) {
      case GL_TEXTURE_2D:
      case GL_TEXTURE_2D_ARRAY:
      case GL_TEXTURE_CUBE_MAP:
      case GL_TEXTURE_CUBE_MAP_ARRAY:
      case GL_TEXTURE_RECTANGLE:
         break;

      case GL_TEXTURE_1D:
      case GL_TEXTURE_1D_ARRAY:
         /* 1D and 1DArray textures are not admitted in gather operations */
         if (pname != GL_TEXTURE_SHADOW)
            goto end;
         break;

      default:
         goto end;
      }

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_SHADER_IMAGE_LOAD:
   case GL_SHADER_IMAGE_STORE:
      if (!_mesa_has_ARB_shader_image_load_store(ctx))
         goto end;

      /* We call to _mesa_is_shader_image_format_supported
       * using "internalformat" as parameter, because the
       * the ARB_internalformat_query2 spec says:
       * "In this case the <internalformat> is the value of the <format>
       * parameter that is passed to BindImageTexture."
       */
      if (target == GL_RENDERBUFFER ||
          !_mesa_is_shader_image_format_supported(ctx, internalformat))
         goto end;

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_SHADER_IMAGE_ATOMIC:
      if (!_mesa_has_ARB_shader_image_load_store(ctx))
         goto end;

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_IMAGE_TEXEL_SIZE: {
      mesa_format image_format;

      if (!_mesa_has_ARB_shader_image_load_store(ctx) ||
          target == GL_RENDERBUFFER)
         goto end;

      image_format = _mesa_get_shader_image_format(internalformat);
      if (image_format == MESA_FORMAT_NONE)
         goto end;

      /* We return bits */
      buffer[0] = (_mesa_get_format_bytes(image_format) * 8);
      break;
   }

   case GL_IMAGE_COMPATIBILITY_CLASS:
      if (!_mesa_has_ARB_shader_image_load_store(ctx) ||
          target == GL_RENDERBUFFER)
         goto end;

      buffer[0] = _mesa_get_image_format_class(internalformat);
      break;

   case GL_IMAGE_PIXEL_FORMAT: {
      GLint base_format;

      if (!_mesa_has_ARB_shader_image_load_store(ctx) ||
          target == GL_RENDERBUFFER ||
          !_mesa_is_shader_image_format_supported(ctx, internalformat))
         goto end;

      base_format = _mesa_base_tex_format(ctx, internalformat);
      if (base_format == -1)
         goto end;

      if (_mesa_is_enum_format_integer(internalformat))
         buffer[0] = _mesa_base_format_to_integer_format(base_format);
      else
         buffer[0] = base_format;
      break;
   }

   case GL_IMAGE_PIXEL_TYPE: {
      mesa_format image_format;
      GLenum datatype;
      GLuint comps;

      if (!_mesa_has_ARB_shader_image_load_store(ctx) ||
          target == GL_RENDERBUFFER)
         goto end;

      image_format = _mesa_get_shader_image_format(internalformat);
      if (image_format == MESA_FORMAT_NONE)
         goto end;

      _mesa_uncompressed_format_to_type_and_comps(image_format, &datatype,
                                                  &comps);
      if (!datatype)
         goto end;

      buffer[0] = datatype;
      break;
   }

   case GL_IMAGE_FORMAT_COMPATIBILITY_TYPE: {
      if (!_mesa_has_ARB_shader_image_load_store(ctx))
         goto end;

      if (!_mesa_legal_get_tex_level_parameter_target(ctx, target, true))
         goto end;

      /* From spec: "Equivalent to calling GetTexParameter with <value> set
       * to IMAGE_FORMAT_COMPATIBILITY_TYPE."
       *
       * GetTexParameter just returns
       * tex_obj->ImageFormatCompatibilityType. We create a fake tex_obj
       * just with the purpose of getting the value.
       */
      struct gl_texture_object *tex_obj = _mesa_new_texture_object(ctx, 0, target);
      buffer[0] = tex_obj->ImageFormatCompatibilityType;
      _mesa_delete_texture_object(ctx, tex_obj);

      break;
   }

   case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST:
   case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST:
   case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE:
   case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE:
      if (target == GL_RENDERBUFFER)
         goto end;

      if (!_mesa_is_depthstencil_format(internalformat)) {
         if (((pname == GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST ||
               pname == GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE) &&
              !_mesa_is_depth_format(internalformat)) ||
             ((pname == GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST ||
               pname == GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE) &&
              !_mesa_is_stencil_format(internalformat)))
            goto end;
      }

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_TEXTURE_COMPRESSED:
      buffer[0] = _mesa_is_compressed_format(ctx, internalformat);
      break;

   case GL_TEXTURE_COMPRESSED_BLOCK_WIDTH:
   case GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT:
   case GL_TEXTURE_COMPRESSED_BLOCK_SIZE: {
      mesa_format mesaformat;
      GLint block_size;

      mesaformat = _mesa_glenum_to_compressed_format(internalformat);
      if (mesaformat == MESA_FORMAT_NONE)
         goto end;

      block_size = _mesa_get_format_bytes(mesaformat);
      assert(block_size > 0);

      if (pname == GL_TEXTURE_COMPRESSED_BLOCK_SIZE) {
         buffer[0] = block_size;
      } else {
         GLuint bwidth, bheight;

         /* Returns the width and height in pixels. We return bytes */
         _mesa_get_format_block_size(mesaformat, &bwidth, &bheight);
         assert(bwidth > 0 && bheight > 0);

         if (pname == GL_TEXTURE_COMPRESSED_BLOCK_WIDTH)
            buffer[0] = block_size / bheight;
         else
            buffer[0] = block_size / bwidth;
      }
      break;
   }

   case GL_CLEAR_BUFFER:
      if (target != GL_TEXTURE_BUFFER)
         goto end;

      ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                      buffer);
      break;

   case GL_TEXTURE_VIEW:
   case GL_VIEW_COMPATIBILITY_CLASS:
      if (!_mesa_has_ARB_texture_view(ctx) ||
          target == GL_TEXTURE_BUFFER ||
          target == GL_RENDERBUFFER)
         goto end;

      if (pname == GL_TEXTURE_VIEW) {
         ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname,
                                         buffer);
      } else {
         GLenum view_class = _mesa_texture_view_lookup_view_class(ctx,
                                                                  internalformat);
         if (view_class == GL_FALSE)
            goto end;

         buffer[0] = view_class;
      }
      break;

   default:
      unreachable("bad param");
   }

 end:
   if (bufSize != 0 && params == NULL) {
      /* Emit a warning to aid application debugging, but go ahead and do the
       * memcpy (and probably crash) anyway.
       */
      _mesa_warning(ctx,
                    "glGetInternalformativ(bufSize = %d, but params = NULL)",
                    bufSize);
   }

   /* Copy the data from the temporary buffer to the buffer supplied by the
    * application.  Clamp the size of the copy to the size supplied by the
    * application.
    */
   memcpy(params, buffer, MIN2(bufSize, 16) * sizeof(GLint));

   return;
}
static void
setup_glsl_msaa_blit_shader(struct gl_context *ctx,
                            struct blit_state *blit,
                            const struct gl_framebuffer *drawFb,
                            struct gl_renderbuffer *src_rb,
                            GLenum target)
{
   const char *vs_source;
   char *fs_source;
   void *mem_ctx;
   enum blit_msaa_shader shader_index;
   bool dst_is_msaa = false;
   GLenum src_datatype;
   const char *vec4_prefix;
   const char *sampler_array_suffix = "";
   char *name;
   const char *texcoord_type = "vec2";
   int samples;
   int shader_offset = 0;

   if (src_rb) {
      samples = MAX2(src_rb->NumSamples, 1);
      src_datatype = _mesa_get_format_datatype(src_rb->Format);
   } else {
      /* depth-or-color glCopyTexImage fallback path that passes a NULL rb and
       * doesn't handle integer.
       */
      samples = 1;
      src_datatype = GL_UNSIGNED_NORMALIZED;
   }

   /* We expect only power of 2 samples in source multisample buffer. */
   assert(samples > 0 && _mesa_is_pow_two(samples));
   while (samples >> (shader_offset + 1)) {
      shader_offset++;
   }
   /* Update the assert if we plan to support more than 16X MSAA. */
   assert(shader_offset >= 0 && shader_offset <= 4);

   if (drawFb->Visual.samples > 1) {
      /* If you're calling meta_BlitFramebuffer with the destination
       * multisampled, this is the only path that will work -- swrast and
       * CopyTexImage won't work on it either.
       */
      assert(ctx->Extensions.ARB_sample_shading);

      dst_is_msaa = true;

      /* We need shader invocation per sample, not per pixel */
      _mesa_set_enable(ctx, GL_MULTISAMPLE, GL_TRUE);
      _mesa_set_enable(ctx, GL_SAMPLE_SHADING, GL_TRUE);
      _mesa_MinSampleShading(1.0);
   }

   switch (target) {
   case GL_TEXTURE_2D_MULTISAMPLE:
   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
      if (src_rb && (src_rb->_BaseFormat == GL_DEPTH_COMPONENT ||
          src_rb->_BaseFormat == GL_DEPTH_STENCIL)) {
         if (dst_is_msaa)
            shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_COPY;
         else
            shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_RESOLVE;
      } else {
         if (dst_is_msaa)
            shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_COPY;
         else {
            shader_index = BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE +
                           shader_offset;
         }
      }

      if (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) {
         shader_index += (BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_RESOLVE -
                          BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE);
         sampler_array_suffix = "Array";
         texcoord_type = "vec3";
      }
      break;
   default:
      _mesa_problem(ctx, "Unkown texture target %s\n",
                    _mesa_enum_to_string(target));
      shader_index = BLIT_2X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE;
   }

   /* We rely on the enum being sorted this way. */
   STATIC_ASSERT(BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_INT ==
                 BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 5);
   STATIC_ASSERT(BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_UINT ==
                 BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 10);
   if (src_datatype == GL_INT) {
      shader_index += 5;
      vec4_prefix = "i";
   } else if (src_datatype == GL_UNSIGNED_INT) {
      shader_index += 10;
      vec4_prefix = "u";
   } else {
      vec4_prefix = "";
   }

   if (blit->msaa_shaders[shader_index]) {
      _mesa_UseProgram(blit->msaa_shaders[shader_index]);
      return;
   }

   mem_ctx = ralloc_context(NULL);

   if (shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_RESOLVE ||
       shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_DEPTH_RESOLVE ||
       shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_DEPTH_COPY ||
       shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_COPY) {
      char *sample_index;
      const char *arb_sample_shading_extension_string;

      if (dst_is_msaa) {
         arb_sample_shading_extension_string = "#extension GL_ARB_sample_shading : enable";
         sample_index = "gl_SampleID";
         name = "depth MSAA copy";
      } else {
         /* Don't need that extension, since we're drawing to a single-sampled
          * destination.
          */
         arb_sample_shading_extension_string = "";
         /* From the GL 4.3 spec:
          *
          *     "If there is a multisample buffer (the value of SAMPLE_BUFFERS
          *      is one), then values are obtained from the depth samples in
          *      this buffer. It is recommended that the depth value of the
          *      centermost sample be used, though implementations may choose
          *      any function of the depth sample values at each pixel.
          *
          * We're slacking and instead of choosing centermost, we've got 0.
          */
         sample_index = "0";
         name = "depth MSAA resolve";
      }

      vs_source = ralloc_asprintf(mem_ctx,
                                  "#version 130\n"
                                  "in vec2 position;\n"
                                  "in %s textureCoords;\n"
                                  "out %s texCoords;\n"
                                  "void main()\n"
                                  "{\n"
                                  "   texCoords = textureCoords;\n"
                                  "   gl_Position = vec4(position, 0.0, 1.0);\n"
                                  "}\n",
                                  texcoord_type,
                                  texcoord_type);
      fs_source = ralloc_asprintf(mem_ctx,
                                  "#version 130\n"
                                  "#extension GL_ARB_texture_multisample : enable\n"
                                  "%s\n"
                                  "uniform sampler2DMS%s texSampler;\n"
                                  "in %s texCoords;\n"
                                  "out vec4 out_color;\n"
                                  "\n"
                                  "void main()\n"
                                  "{\n"
                                  "   gl_FragDepth = texelFetch(texSampler, i%s(texCoords), %s).r;\n"
                                  "}\n",
                                  arb_sample_shading_extension_string,
                                  sampler_array_suffix,
                                  texcoord_type,
                                  texcoord_type,
                                  sample_index);
   } else {
      /* You can create 2D_MULTISAMPLE textures with 0 sample count (meaning 1
       * sample).  Yes, this is ridiculous.
       */
      char *sample_resolve;
      const char *arb_sample_shading_extension_string;
      const char *merge_function;
      name = ralloc_asprintf(mem_ctx, "%svec4 MSAA %s",
                             vec4_prefix,
                             dst_is_msaa ? "copy" : "resolve");

      if (dst_is_msaa) {
         arb_sample_shading_extension_string = "#extension GL_ARB_sample_shading : enable";
         sample_resolve = ralloc_asprintf(mem_ctx, "   out_color = texelFetch(texSampler, i%s(texCoords), gl_SampleID);", texcoord_type);
         merge_function = "";
      } else {
         int i;
         int step;

         if (src_datatype == GL_INT || src_datatype == GL_UNSIGNED_INT) {
            merge_function =
               "gvec4 merge(gvec4 a, gvec4 b) { return (a >> gvec4(1)) + (b >> gvec4(1)) + (a & b & gvec4(1)); }\n";
         } else {
            /* The divide will happen at the end for floats. */
            merge_function =
               "vec4 merge(vec4 a, vec4 b) { return (a + b); }\n";
         }

         arb_sample_shading_extension_string = "";

         /* We're assuming power of two samples for this resolution procedure.
          *
          * To avoid losing any floating point precision if the samples all
          * happen to have the same value, we merge pairs of values at a time
          * (so the floating point exponent just gets increased), rather than
          * doing a naive sum and dividing.
          */
         assert(_mesa_is_pow_two(samples));
         /* Fetch each individual sample. */
         sample_resolve = rzalloc_size(mem_ctx, 1);
         for (i = 0; i < samples; i++) {
            ralloc_asprintf_append(&sample_resolve,
                                   "   gvec4 sample_1_%d = texelFetch(texSampler, i%s(texCoords), %d);\n",
                                   i, texcoord_type, i);
         }
         /* Now, merge each pair of samples, then merge each pair of those,
          * etc.
          */
         for (step = 2; step <= samples; step *= 2) {
            for (i = 0; i < samples; i += step) {
               ralloc_asprintf_append(&sample_resolve,
                                      "   gvec4 sample_%d_%d = merge(sample_%d_%d, sample_%d_%d);\n",
                                      step, i,
                                      step / 2, i,
                                      step / 2, i + step / 2);
            }
         }

         /* Scale the final result. */
         if (src_datatype == GL_UNSIGNED_INT || src_datatype == GL_INT) {
            ralloc_asprintf_append(&sample_resolve,
                                   "   out_color = sample_%d_0;\n",
                                   samples);
         } else {
            ralloc_asprintf_append(&sample_resolve,
                                   "   gl_FragColor = sample_%d_0 / %f;\n",
                                   samples, (float)samples);
         }
      }

      vs_source = ralloc_asprintf(mem_ctx,
                                  "#version 130\n"
                                  "in vec2 position;\n"
                                  "in %s textureCoords;\n"
                                  "out %s texCoords;\n"
                                  "void main()\n"
                                  "{\n"
                                  "   texCoords = textureCoords;\n"
                                  "   gl_Position = vec4(position, 0.0, 1.0);\n"
                                  "}\n",
                                  texcoord_type,
                                  texcoord_type);
      fs_source = ralloc_asprintf(mem_ctx,
                                  "#version 130\n"
                                  "#extension GL_ARB_texture_multisample : enable\n"
                                  "%s\n"
                                  "#define gvec4 %svec4\n"
                                  "uniform %ssampler2DMS%s texSampler;\n"
                                  "in %s texCoords;\n"
                                  "out gvec4 out_color;\n"
                                  "\n"
                                  "%s" /* merge_function */
                                  "void main()\n"
                                  "{\n"
                                  "%s\n" /* sample_resolve */
                                  "}\n",
                                  arb_sample_shading_extension_string,
                                  vec4_prefix,
                                  vec4_prefix,
                                  sampler_array_suffix,
                                  texcoord_type,
                                  merge_function,
                                  sample_resolve);
   }

   _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source, name,
                                       &blit->msaa_shaders[shader_index]);

   ralloc_free(mem_ctx);
}
Example #24
0
static GLenum
read_pixels_es3_error_check(GLenum format, GLenum type,
                            const struct gl_renderbuffer *rb)
{
   const GLenum internalFormat = rb->InternalFormat;
   const GLenum data_type = _mesa_get_format_datatype(rb->Format);
   GLboolean is_unsigned_int = GL_FALSE;
   GLboolean is_signed_int = GL_FALSE;
   GLboolean is_float_depth = (internalFormat == GL_DEPTH_COMPONENT32F) ||
         (internalFormat == GL_DEPTH32F_STENCIL8);

   is_unsigned_int = _mesa_is_enum_format_unsigned_int(internalFormat);
   if (!is_unsigned_int) {
      is_signed_int = _mesa_is_enum_format_signed_int(internalFormat);
   }

   switch (format) {
   case GL_RGBA:
      if (type == GL_FLOAT && data_type == GL_FLOAT)
         return GL_NO_ERROR; /* EXT_color_buffer_float */
      if (type == GL_UNSIGNED_BYTE && data_type == GL_UNSIGNED_NORMALIZED)
         return GL_NO_ERROR;
      if (internalFormat == GL_RGB10_A2 &&
          type == GL_UNSIGNED_INT_2_10_10_10_REV)
         return GL_NO_ERROR;
      if (internalFormat == GL_RGB10_A2UI && type == GL_UNSIGNED_BYTE)
         return GL_NO_ERROR;
      break;
   case GL_BGRA:
      /* GL_EXT_read_format_bgra */
      if (type == GL_UNSIGNED_BYTE ||
          type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
          type == GL_UNSIGNED_SHORT_1_5_5_5_REV)
         return GL_NO_ERROR;
      break;
   case GL_RGBA_INTEGER:
      if ((is_signed_int && type == GL_INT) ||
          (is_unsigned_int && type == GL_UNSIGNED_INT))
         return GL_NO_ERROR;
      break;
   case GL_DEPTH_STENCIL:
      switch (type) {
      case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
         if (is_float_depth)
            return GL_NO_ERROR;
         break;
      case GL_UNSIGNED_INT_24_8:
         if (!is_float_depth)
            return GL_NO_ERROR;
         break;
      default:
         return GL_INVALID_ENUM;
      }
      break;
   case GL_DEPTH_COMPONENT:
      switch (type) {
      case GL_FLOAT:
         if (is_float_depth)
            return GL_NO_ERROR;
         break;
      case GL_UNSIGNED_SHORT:
      case GL_UNSIGNED_INT:
      case GL_UNSIGNED_INT_24_8:
         if (!is_float_depth)
            return GL_NO_ERROR;
         break;
      default:
         return GL_INVALID_ENUM;
      }
      break;
   case GL_STENCIL_INDEX:
      switch (type) {
      case GL_UNSIGNED_BYTE:
         return GL_NO_ERROR;
      default:
         return GL_INVALID_ENUM;
      }
      break;
   }

   return GL_INVALID_OPERATION;
}
Example #25
0
static void
gen6_upload_blend_state(struct brw_context *brw)
{
   bool is_buffer_zero_integer_format = false;
   struct gl_context *ctx = &brw->intel.ctx;
   struct gen6_blend_state *blend;
   int b;
   int nr_draw_buffers = ctx->DrawBuffer->_NumColorDrawBuffers;
   int size;

   /* We need at least one BLEND_STATE written, because we might do
    * thread dispatch even if _NumColorDrawBuffers is 0 (for example
    * for computed depth or alpha test), which will do an FB write
    * with render target 0, which will reference BLEND_STATE[0] for
    * alpha test enable.
    */
   if (nr_draw_buffers == 0 && ctx->Color.AlphaEnabled)
      nr_draw_buffers = 1;

   size = sizeof(*blend) * nr_draw_buffers;
   blend = brw_state_batch(brw, AUB_TRACE_BLEND_STATE,
			   size, 64, &brw->cc.blend_state_offset);

   memset(blend, 0, size);

   for (b = 0; b < nr_draw_buffers; b++) {
      /* _NEW_BUFFERS */
      struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[b];
      GLenum rb_type;
      bool integer;

      if (rb)
	 rb_type = _mesa_get_format_datatype(rb->Format);
      else
	 rb_type = GL_UNSIGNED_NORMALIZED;

      /* Used for implementing the following bit of GL_EXT_texture_integer:
       *     "Per-fragment operations that require floating-point color
       *      components, including multisample alpha operations, alpha test,
       *      blending, and dithering, have no effect when the corresponding
       *      colors are written to an integer color buffer."
      */
      integer = (rb_type == GL_INT || rb_type == GL_UNSIGNED_INT);

      if(b == 0 && integer)
         is_buffer_zero_integer_format = true;

      /* _NEW_COLOR */
      if (ctx->Color.ColorLogicOpEnabled) {
	 /* Floating point RTs should have no effect from LogicOp,
	  * except for disabling of blending, but other types should.
	  *
	  * However, from the Sandy Bridge PRM, Vol 2 Par 1, Section 8.1.11,
	  * "Logic Ops",
	  *
	  *     "Logic Ops are only supported on *_UNORM surfaces (excluding
	  *      _SRGB variants), otherwise Logic Ops must be DISABLED."
	  */
         WARN_ONCE(ctx->Color.LogicOp != GL_COPY &&
                   rb_type != GL_UNSIGNED_NORMALIZED &&
                   rb_type != GL_FLOAT, "Ignoring %s logic op on %s "
                   "renderbuffer\n",
                   _mesa_lookup_enum_by_nr(ctx->Color.LogicOp),
                   _mesa_lookup_enum_by_nr(rb_type));
	 if (rb_type == GL_UNSIGNED_NORMALIZED) {
	    blend[b].blend1.logic_op_enable = 1;
	    blend[b].blend1.logic_op_func =
	       intel_translate_logic_op(ctx->Color.LogicOp);
	 }
      } else if (ctx->Color.BlendEnabled & (1 << b) && !integer) {
	 GLenum eqRGB = ctx->Color.Blend[b].EquationRGB;
	 GLenum eqA = ctx->Color.Blend[b].EquationA;
	 GLenum srcRGB = ctx->Color.Blend[b].SrcRGB;
	 GLenum dstRGB = ctx->Color.Blend[b].DstRGB;
	 GLenum srcA = ctx->Color.Blend[b].SrcA;
	 GLenum dstA = ctx->Color.Blend[b].DstA;

	 if (eqRGB == GL_MIN || eqRGB == GL_MAX) {
	    srcRGB = dstRGB = GL_ONE;
	 }

	 if (eqA == GL_MIN || eqA == GL_MAX) {
	    srcA = dstA = GL_ONE;
	 }

	 blend[b].blend0.dest_blend_factor = brw_translate_blend_factor(dstRGB);
	 blend[b].blend0.source_blend_factor = brw_translate_blend_factor(srcRGB);
	 blend[b].blend0.blend_func = brw_translate_blend_equation(eqRGB);

	 blend[b].blend0.ia_dest_blend_factor = brw_translate_blend_factor(dstA);
	 blend[b].blend0.ia_source_blend_factor = brw_translate_blend_factor(srcA);
	 blend[b].blend0.ia_blend_func = brw_translate_blend_equation(eqA);

	 blend[b].blend0.blend_enable = 1;
	 blend[b].blend0.ia_blend_enable = (srcA != srcRGB ||
					 dstA != dstRGB ||
					 eqA != eqRGB);
      }

      /* See section 8.1.6 "Pre-Blend Color Clamping" of the
       * SandyBridge PRM Volume 2 Part 1 for HW requirements.
       *
       * We do our ARB_color_buffer_float CLAMP_FRAGMENT_COLOR
       * clamping in the fragment shader.  For its clamping of
       * blending, the spec says:
       *
       *     "RESOLVED: For fixed-point color buffers, the inputs and
       *      the result of the blending equation are clamped.  For
       *      floating-point color buffers, no clamping occurs."
       *
       * So, generally, we want clamping to the render target's range.
       * And, good news, the hardware tables for both pre- and
       * post-blend color clamping are either ignored, or any are
       * allowed, or clamping is required but RT range clamping is a
       * valid option.
       */
      blend[b].blend1.pre_blend_clamp_enable = 1;
      blend[b].blend1.post_blend_clamp_enable = 1;
      blend[b].blend1.clamp_range = BRW_RENDERTARGET_CLAMPRANGE_FORMAT;

      /* _NEW_COLOR */
      if (ctx->Color.AlphaEnabled && !integer) {
	 blend[b].blend1.alpha_test_enable = 1;
	 blend[b].blend1.alpha_test_func =
	    intel_translate_compare_func(ctx->Color.AlphaFunc);

      }

      /* _NEW_COLOR */
      if (ctx->Color.DitherFlag && !integer) {
	 blend[b].blend1.dither_enable = 1;
	 blend[b].blend1.y_dither_offset = 0;
	 blend[b].blend1.x_dither_offset = 0;
      }

      blend[b].blend1.write_disable_r = !ctx->Color.ColorMask[b][0];
      blend[b].blend1.write_disable_g = !ctx->Color.ColorMask[b][1];
      blend[b].blend1.write_disable_b = !ctx->Color.ColorMask[b][2];
      blend[b].blend1.write_disable_a = !ctx->Color.ColorMask[b][3];

      /* OpenGL specification 3.3 (page 196), section 4.1.3 says:
       * "If drawbuffer zero is not NONE and the buffer it references has an
       * integer format, the SAMPLE_ALPHA_TO_COVERAGE and SAMPLE_ALPHA_TO_ONE
       * operations are skipped."
       */
      if(!is_buffer_zero_integer_format) {
         /* _NEW_MULTISAMPLE */
         blend[b].blend1.alpha_to_coverage =
            ctx->Multisample._Enabled && ctx->Multisample.SampleAlphaToCoverage;

	/* From SandyBridge PRM, volume 2 Part 1, section 8.2.3, BLEND_STATE:
	 * DWord 1, Bit 30 (AlphaToOne Enable):
	 * "If Dual Source Blending is enabled, this bit must be disabled"
	 */
         WARN_ONCE(ctx->Color.Blend[b]._UsesDualSrc &&
                   ctx->Multisample._Enabled &&
                   ctx->Multisample.SampleAlphaToOne,
                   "HW workaround: disabling alpha to one with dual src "
                   "blending\n");
	 if (ctx->Color.Blend[b]._UsesDualSrc)
            blend[b].blend1.alpha_to_one = false;
	 else
	    blend[b].blend1.alpha_to_one =
	       ctx->Multisample._Enabled && ctx->Multisample.SampleAlphaToOne;

         blend[b].blend1.alpha_to_coverage_dither = (brw->intel.gen >= 7);
      }
      else {
         blend[b].blend1.alpha_to_coverage = false;
         blend[b].blend1.alpha_to_one = false;
      }
   }

   brw->state.dirty.cache |= CACHE_NEW_BLEND_STATE;
}
Example #26
0
void GLAPIENTRY
_mesa_GetTexLevelParameteriv( GLenum target, GLint level,
                              GLenum pname, GLint *params )
{
   struct gl_texture_object *texObj;
   const struct gl_texture_image *img = NULL;
   GLint maxLevels;
   gl_format texFormat;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   /* this will catch bad target values */
   maxLevels = _mesa_max_texture_levels(ctx, target);
   if (maxLevels == 0) {
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "glGetTexLevelParameter[if]v(target=0x%x)", target);
      return;
   }

   if (level < 0 || level >= maxLevels) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexLevelParameter[if]v" );
      return;
   }

   texObj = _mesa_select_tex_object(ctx, target);

   img = _mesa_select_tex_image(ctx, texObj, target, level);
   if (!img || img->TexFormat == MESA_FORMAT_NONE) {
      /* undefined texture image */
      if (pname == GL_TEXTURE_COMPONENTS)
         *params = 1;
      else
         *params = 0;
      return;
   }

   texFormat = img->TexFormat;

   switch (pname) {
      case GL_TEXTURE_WIDTH:
         *params = img->Width;
         break;
      case GL_TEXTURE_HEIGHT:
         *params = img->Height;
         break;
      case GL_TEXTURE_DEPTH:
         *params = img->Depth;
         break;
      case GL_TEXTURE_INTERNAL_FORMAT:
         *params = img->InternalFormat;
         break;
      case GL_TEXTURE_BORDER:
         *params = img->Border;
         break;
      case GL_TEXTURE_RED_SIZE:
      case GL_TEXTURE_GREEN_SIZE:
      case GL_TEXTURE_BLUE_SIZE:
      case GL_TEXTURE_ALPHA_SIZE:
         if (_mesa_base_format_has_channel(img->_BaseFormat, pname))
            *params = _mesa_get_format_bits(texFormat, pname);
         else
            *params = 0;
         break;
      case GL_TEXTURE_INTENSITY_SIZE:
      case GL_TEXTURE_LUMINANCE_SIZE:
         if (_mesa_base_format_has_channel(img->_BaseFormat, pname)) {
            *params = _mesa_get_format_bits(texFormat, pname);
            if (*params == 0) {
               /* intensity or luminance is probably stored as RGB[A] */
               *params = MIN2(_mesa_get_format_bits(texFormat,
                                                    GL_TEXTURE_RED_SIZE),
                              _mesa_get_format_bits(texFormat,
                                                    GL_TEXTURE_GREEN_SIZE));
            }
         }
         else {
            *params = 0;
         }
         break;

      /* GL_ARB_texture_float */
      case GL_TEXTURE_RED_TYPE_ARB:
      case GL_TEXTURE_GREEN_TYPE_ARB:
      case GL_TEXTURE_BLUE_TYPE_ARB:
      case GL_TEXTURE_ALPHA_TYPE_ARB:
      case GL_TEXTURE_LUMINANCE_TYPE_ARB:
      case GL_TEXTURE_INTENSITY_TYPE_ARB:
      case GL_TEXTURE_DEPTH_TYPE_ARB:
         if (!ctx->Extensions.ARB_texture_float)
            goto invalid_pname;
	 if (_mesa_base_format_has_channel(img->_BaseFormat, pname))
	    *params = _mesa_get_format_datatype(texFormat);
	 else
	    *params = GL_NONE;
         break;

      default:
         goto invalid_pname;
   }

   /* no error if we get here */
   return;

invalid_pname:
   _mesa_error(ctx, GL_INVALID_ENUM,
               "glGetTexLevelParameter[if]v(pname=%s)",
               _mesa_lookup_enum_by_nr(pname));
}
Example #27
0
static void
prepare_blend_state(struct brw_context *brw)
{
   struct gl_context *ctx = &brw->intel.ctx;
   struct gen6_blend_state *blend;
   int b;
   int nr_draw_buffers = ctx->DrawBuffer->_NumColorDrawBuffers;
   int size;

   /* We need at least one BLEND_STATE written, because we might do
    * thread dispatch even if _NumColorDrawBuffers is 0 (for example
    * for computed depth or alpha test), which will do an FB write
    * with render target 0, which will reference BLEND_STATE[0] for
    * alpha test enable.
    */
   if (nr_draw_buffers == 0 && ctx->Color.AlphaEnabled)
      nr_draw_buffers = 1;

   size = sizeof(*blend) * nr_draw_buffers;
   blend = brw_state_batch(brw, AUB_TRACE_BLEND_STATE,
			   size, 64, &brw->cc.blend_state_offset);

   memset(blend, 0, size);

   for (b = 0; b < nr_draw_buffers; b++) {
      /* _NEW_COLOR */
      if (ctx->Color._LogicOpEnabled) {
	 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[b];
	 /* _NEW_BUFFERS */
	 /* Floating point RTs should have no effect from LogicOp,
	  * except for disabling of blending
	  */
	 if (_mesa_get_format_datatype(rb->Format) != GL_FLOAT) {
	    blend[b].blend1.logic_op_enable = 1;
	    blend[b].blend1.logic_op_func =
	       intel_translate_logic_op(ctx->Color.LogicOp);
	 }
      } else if (ctx->Color.BlendEnabled & (1 << b)) {
	 GLenum eqRGB = ctx->Color.Blend[0].EquationRGB;
	 GLenum eqA = ctx->Color.Blend[0].EquationA;
	 GLenum srcRGB = ctx->Color.Blend[0].SrcRGB;
	 GLenum dstRGB = ctx->Color.Blend[0].DstRGB;
	 GLenum srcA = ctx->Color.Blend[0].SrcA;
	 GLenum dstA = ctx->Color.Blend[0].DstA;

	 if (eqRGB == GL_MIN || eqRGB == GL_MAX) {
	    srcRGB = dstRGB = GL_ONE;
	 }

	 if (eqA == GL_MIN || eqA == GL_MAX) {
	    srcA = dstA = GL_ONE;
	 }

	 blend[b].blend0.dest_blend_factor = brw_translate_blend_factor(dstRGB);
	 blend[b].blend0.source_blend_factor = brw_translate_blend_factor(srcRGB);
	 blend[b].blend0.blend_func = brw_translate_blend_equation(eqRGB);

	 blend[b].blend0.ia_dest_blend_factor = brw_translate_blend_factor(dstA);
	 blend[b].blend0.ia_source_blend_factor = brw_translate_blend_factor(srcA);
	 blend[b].blend0.ia_blend_func = brw_translate_blend_equation(eqA);

	 blend[b].blend0.blend_enable = 1;
	 blend[b].blend0.ia_blend_enable = (srcA != srcRGB ||
					 dstA != dstRGB ||
					 eqA != eqRGB);
      }


      /* _NEW_COLOR */
      if (ctx->Color.AlphaEnabled) {
	 blend[b].blend1.alpha_test_enable = 1;
	 blend[b].blend1.alpha_test_func =
	    intel_translate_compare_func(ctx->Color.AlphaFunc);

      }

      /* _NEW_COLOR */
      if (ctx->Color.DitherFlag) {
	 blend[b].blend1.dither_enable = 1;
	 blend[b].blend1.y_dither_offset = 0;
	 blend[b].blend1.x_dither_offset = 0;
      }

      blend[b].blend1.write_disable_r = !ctx->Color.ColorMask[b][0];
      blend[b].blend1.write_disable_g = !ctx->Color.ColorMask[b][1];
      blend[b].blend1.write_disable_b = !ctx->Color.ColorMask[b][2];
      blend[b].blend1.write_disable_a = !ctx->Color.ColorMask[b][3];
   }

   brw->state.dirty.cache |= CACHE_NEW_BLEND_STATE;
}
Example #28
0
/**
 * The glGet queries of the framebuffer red/green/blue size, stencil size,
 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual.  These can
 * change depending on the renderbuffer bindings.  This function updates
 * the given framebuffer's Visual from the current renderbuffer bindings.
 *
 * This may apply to user-created framebuffers or window system framebuffers.
 *
 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
 * The former one is used to convert floating point depth values into
 * integer Z values.
 */
void
_mesa_update_framebuffer_visual(struct gl_context *ctx,
				struct gl_framebuffer *fb)
{
   GLuint i;

   memset(&fb->Visual, 0, sizeof(fb->Visual));
   fb->Visual.rgbMode = GL_TRUE; /* assume this */

#if 0 /* this _might_ be needed */
   if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
      /* leave visual fields zero'd */
      return;
   }
#endif

   /* find first RGB renderbuffer */
   for (i = 0; i < BUFFER_COUNT; i++) {
      if (fb->Attachment[i].Renderbuffer) {
         const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
         const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
         const gl_format fmt = rb->Format;

         if (_mesa_is_legal_color_format(ctx, baseFormat)) {
            fb->Visual.redBits = _mesa_get_format_bits(fmt, GL_RED_BITS);
            fb->Visual.greenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS);
            fb->Visual.blueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS);
            fb->Visual.alphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS);
            fb->Visual.rgbBits = fb->Visual.redBits
               + fb->Visual.greenBits + fb->Visual.blueBits;
            fb->Visual.samples = rb->NumSamples;
            fb->Visual.sampleBuffers = rb->NumSamples > 0 ? 1 : 0;
            if (_mesa_get_format_color_encoding(fmt) == GL_SRGB)
                fb->Visual.sRGBCapable = ctx->Const.sRGBCapable;
            break;
         }
      }
   }

   fb->Visual.floatMode = GL_FALSE;
   for (i = 0; i < BUFFER_COUNT; i++) {
      if (fb->Attachment[i].Renderbuffer) {
         const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
         const gl_format fmt = rb->Format;

         if (_mesa_get_format_datatype(fmt) == GL_FLOAT) {
            fb->Visual.floatMode = GL_TRUE;
            break;
         }
      }
   }

   if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
      const struct gl_renderbuffer *rb =
         fb->Attachment[BUFFER_DEPTH].Renderbuffer;
      const gl_format fmt = rb->Format;
      fb->Visual.haveDepthBuffer = GL_TRUE;
      fb->Visual.depthBits = _mesa_get_format_bits(fmt, GL_DEPTH_BITS);
   }

   if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
      const struct gl_renderbuffer *rb =
         fb->Attachment[BUFFER_STENCIL].Renderbuffer;
      const gl_format fmt = rb->Format;
      fb->Visual.haveStencilBuffer = GL_TRUE;
      fb->Visual.stencilBits = _mesa_get_format_bits(fmt, GL_STENCIL_BITS);
   }

   if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
      const struct gl_renderbuffer *rb =
         fb->Attachment[BUFFER_ACCUM].Renderbuffer;
      const gl_format fmt = rb->Format;
      fb->Visual.haveAccumBuffer = GL_TRUE;
      fb->Visual.accumRedBits = _mesa_get_format_bits(fmt, GL_RED_BITS);
      fb->Visual.accumGreenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS);
      fb->Visual.accumBlueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS);
      fb->Visual.accumAlphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS);
   }

   compute_depth_max(fb);
}
Example #29
0
/**
 * Examine a texture object to determine if it is complete.
 *
 * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE
 * accordingly.
 *
 * \param ctx GL context.
 * \param t texture object.
 *
 * According to the texture target, verifies that each of the mipmaps is
 * present and has the expected size.
 */
void
_mesa_test_texobj_completeness( const struct gl_context *ctx,
                                struct gl_texture_object *t )
{
   const GLint baseLevel = t->BaseLevel;
   const struct gl_texture_image *baseImage;
   GLint maxLog2 = 0, maxLevels = 0;

   /* We'll set these to FALSE if tests fail below */
   t->_BaseComplete = GL_TRUE;
   t->_MipmapComplete = GL_TRUE;

   if (t->Target == GL_TEXTURE_BUFFER) {
      /* Buffer textures are always considered complete.  The obvious case where
       * they would be incomplete (no BO attached) is actually specced to be
       * undefined rendering results.
       */
      return;
   }

   /* Detect cases where the application set the base level to an invalid
    * value.
    */
   if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) {
      incomplete(t, BASE, "base level = %d is invalid", baseLevel);
      return;
   }

   if (t->MaxLevel < baseLevel) {
      incomplete(t, BASE, "MAX_LEVEL (%d) < BASE_LEVEL (%d)",
		 t->MaxLevel, baseLevel);
      return;
   }

   baseImage = t->Image[0][baseLevel];

   /* Always need the base level image */
   if (!baseImage) {
      incomplete(t, BASE, "Image[baseLevel=%d] == NULL", baseLevel);
      return;
   }

   /* Check width/height/depth for zero */
   if (baseImage->Width == 0 ||
       baseImage->Height == 0 ||
       baseImage->Depth == 0) {
      incomplete(t, BASE, "texture width or height or depth = 0");
      return;
   }

   /* Check if the texture values are integer */
   {
      GLenum datatype = _mesa_get_format_datatype(baseImage->TexFormat);
      t->_IsIntegerFormat = datatype == GL_INT || datatype == GL_UNSIGNED_INT;
   }

   /* Compute _MaxLevel (the maximum mipmap level we'll sample from given the
    * mipmap image sizes and GL_TEXTURE_MAX_LEVEL state).
    */
   switch (t->Target) {
   case GL_TEXTURE_1D:
   case GL_TEXTURE_1D_ARRAY_EXT:
      maxLog2 = baseImage->WidthLog2;
      maxLevels = ctx->Const.MaxTextureLevels;
      break;
   case GL_TEXTURE_2D:
   case GL_TEXTURE_2D_ARRAY_EXT:
      maxLog2 = MAX2(baseImage->WidthLog2,
                     baseImage->HeightLog2);
      maxLevels = ctx->Const.MaxTextureLevels;
      break;
   case GL_TEXTURE_3D:
      maxLog2 = MAX3(baseImage->WidthLog2,
                     baseImage->HeightLog2,
                     baseImage->DepthLog2);
      maxLevels = ctx->Const.Max3DTextureLevels;
      break;
   case GL_TEXTURE_CUBE_MAP_ARB:
      maxLog2 = MAX2(baseImage->WidthLog2,
                     baseImage->HeightLog2);
      maxLevels = ctx->Const.MaxCubeTextureLevels;
      break;
   case GL_TEXTURE_RECTANGLE_NV:
   case GL_TEXTURE_BUFFER:
   case GL_TEXTURE_EXTERNAL_OES:
      maxLog2 = 0;  /* not applicable */
      maxLevels = 1;  /* no mipmapping */
      break;
   default:
      _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness");
      return;
   }

   ASSERT(maxLevels > 0);

   t->_MaxLevel = baseLevel + maxLog2;  /* 'p' in the GL spec */
   t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel);
   t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1); /* 'q' in the GL spec */

   /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
   t->_MaxLambda = (GLfloat) (t->_MaxLevel - baseLevel);

   if (t->Immutable) {
      /* This texture object was created with glTexStorage1/2/3D() so we
       * know that all the mipmap levels are the right size and all cube
       * map faces are the same size.
       * We don't need to do any of the additional checks below.
       */
      return;
   }

   if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
      /* Make sure that all six cube map level 0 images are the same size.
       * Note:  we know that the image's width==height (we enforce that
       * at glTexImage time) so we only need to test the width here.
       */
      GLuint face;
      assert(baseImage->Width2 == baseImage->Height);
      for (face = 1; face < 6; face++) {
         assert(t->Image[face][baseLevel] == NULL ||
                t->Image[face][baseLevel]->Width2 ==
                t->Image[face][baseLevel]->Height2);
         if (t->Image[face][baseLevel] == NULL ||
             t->Image[face][baseLevel]->Width2 != baseImage->Width2) {
            incomplete(t, BASE, "Cube face missing or mismatched size");
            return;
         }
      }
   }

   /*
    * Do mipmap consistency checking.
    * Note: we don't care about the current texture sampler state here.
    * To determine texture completeness we'll either look at _BaseComplete
    * or _MipmapComplete depending on the current minification filter mode.
    */
   {
      GLint i;
      const GLint minLevel = baseLevel;
      const GLint maxLevel = t->_MaxLevel;
      const GLuint numFaces = _mesa_num_tex_faces(t->Target);
      GLuint width, height, depth, face;

      if (minLevel > maxLevel) {
         incomplete(t, BASE, "minLevel > maxLevel");
         return;
      }

      /* Get the base image's dimensions */
      width = baseImage->Width2;
      height = baseImage->Height2;
      depth = baseImage->Depth2;

      /* Note: this loop will be a no-op for RECT, BUFFER, EXTERNAL textures */
      for (i = baseLevel + 1; i < maxLevels; i++) {
         /* Compute the expected size of image at level[i] */
         if (width > 1) {
            width /= 2;
         }
         if (height > 1 && t->Target != GL_TEXTURE_1D_ARRAY) {
            height /= 2;
         }
         if (depth > 1 && t->Target != GL_TEXTURE_2D_ARRAY) {
            depth /= 2;
         }

         /* loop over cube faces (or single face otherwise) */
         for (face = 0; face < numFaces; face++) {
            if (i >= minLevel && i <= maxLevel) {
               const struct gl_texture_image *img = t->Image[face][i];

               if (!img) {
                  incomplete(t, MIPMAP, "TexImage[%d] is missing", i);
                  return;
               }
               if (img->TexFormat != baseImage->TexFormat) {
                  incomplete(t, MIPMAP, "Format[i] != Format[baseLevel]");
                  return;
               }
               if (img->Border != baseImage->Border) {
                  incomplete(t, MIPMAP, "Border[i] != Border[baseLevel]");
                  return;
               }
               if (img->Width2 != width) {
                  incomplete(t, MIPMAP, "TexImage[%d] bad width %u", i, img->Width2);
                  return;
               }
               if (img->Height2 != height) {
                  incomplete(t, MIPMAP, "TexImage[%d] bad height %u", i, img->Height2);
                  return;
               }
               if (img->Depth2 != depth) {
                  incomplete(t, MIPMAP, "TexImage[%d] bad depth %u", i, img->Depth2);
                  return;
               }

               /* Extra checks for cube textures */
               if (face > 0) {
                  /* check that cube faces are the same size */
                  if (img->Width2 != t->Image[0][i]->Width2 || 
                      img->Height2 != t->Image[0][i]->Height2) {
		     incomplete(t, MIPMAP, "CubeMap Image[n][i] bad size");
		     return;
		  }
               }
            }
         }
         
         if (width == 1 && height == 1 && depth == 1) {
            return;  /* found smallest needed mipmap, all done! */
         }
      }
   }
}
Example #30
0
void GLAPIENTRY
_mesa_GetTexLevelParameteriv( GLenum target, GLint level,
                              GLenum pname, GLint *params )
{
   const struct gl_texture_unit *texUnit;
   struct gl_texture_object *texObj;
   const struct gl_texture_image *img = NULL;
   GLint maxLevels;
   gl_format texFormat;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glGetTexLevelParameteriv(current unit)");
      return;
   }

   texUnit = _mesa_get_current_tex_unit(ctx);

   /* this will catch bad target values */
   maxLevels = _mesa_max_texture_levels(ctx, target);
   if (maxLevels == 0) {
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "glGetTexLevelParameter[if]v(target=0x%x)", target);
      return;
   }

   if (level < 0 || level >= maxLevels) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexLevelParameter[if]v" );
      return;
   }

   texObj = _mesa_select_tex_object(ctx, texUnit, target);

   img = _mesa_select_tex_image(ctx, texObj, target, level);
   if (!img || !img->TexFormat) {
      /* undefined texture image */
      if (pname == GL_TEXTURE_COMPONENTS)
         *params = 1;
      else
         *params = 0;
      return;
   }

   texFormat = img->TexFormat;

   switch (pname) {
      case GL_TEXTURE_WIDTH:
         *params = img->Width;
         break;
      case GL_TEXTURE_HEIGHT:
         *params = img->Height;
         break;
      case GL_TEXTURE_DEPTH:
         *params = img->Depth;
         break;
      case GL_TEXTURE_INTERNAL_FORMAT:
         if (_mesa_is_format_compressed(texFormat)) {
            /* need to return the actual compressed format */
            *params = _mesa_compressed_format_to_glenum(ctx, texFormat);
         }
         else {
	    /* If the true internal format is not compressed but the user
	     * requested a generic compressed format, we have to return the
	     * generic base format that matches.
	     *
	     * From page 119 (page 129 of the PDF) of the OpenGL 1.3 spec:
	     *
	     *     "If no specific compressed format is available,
	     *     internalformat is instead replaced by the corresponding base
	     *     internal format."
	     *
	     * Otherwise just return the user's requested internal format
	     */
	    const GLenum f =
	       _mesa_gl_compressed_format_base_format(img->InternalFormat);

	    *params = (f != 0) ? f : img->InternalFormat;
	 }
         break;
      case GL_TEXTURE_BORDER:
         *params = img->Border;
         break;
      case GL_TEXTURE_RED_SIZE:
         if (img->_BaseFormat == GL_RED) {
            *params = _mesa_get_format_bits(texFormat, pname);
	    break;
	 }
	 /* FALLTHROUGH */
      case GL_TEXTURE_GREEN_SIZE:
         if (img->_BaseFormat == GL_RG) {
            *params = _mesa_get_format_bits(texFormat, pname);
	    break;
	 }
	 /* FALLTHROUGH */
      case GL_TEXTURE_BLUE_SIZE:
         if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA)
            *params = _mesa_get_format_bits(texFormat, pname);
         else
            *params = 0;
         break;
      case GL_TEXTURE_ALPHA_SIZE:
         if (img->_BaseFormat == GL_ALPHA ||
             img->_BaseFormat == GL_LUMINANCE_ALPHA ||
             img->_BaseFormat == GL_RGBA)
            *params = _mesa_get_format_bits(texFormat, pname);
         else
            *params = 0;
         break;
      case GL_TEXTURE_INTENSITY_SIZE:
         if (img->_BaseFormat != GL_INTENSITY)
            *params = 0;
         else {
            *params = _mesa_get_format_bits(texFormat, pname);
            if (*params == 0) {
               /* intensity probably stored as rgb texture */
               *params = MIN2(_mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE),
                              _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE));
            }
         }
         break;
      case GL_TEXTURE_LUMINANCE_SIZE:
         if (img->_BaseFormat != GL_LUMINANCE &&
             img->_BaseFormat != GL_LUMINANCE_ALPHA)
            *params = 0;
         else {
            *params = _mesa_get_format_bits(texFormat, pname);
            if (*params == 0) {
               /* luminance probably stored as rgb texture */
               *params = MIN2(_mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE),
                              _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE));
            }
         }
         break;
      case GL_TEXTURE_INDEX_SIZE_EXT:
         if (img->_BaseFormat == GL_COLOR_INDEX)
            *params = _mesa_get_format_bits(texFormat, pname);
         else
            *params = 0;
         break;
      case GL_TEXTURE_DEPTH_SIZE_ARB:
         if (ctx->Extensions.ARB_depth_texture)
            *params = _mesa_get_format_bits(texFormat, pname);
         else
            goto invalid_pname;
         break;
      case GL_TEXTURE_STENCIL_SIZE_EXT:
         if (ctx->Extensions.EXT_packed_depth_stencil ||
             ctx->Extensions.ARB_framebuffer_object) {
            *params = _mesa_get_format_bits(texFormat, pname);
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_SHARED_SIZE:
         if (ctx->VersionMajor >= 3 ||
             ctx->Extensions.EXT_texture_shared_exponent) {
            *params = texFormat == MESA_FORMAT_RGB9_E5_FLOAT ? 5 : 0;
         }
         else {
            goto invalid_pname;
         }
         break;

      /* GL_ARB_texture_compression */
      case GL_TEXTURE_COMPRESSED_IMAGE_SIZE:
	 if (_mesa_is_format_compressed(texFormat) &&
             !_mesa_is_proxy_texture(target)) {
            *params = _mesa_format_image_size(texFormat, img->Width,
                                              img->Height, img->Depth);
	 }
	 else {
	    _mesa_error(ctx, GL_INVALID_OPERATION,
			"glGetTexLevelParameter[if]v(pname)");
	 }
         break;
      case GL_TEXTURE_COMPRESSED:
         *params = (GLint) _mesa_is_format_compressed(texFormat);
         break;

      /* GL_ARB_texture_float */
      case GL_TEXTURE_RED_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_GREEN_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_BLUE_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_BLUE_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_ALPHA_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_ALPHA_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_LUMINANCE_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_LUMINANCE_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_INTENSITY_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_INTENSITY_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_DEPTH_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_DEPTH_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;

      default:
         goto invalid_pname;
   }

   /* no error if we get here */
   return;

invalid_pname:
   _mesa_error(ctx, GL_INVALID_ENUM,
               "glGetTexLevelParameter[if]v(pname=%s)",
               _mesa_lookup_enum_by_nr(pname));
}