Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * OTHER DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25. /**
  26.  * Meta operations.  Some GL operations can be expressed in terms of
  27.  * other GL operations.  For example, glBlitFramebuffer() can be done
  28.  * with texture mapping and glClear() can be done with polygon rendering.
  29.  *
  30.  * \author Brian Paul
  31.  */
  32.  
  33. #include "main/arrayobj.h"
  34. #include "main/buffers.h"
  35. #include "main/enums.h"
  36. #include "main/enable.h"
  37. #include "main/fbobject.h"
  38. #include "main/macros.h"
  39. #include "main/mipmap.h"
  40. #include "main/teximage.h"
  41. #include "main/texobj.h"
  42. #include "main/texparam.h"
  43. #include "main/varray.h"
  44. #include "main/viewport.h"
  45. #include "drivers/common/meta.h"
  46. #include "program/prog_instruction.h"
  47.  
  48.  
  49. /**
  50.  * Check if the call to _mesa_meta_GenerateMipmap() will require a
  51.  * software fallback.  The fallback path will require that the texture
  52.  * images are mapped.
  53.  * \return GL_TRUE if a fallback is needed, GL_FALSE otherwise
  54.  */
  55. static bool
  56. fallback_required(struct gl_context *ctx, GLenum target,
  57.                   struct gl_texture_object *texObj)
  58. {
  59.    const GLuint fboSave = ctx->DrawBuffer->Name;
  60.    struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap;
  61.    struct gl_texture_image *baseImage;
  62.    GLuint srcLevel;
  63.    GLenum status;
  64.  
  65.    /* check for fallbacks */
  66.    if (target == GL_TEXTURE_3D) {
  67.       _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
  68.                        "glGenerateMipmap() to %s target\n",
  69.                        _mesa_lookup_enum_by_nr(target));
  70.       return true;
  71.    }
  72.  
  73.    srcLevel = texObj->BaseLevel;
  74.    baseImage = _mesa_select_tex_image(texObj, target, srcLevel);
  75.    if (!baseImage) {
  76.       _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
  77.                        "glGenerateMipmap() couldn't find base teximage\n");
  78.       return true;
  79.    }
  80.  
  81.    if (_mesa_is_format_compressed(baseImage->TexFormat)) {
  82.       _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
  83.                        "glGenerateMipmap() with %s format\n",
  84.                        _mesa_get_format_name(baseImage->TexFormat));
  85.       return true;
  86.    }
  87.  
  88.    if (_mesa_get_format_color_encoding(baseImage->TexFormat) == GL_SRGB &&
  89.        !ctx->Extensions.EXT_texture_sRGB_decode) {
  90.       /* The texture format is sRGB but we can't turn off sRGB->linear
  91.        * texture sample conversion.  So we won't be able to generate the
  92.        * right colors when rendering.  Need to use a fallback.
  93.        */
  94.       _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
  95.                        "glGenerateMipmap() of sRGB texture without "
  96.                        "sRGB decode\n");
  97.       return true;
  98.    }
  99.  
  100.    /*
  101.     * Test that we can actually render in the texture's format.
  102.     */
  103.    if (!mipmap->FBO)
  104.       _mesa_GenFramebuffers(1, &mipmap->FBO);
  105.    _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO);
  106.  
  107.    _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, baseImage, 0);
  108.  
  109.    status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
  110.  
  111.    _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboSave);
  112.  
  113.    if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
  114.       _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
  115.                        "glGenerateMipmap() got incomplete FBO\n");
  116.       return true;
  117.    }
  118.  
  119.    return false;
  120. }
  121.  
  122. void
  123. _mesa_meta_glsl_generate_mipmap_cleanup(struct gen_mipmap_state *mipmap)
  124. {
  125.    if (mipmap->VAO == 0)
  126.       return;
  127.    _mesa_DeleteVertexArrays(1, &mipmap->VAO);
  128.    mipmap->VAO = 0;
  129.    _mesa_DeleteBuffers(1, &mipmap->VBO);
  130.    mipmap->VBO = 0;
  131.  
  132.    _mesa_meta_blit_shader_table_cleanup(&mipmap->shaders);
  133. }
  134.  
  135. static GLboolean
  136. prepare_mipmap_level(struct gl_context *ctx,
  137.                      struct gl_texture_object *texObj, GLuint level,
  138.                      GLsizei width, GLsizei height, GLsizei depth,
  139.                      GLenum intFormat, mesa_format format)
  140. {
  141.    if (texObj->Target == GL_TEXTURE_1D_ARRAY) {
  142.       /* Work around Mesa expecting the number of array slices in "height". */
  143.       height = depth;
  144.       depth = 1;
  145.    }
  146.  
  147.    return _mesa_prepare_mipmap_level(ctx, texObj, level, width, height, depth,
  148.                                      0, intFormat, format);
  149. }
  150.  
  151. /**
  152.  * Called via ctx->Driver.GenerateMipmap()
  153.  * Note: We don't yet support 3D textures, 1D/2D array textures or texture
  154.  * borders.
  155.  */
  156. void
  157. _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
  158.                           struct gl_texture_object *texObj)
  159. {
  160.    struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap;
  161.    struct vertex verts[4];
  162.    const GLuint baseLevel = texObj->BaseLevel;
  163.    const GLuint maxLevel = texObj->MaxLevel;
  164.    const GLint maxLevelSave = texObj->MaxLevel;
  165.    const GLboolean genMipmapSave = texObj->GenerateMipmap;
  166.    const GLuint currentTexUnitSave = ctx->Texture.CurrentUnit;
  167.    const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
  168.                                       ctx->Extensions.ARB_fragment_shader;
  169.    GLenum faceTarget;
  170.    GLuint dstLevel;
  171.    GLuint samplerSave;
  172.    GLint swizzle[4];
  173.    GLboolean swizzleSaved = GL_FALSE;
  174.  
  175.    if (fallback_required(ctx, target, texObj)) {
  176.       _mesa_generate_mipmap(ctx, target, texObj);
  177.       return;
  178.    }
  179.  
  180.    if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
  181.        target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) {
  182.       faceTarget = target;
  183.       target = GL_TEXTURE_CUBE_MAP;
  184.    } else {
  185.       faceTarget = target;
  186.    }
  187.  
  188.    _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS);
  189.  
  190.    /* Choose between glsl version and fixed function version of
  191.     * GenerateMipmap function.
  192.     */
  193.    if (use_glsl_version) {
  194.       _mesa_meta_setup_vertex_objects(&mipmap->VAO, &mipmap->VBO, true,
  195.                                       2, 4, 0);
  196.       _mesa_meta_setup_blit_shader(ctx, target, false, &mipmap->shaders);
  197.    } else {
  198.       _mesa_meta_setup_ff_tnl_for_blit(&mipmap->VAO, &mipmap->VBO, 3);
  199.       _mesa_set_enable(ctx, target, GL_TRUE);
  200.    }
  201.  
  202.    samplerSave = ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ?
  203.       ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0;
  204.  
  205.    if (currentTexUnitSave != 0)
  206.       _mesa_BindTexture(target, texObj->Name);
  207.  
  208.    if (!mipmap->Sampler) {
  209.       _mesa_GenSamplers(1, &mipmap->Sampler);
  210.       _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler);
  211.  
  212.       _mesa_SamplerParameteri(mipmap->Sampler,
  213.                               GL_TEXTURE_MIN_FILTER,
  214.                               GL_LINEAR_MIPMAP_LINEAR);
  215.       _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  216.       _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  217.       _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  218.       _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
  219.  
  220.       /* We don't want to encode or decode sRGB values; treat them as linear.
  221.        * This is not technically correct for GLES3 but we don't get any API
  222.        * error at the moment.
  223.        */
  224.       if (ctx->Extensions.EXT_texture_sRGB_decode) {
  225.          _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_SRGB_DECODE_EXT,
  226.                GL_SKIP_DECODE_EXT);
  227.       }
  228.    } else {
  229.       _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler);
  230.    }
  231.  
  232.    assert(mipmap->FBO != 0);
  233.    _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO);
  234.  
  235.    _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE);
  236.  
  237.    if (texObj->_Swizzle != SWIZZLE_NOOP) {
  238.       static const GLint swizzleNoop[4] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
  239.       memcpy(swizzle, texObj->Swizzle, sizeof(swizzle));
  240.       swizzleSaved = GL_TRUE;
  241.       _mesa_TexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzleNoop);
  242.    }
  243.  
  244.    /* Silence valgrind warnings about reading uninitialized stack. */
  245.    memset(verts, 0, sizeof(verts));
  246.  
  247.    /* setup vertex positions */
  248.    verts[0].x = -1.0F;
  249.    verts[0].y = -1.0F;
  250.    verts[1].x =  1.0F;
  251.    verts[1].y = -1.0F;
  252.    verts[2].x =  1.0F;
  253.    verts[2].y =  1.0F;
  254.    verts[3].x = -1.0F;
  255.    verts[3].y =  1.0F;
  256.  
  257.    /* texture is already locked, unlock now */
  258.    _mesa_unlock_texture(ctx, texObj);
  259.  
  260.    for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) {
  261.       const struct gl_texture_image *srcImage;
  262.       struct gl_texture_image *dstImage;
  263.       const GLuint srcLevel = dstLevel - 1;
  264.       GLuint layer;
  265.       GLsizei srcWidth, srcHeight, srcDepth;
  266.       GLsizei dstWidth, dstHeight, dstDepth;
  267.  
  268.       srcImage = _mesa_select_tex_image(texObj, faceTarget, srcLevel);
  269.       assert(srcImage->Border == 0);
  270.  
  271.       /* src size */
  272.       srcWidth = srcImage->Width;
  273.       if (target == GL_TEXTURE_1D_ARRAY) {
  274.          srcHeight = 1;
  275.          srcDepth = srcImage->Height;
  276.       } else {
  277.          srcHeight = srcImage->Height;
  278.          srcDepth = srcImage->Depth;
  279.       }
  280.  
  281.       /* new dst size */
  282.       dstWidth = minify(srcWidth, 1);
  283.       dstHeight = minify(srcHeight, 1);
  284.       dstDepth = target == GL_TEXTURE_3D ? minify(srcDepth, 1) : srcDepth;
  285.  
  286.       if (dstWidth == srcWidth &&
  287.           dstHeight == srcHeight &&
  288.           dstDepth == srcDepth) {
  289.          /* all done */
  290.          break;
  291.       }
  292.  
  293.       /* Allocate storage for the destination mipmap image(s) */
  294.  
  295.       /* Set MaxLevel large enough to hold the new level when we allocate it */
  296.       _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, dstLevel);
  297.  
  298.       if (!prepare_mipmap_level(ctx, texObj, dstLevel,
  299.                                 dstWidth, dstHeight, dstDepth,
  300.                                 srcImage->InternalFormat,
  301.                                 srcImage->TexFormat)) {
  302.          /* All done.  We either ran out of memory or we would go beyond the
  303.           * last valid level of an immutable texture if we continued.
  304.           */
  305.          break;
  306.       }
  307.       dstImage = _mesa_select_tex_image(texObj, faceTarget, dstLevel);
  308.  
  309.       /* limit minification to src level */
  310.       _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel);
  311.  
  312.       /* setup viewport */
  313.       _mesa_set_viewport(ctx, 0, 0, 0, dstWidth, dstHeight);
  314.       _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
  315.  
  316.       for (layer = 0; layer < dstDepth; ++layer) {
  317.          /* Setup texture coordinates */
  318.          _mesa_meta_setup_texture_coords(faceTarget,
  319.                                          layer,
  320.                                          0, 0, 1, /* width, height never used here */
  321.                                          verts[0].tex,
  322.                                          verts[1].tex,
  323.                                          verts[2].tex,
  324.                                          verts[3].tex);
  325.  
  326.          /* upload vertex data */
  327.          _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
  328.                           verts, GL_DYNAMIC_DRAW_ARB);
  329.  
  330.          _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstImage, layer);
  331.  
  332.          /* sanity check */
  333.          if (_mesa_CheckFramebufferStatus(GL_FRAMEBUFFER) !=
  334.              GL_FRAMEBUFFER_COMPLETE) {
  335.             _mesa_problem(ctx, "Unexpected incomplete framebuffer in "
  336.                           "_mesa_meta_GenerateMipmap()");
  337.             break;
  338.          }
  339.  
  340.          assert(dstWidth == ctx->DrawBuffer->Width);
  341.          if (target == GL_TEXTURE_1D_ARRAY) {
  342.             assert(dstHeight == 1);
  343.          } else {
  344.             assert(dstHeight == ctx->DrawBuffer->Height);
  345.          }
  346.  
  347.          _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
  348.       }
  349.    }
  350.  
  351.    _mesa_lock_texture(ctx, texObj); /* relock */
  352.  
  353.    _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave);
  354.  
  355.    _mesa_meta_end(ctx);
  356.  
  357.    _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave);
  358.    if (genMipmapSave)
  359.       _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave);
  360.    if (swizzleSaved)
  361.       _mesa_TexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
  362. }
  363.