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. #include "main/glheader.h"
  26. #include "main/mtypes.h"
  27. #include "main/imports.h"
  28. #include "main/arbprogram.h"
  29. #include "main/arrayobj.h"
  30. #include "main/blend.h"
  31. #include "main/condrender.h"
  32. #include "main/depth.h"
  33. #include "main/enable.h"
  34. #include "main/enums.h"
  35. #include "main/fbobject.h"
  36. #include "main/image.h"
  37. #include "main/macros.h"
  38. #include "main/matrix.h"
  39. #include "main/multisample.h"
  40. #include "main/objectlabel.h"
  41. #include "main/readpix.h"
  42. #include "main/scissor.h"
  43. #include "main/shaderapi.h"
  44. #include "main/texobj.h"
  45. #include "main/texenv.h"
  46. #include "main/teximage.h"
  47. #include "main/texparam.h"
  48. #include "main/uniforms.h"
  49. #include "main/varray.h"
  50. #include "main/viewport.h"
  51. #include "swrast/swrast.h"
  52. #include "drivers/common/meta.h"
  53. #include "util/ralloc.h"
  54.  
  55. /** Return offset in bytes of the field within a vertex struct */
  56. #define OFFSET(FIELD) ((void *) offsetof(struct vertex, FIELD))
  57.  
  58. static void
  59. setup_glsl_msaa_blit_scaled_shader(struct gl_context *ctx,
  60.                                    struct blit_state *blit,
  61.                                    struct gl_renderbuffer *src_rb,
  62.                                    GLenum target, GLenum filter)
  63. {
  64.    GLint loc_src_width, loc_src_height;
  65.    int i, samples;
  66.    int shader_offset = 0;
  67.    void *mem_ctx = ralloc_context(NULL);
  68.    char *fs_source;
  69.    char *name, *sample_number;
  70.    const uint8_t *sample_map;
  71.    char *sample_map_str = rzalloc_size(mem_ctx, 1);
  72.    char *sample_map_expr = rzalloc_size(mem_ctx, 1);
  73.    char *texel_fetch_macro = rzalloc_size(mem_ctx, 1);
  74.    const char *vs_source;
  75.    const char *sampler_array_suffix = "";
  76.    const char *texcoord_type = "vec2";
  77.    float y_scale;
  78.    enum blit_msaa_shader shader_index;
  79.  
  80.    assert(src_rb);
  81.    samples = MAX2(src_rb->NumSamples, 1);
  82.    y_scale = samples * 0.5;
  83.  
  84.    /* We expect only power of 2 samples in source multisample buffer. */
  85.    assert(samples > 0 && (samples & (samples - 1)) == 0);
  86.    while (samples >> (shader_offset + 1)) {
  87.       shader_offset++;
  88.    }
  89.    /* Update the assert if we plan to support more than 8X MSAA. */
  90.    assert(shader_offset > 0 && shader_offset < 4);
  91.  
  92.    assert(target == GL_TEXTURE_2D_MULTISAMPLE ||
  93.           target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
  94.  
  95.    shader_index = BLIT_2X_MSAA_SHADER_2D_MULTISAMPLE_SCALED_RESOLVE +
  96.                   shader_offset - 1;
  97.  
  98.    if (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) {
  99.       shader_index += BLIT_2X_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_SCALED_RESOLVE -
  100.                       BLIT_2X_MSAA_SHADER_2D_MULTISAMPLE_SCALED_RESOLVE;
  101.       sampler_array_suffix = "Array";
  102.       texcoord_type = "vec3";
  103.    }
  104.  
  105.    if (blit->msaa_shaders[shader_index]) {
  106.       _mesa_UseProgram(blit->msaa_shaders[shader_index]);
  107.       /* Update the uniform values. */
  108.       loc_src_width =
  109.          _mesa_GetUniformLocation(blit->msaa_shaders[shader_index], "src_width");
  110.       loc_src_height =
  111.          _mesa_GetUniformLocation(blit->msaa_shaders[shader_index], "src_height");
  112.       _mesa_Uniform1f(loc_src_width, src_rb->Width);
  113.       _mesa_Uniform1f(loc_src_height, src_rb->Height);
  114.       return;
  115.    }
  116.  
  117.    name = ralloc_asprintf(mem_ctx, "vec4 MSAA scaled resolve");
  118.  
  119.    /* Below switch is used to setup the shader expression, which computes
  120.     * sample index and map it to to a sample number on hardware.
  121.     */
  122.    switch(samples) {
  123.    case 2:
  124.       sample_number =  "sample_map[int(2 * fract(coord.x))]";
  125.       sample_map = ctx->Const.SampleMap2x;
  126.       break;
  127.    case 4:
  128.       sample_number =  "sample_map[int(2 * fract(coord.x) + 4 * fract(coord.y))]";
  129.       sample_map = ctx->Const.SampleMap4x;
  130.       break;
  131.    case 8:
  132.       sample_number =  "sample_map[int(2 * fract(coord.x) + 8 * fract(coord.y))]";
  133.       sample_map = ctx->Const.SampleMap8x;
  134.       break;
  135.    default:
  136.       sample_number = NULL;
  137.       sample_map = NULL;
  138.       _mesa_problem(ctx, "Unsupported sample count %d\n", samples);
  139.       unreachable("Unsupported sample count");
  140.    }
  141.  
  142.    /* Create sample map string. */
  143.    for (i = 0 ; i < samples - 1; i++) {
  144.       ralloc_asprintf_append(&sample_map_str, "%d, ", sample_map[i]);
  145.    }
  146.    ralloc_asprintf_append(&sample_map_str, "%d", sample_map[samples - 1]);
  147.  
  148.    /* Create sample map expression using above string. */
  149.    ralloc_asprintf_append(&sample_map_expr,
  150.                           "   const int sample_map[%d] = int[%d](%s);\n",
  151.                           samples, samples, sample_map_str);
  152.  
  153.    ralloc_asprintf_append(&texel_fetch_macro,
  154.                           "#define TEXEL_FETCH(coord) texelFetch(texSampler, i%s(coord), %s);\n",
  155.                           texcoord_type, sample_number);
  156.  
  157.    vs_source = ralloc_asprintf(mem_ctx,
  158.                                "#version 130\n"
  159.                                "in vec2 position;\n"
  160.                                "in %s textureCoords;\n"
  161.                                "out %s texCoords;\n"
  162.                                "void main()\n"
  163.                                "{\n"
  164.                                "   texCoords = textureCoords;\n"
  165.                                "   gl_Position = vec4(position, 0.0, 1.0);\n"
  166.                                "}\n",
  167.                                texcoord_type,
  168.                                texcoord_type);
  169.    fs_source = ralloc_asprintf(mem_ctx,
  170.                                "#version 130\n"
  171.                                "#extension GL_ARB_texture_multisample : enable\n"
  172.                                "uniform sampler2DMS%s texSampler;\n"
  173.                                "uniform float src_width, src_height;\n"
  174.                                "in %s texCoords;\n"
  175.                                "out vec4 out_color;\n"
  176.                                "\n"
  177.                                "void main()\n"
  178.                                "{\n"
  179.                                "%s"
  180.                                "   vec2 interp;\n"
  181.                                "   const vec2 scale = vec2(2.0f, %ff);\n"
  182.                                "   const vec2 scale_inv = vec2(0.5f, %ff);\n"
  183.                                "   const vec2 s_0_offset = vec2(0.25f, %ff);\n"
  184.                                "   vec2 s_0_coord, s_1_coord, s_2_coord, s_3_coord;\n"
  185.                                "   vec4 s_0_color, s_1_color, s_2_color, s_3_color;\n"
  186.                                "   vec4 x_0_color, x_1_color;\n"
  187.                                "   vec2 tex_coord = texCoords - s_0_offset;\n"
  188.                                "\n"
  189.                                "   tex_coord *= scale;\n"
  190.                                "   clamp(tex_coord.x, 0.0f, scale.x * src_width - 1.0f);\n"
  191.                                "   clamp(tex_coord.y, 0.0f, scale.y * src_height - 1.0f);\n"
  192.                                "   interp = fract(tex_coord);\n"
  193.                                "   tex_coord = ivec2(tex_coord) * scale_inv;\n"
  194.                                "\n"
  195.                                "   /* Compute the sample coordinates used for filtering. */\n"
  196.                                "   s_0_coord = tex_coord;\n"
  197.                                "   s_1_coord = tex_coord + vec2(scale_inv.x, 0.0f);\n"
  198.                                "   s_2_coord = tex_coord + vec2(0.0f, scale_inv.y);\n"
  199.                                "   s_3_coord = tex_coord + vec2(scale_inv.x, scale_inv.y);\n"
  200.                                "\n"
  201.                                "   /* Fetch sample color values. */\n"
  202.                                "%s"
  203.                                "   s_0_color = TEXEL_FETCH(s_0_coord)\n"
  204.                                "   s_1_color = TEXEL_FETCH(s_1_coord)\n"
  205.                                "   s_2_color = TEXEL_FETCH(s_2_coord)\n"
  206.                                "   s_3_color = TEXEL_FETCH(s_3_coord)\n"
  207.                                "#undef TEXEL_FETCH\n"
  208.                                "\n"
  209.                                "   /* Do bilinear filtering on sample colors. */\n"
  210.                                "   x_0_color =  mix(s_0_color, s_1_color, interp.x);\n"
  211.                                "   x_1_color =  mix(s_2_color, s_3_color, interp.x);\n"
  212.                                "   out_color = mix(x_0_color, x_1_color, interp.y);\n"
  213.                                "}\n",
  214.                                sampler_array_suffix,
  215.                                texcoord_type,
  216.                                sample_map_expr,
  217.                                y_scale,
  218.                                1.0f / y_scale,
  219.                                1.0f / samples,
  220.                                texel_fetch_macro);
  221.  
  222.    _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source, name,
  223.                                        &blit->msaa_shaders[shader_index]);
  224.    loc_src_width =
  225.       _mesa_GetUniformLocation(blit->msaa_shaders[shader_index], "src_width");
  226.    loc_src_height =
  227.       _mesa_GetUniformLocation(blit->msaa_shaders[shader_index], "src_height");
  228.    _mesa_Uniform1f(loc_src_width, src_rb->Width);
  229.    _mesa_Uniform1f(loc_src_height, src_rb->Height);
  230.  
  231.    ralloc_free(mem_ctx);
  232. }
  233.  
  234. static void
  235. setup_glsl_msaa_blit_shader(struct gl_context *ctx,
  236.                             struct blit_state *blit,
  237.                             const struct gl_framebuffer *drawFb,
  238.                             struct gl_renderbuffer *src_rb,
  239.                             GLenum target)
  240. {
  241.    const char *vs_source;
  242.    char *fs_source;
  243.    void *mem_ctx;
  244.    enum blit_msaa_shader shader_index;
  245.    bool dst_is_msaa = false;
  246.    GLenum src_datatype;
  247.    const char *vec4_prefix;
  248.    const char *sampler_array_suffix = "";
  249.    char *name;
  250.    const char *texcoord_type = "vec2";
  251.    int samples;
  252.    int shader_offset = 0;
  253.  
  254.    if (src_rb) {
  255.       samples = MAX2(src_rb->NumSamples, 1);
  256.       src_datatype = _mesa_get_format_datatype(src_rb->Format);
  257.    } else {
  258.       /* depth-or-color glCopyTexImage fallback path that passes a NULL rb and
  259.        * doesn't handle integer.
  260.        */
  261.       samples = 1;
  262.       src_datatype = GL_UNSIGNED_NORMALIZED;
  263.    }
  264.  
  265.    /* We expect only power of 2 samples in source multisample buffer. */
  266.    assert(samples > 0 && (samples & (samples - 1)) == 0);
  267.    while (samples >> (shader_offset + 1)) {
  268.       shader_offset++;
  269.    }
  270.    /* Update the assert if we plan to support more than 16X MSAA. */
  271.    assert(shader_offset >= 0 && shader_offset <= 4);
  272.  
  273.    if (drawFb->Visual.samples > 1) {
  274.       /* If you're calling meta_BlitFramebuffer with the destination
  275.        * multisampled, this is the only path that will work -- swrast and
  276.        * CopyTexImage won't work on it either.
  277.        */
  278.       assert(ctx->Extensions.ARB_sample_shading);
  279.  
  280.       dst_is_msaa = true;
  281.  
  282.       /* We need shader invocation per sample, not per pixel */
  283.       _mesa_set_enable(ctx, GL_MULTISAMPLE, GL_TRUE);
  284.       _mesa_set_enable(ctx, GL_SAMPLE_SHADING, GL_TRUE);
  285.       _mesa_MinSampleShading(1.0);
  286.    }
  287.  
  288.    switch (target) {
  289.    case GL_TEXTURE_2D_MULTISAMPLE:
  290.    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
  291.       if (src_rb && (src_rb->_BaseFormat == GL_DEPTH_COMPONENT ||
  292.           src_rb->_BaseFormat == GL_DEPTH_STENCIL)) {
  293.          if (dst_is_msaa)
  294.             shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_COPY;
  295.          else
  296.             shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_RESOLVE;
  297.       } else {
  298.          if (dst_is_msaa)
  299.             shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_COPY;
  300.          else {
  301.             shader_index = BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE +
  302.                            shader_offset;
  303.          }
  304.       }
  305.  
  306.       if (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) {
  307.          shader_index += (BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_RESOLVE -
  308.                           BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE);
  309.          sampler_array_suffix = "Array";
  310.          texcoord_type = "vec3";
  311.       }
  312.       break;
  313.    default:
  314.       _mesa_problem(ctx, "Unkown texture target %s\n",
  315.                     _mesa_lookup_enum_by_nr(target));
  316.       shader_index = BLIT_2X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE;
  317.    }
  318.  
  319.    /* We rely on the enum being sorted this way. */
  320.    STATIC_ASSERT(BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_INT ==
  321.                  BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 5);
  322.    STATIC_ASSERT(BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_UINT ==
  323.                  BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 10);
  324.    if (src_datatype == GL_INT) {
  325.       shader_index += 5;
  326.       vec4_prefix = "i";
  327.    } else if (src_datatype == GL_UNSIGNED_INT) {
  328.       shader_index += 10;
  329.       vec4_prefix = "u";
  330.    } else {
  331.       vec4_prefix = "";
  332.    }
  333.  
  334.    if (blit->msaa_shaders[shader_index]) {
  335.       _mesa_UseProgram(blit->msaa_shaders[shader_index]);
  336.       return;
  337.    }
  338.  
  339.    mem_ctx = ralloc_context(NULL);
  340.  
  341.    if (shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_RESOLVE ||
  342.        shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_DEPTH_RESOLVE ||
  343.        shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_DEPTH_COPY ||
  344.        shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_COPY) {
  345.       char *sample_index;
  346.       const char *arb_sample_shading_extension_string;
  347.  
  348.       if (dst_is_msaa) {
  349.          arb_sample_shading_extension_string = "#extension GL_ARB_sample_shading : enable";
  350.          sample_index = "gl_SampleID";
  351.          name = "depth MSAA copy";
  352.       } else {
  353.          /* Don't need that extension, since we're drawing to a single-sampled
  354.           * destination.
  355.           */
  356.          arb_sample_shading_extension_string = "";
  357.          /* From the GL 4.3 spec:
  358.           *
  359.           *     "If there is a multisample buffer (the value of SAMPLE_BUFFERS
  360.           *      is one), then values are obtained from the depth samples in
  361.           *      this buffer. It is recommended that the depth value of the
  362.           *      centermost sample be used, though implementations may choose
  363.           *      any function of the depth sample values at each pixel.
  364.           *
  365.           * We're slacking and instead of choosing centermost, we've got 0.
  366.           */
  367.          sample_index = "0";
  368.          name = "depth MSAA resolve";
  369.       }
  370.  
  371.       vs_source = ralloc_asprintf(mem_ctx,
  372.                                   "#version 130\n"
  373.                                   "in vec2 position;\n"
  374.                                   "in %s textureCoords;\n"
  375.                                   "out %s texCoords;\n"
  376.                                   "void main()\n"
  377.                                   "{\n"
  378.                                   "   texCoords = textureCoords;\n"
  379.                                   "   gl_Position = vec4(position, 0.0, 1.0);\n"
  380.                                   "}\n",
  381.                                   texcoord_type,
  382.                                   texcoord_type);
  383.       fs_source = ralloc_asprintf(mem_ctx,
  384.                                   "#version 130\n"
  385.                                   "#extension GL_ARB_texture_multisample : enable\n"
  386.                                   "%s\n"
  387.                                   "uniform sampler2DMS%s texSampler;\n"
  388.                                   "in %s texCoords;\n"
  389.                                   "out vec4 out_color;\n"
  390.                                   "\n"
  391.                                   "void main()\n"
  392.                                   "{\n"
  393.                                   "   gl_FragDepth = texelFetch(texSampler, i%s(texCoords), %s).r;\n"
  394.                                   "}\n",
  395.                                   arb_sample_shading_extension_string,
  396.                                   sampler_array_suffix,
  397.                                   texcoord_type,
  398.                                   texcoord_type,
  399.                                   sample_index);
  400.    } else {
  401.       /* You can create 2D_MULTISAMPLE textures with 0 sample count (meaning 1
  402.        * sample).  Yes, this is ridiculous.
  403.        */
  404.       char *sample_resolve;
  405.       const char *arb_sample_shading_extension_string;
  406.       const char *merge_function;
  407.       name = ralloc_asprintf(mem_ctx, "%svec4 MSAA %s",
  408.                              vec4_prefix,
  409.                              dst_is_msaa ? "copy" : "resolve");
  410.  
  411.       if (dst_is_msaa) {
  412.          arb_sample_shading_extension_string = "#extension GL_ARB_sample_shading : enable";
  413.          sample_resolve = ralloc_asprintf(mem_ctx, "   out_color = texelFetch(texSampler, i%s(texCoords), gl_SampleID);", texcoord_type);
  414.          merge_function = "";
  415.       } else {
  416.          int i;
  417.          int step;
  418.  
  419.          if (src_datatype == GL_INT || src_datatype == GL_UNSIGNED_INT) {
  420.             merge_function =
  421.                "gvec4 merge(gvec4 a, gvec4 b) { return (a >> gvec4(1)) + (b >> gvec4(1)) + (a & b & gvec4(1)); }\n";
  422.          } else {
  423.             /* The divide will happen at the end for floats. */
  424.             merge_function =
  425.                "vec4 merge(vec4 a, vec4 b) { return (a + b); }\n";
  426.          }
  427.  
  428.          arb_sample_shading_extension_string = "";
  429.  
  430.          /* We're assuming power of two samples for this resolution procedure.
  431.           *
  432.           * To avoid losing any floating point precision if the samples all
  433.           * happen to have the same value, we merge pairs of values at a time
  434.           * (so the floating point exponent just gets increased), rather than
  435.           * doing a naive sum and dividing.
  436.           */
  437.          assert((samples & (samples - 1)) == 0);
  438.          /* Fetch each individual sample. */
  439.          sample_resolve = rzalloc_size(mem_ctx, 1);
  440.          for (i = 0; i < samples; i++) {
  441.             ralloc_asprintf_append(&sample_resolve,
  442.                                    "   gvec4 sample_1_%d = texelFetch(texSampler, i%s(texCoords), %d);\n",
  443.                                    i, texcoord_type, i);
  444.          }
  445.          /* Now, merge each pair of samples, then merge each pair of those,
  446.           * etc.
  447.           */
  448.          for (step = 2; step <= samples; step *= 2) {
  449.             for (i = 0; i < samples; i += step) {
  450.                ralloc_asprintf_append(&sample_resolve,
  451.                                       "   gvec4 sample_%d_%d = merge(sample_%d_%d, sample_%d_%d);\n",
  452.                                       step, i,
  453.                                       step / 2, i,
  454.                                       step / 2, i + step / 2);
  455.             }
  456.          }
  457.  
  458.          /* Scale the final result. */
  459.          if (src_datatype == GL_UNSIGNED_INT || src_datatype == GL_INT) {
  460.             ralloc_asprintf_append(&sample_resolve,
  461.                                    "   out_color = sample_%d_0;\n",
  462.                                    samples);
  463.          } else {
  464.             ralloc_asprintf_append(&sample_resolve,
  465.                                    "   gl_FragColor = sample_%d_0 / %f;\n",
  466.                                    samples, (float)samples);
  467.          }
  468.       }
  469.  
  470.       vs_source = ralloc_asprintf(mem_ctx,
  471.                                   "#version 130\n"
  472.                                   "in vec2 position;\n"
  473.                                   "in %s textureCoords;\n"
  474.                                   "out %s texCoords;\n"
  475.                                   "void main()\n"
  476.                                   "{\n"
  477.                                   "   texCoords = textureCoords;\n"
  478.                                   "   gl_Position = vec4(position, 0.0, 1.0);\n"
  479.                                   "}\n",
  480.                                   texcoord_type,
  481.                                   texcoord_type);
  482.       fs_source = ralloc_asprintf(mem_ctx,
  483.                                   "#version 130\n"
  484.                                   "#extension GL_ARB_texture_multisample : enable\n"
  485.                                   "%s\n"
  486.                                   "#define gvec4 %svec4\n"
  487.                                   "uniform %ssampler2DMS%s texSampler;\n"
  488.                                   "in %s texCoords;\n"
  489.                                   "out gvec4 out_color;\n"
  490.                                   "\n"
  491.                                   "%s" /* merge_function */
  492.                                   "void main()\n"
  493.                                   "{\n"
  494.                                   "%s\n" /* sample_resolve */
  495.                                   "}\n",
  496.                                   arb_sample_shading_extension_string,
  497.                                   vec4_prefix,
  498.                                   vec4_prefix,
  499.                                   sampler_array_suffix,
  500.                                   texcoord_type,
  501.                                   merge_function,
  502.                                   sample_resolve);
  503.    }
  504.  
  505.    _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source, name,
  506.                                        &blit->msaa_shaders[shader_index]);
  507.  
  508.    ralloc_free(mem_ctx);
  509. }
  510.  
  511. static void
  512. setup_glsl_blit_framebuffer(struct gl_context *ctx,
  513.                             struct blit_state *blit,
  514.                             const struct gl_framebuffer *drawFb,
  515.                             struct gl_renderbuffer *src_rb,
  516.                             GLenum target, GLenum filter,
  517.                             bool is_scaled_blit,
  518.                             bool do_depth)
  519. {
  520.    unsigned texcoord_size;
  521.    bool is_target_multisample = target == GL_TEXTURE_2D_MULTISAMPLE ||
  522.                                 target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
  523.    bool is_filter_scaled_resolve = filter == GL_SCALED_RESOLVE_FASTEST_EXT ||
  524.                                    filter == GL_SCALED_RESOLVE_NICEST_EXT;
  525.  
  526.    /* target = GL_TEXTURE_RECTANGLE is not supported in GLES 3.0 */
  527.    assert(_mesa_is_desktop_gl(ctx) || target == GL_TEXTURE_2D);
  528.  
  529.    texcoord_size = 2 + (src_rb->Depth > 1 ? 1 : 0);
  530.  
  531.    _mesa_meta_setup_vertex_objects(&blit->VAO, &blit->VBO, true,
  532.                                    2, texcoord_size, 0);
  533.  
  534.    if (is_target_multisample && is_filter_scaled_resolve && is_scaled_blit) {
  535.       setup_glsl_msaa_blit_scaled_shader(ctx, blit, src_rb, target, filter);
  536.    } else if (is_target_multisample) {
  537.       setup_glsl_msaa_blit_shader(ctx, blit, drawFb, src_rb, target);
  538.    } else {
  539.       _mesa_meta_setup_blit_shader(ctx, target, do_depth,
  540.                                    do_depth ? &blit->shaders_with_depth
  541.                                             : &blit->shaders_without_depth);
  542.    }
  543. }
  544.  
  545. /**
  546.  * Try to do a color or depth glBlitFramebuffer using texturing.
  547.  *
  548.  * We can do this when the src renderbuffer is actually a texture, or when the
  549.  * driver exposes BindRenderbufferTexImage().
  550.  */
  551. static bool
  552. blitframebuffer_texture(struct gl_context *ctx,
  553.                         const struct gl_framebuffer *readFb,
  554.                         const struct gl_framebuffer *drawFb,
  555.                         GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
  556.                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
  557.                         GLenum filter, GLint flipX, GLint flipY,
  558.                         GLboolean glsl_version, GLboolean do_depth)
  559. {
  560.    int att_index = do_depth ? BUFFER_DEPTH : readFb->_ColorReadBufferIndex;
  561.    const struct gl_renderbuffer_attachment *readAtt =
  562.       &readFb->Attachment[att_index];
  563.    struct blit_state *blit = &ctx->Meta->Blit;
  564.    struct fb_tex_blit_state fb_tex_blit;
  565.    const GLint dstX = MIN2(dstX0, dstX1);
  566.    const GLint dstY = MIN2(dstY0, dstY1);
  567.    const GLint dstW = abs(dstX1 - dstX0);
  568.    const GLint dstH = abs(dstY1 - dstY0);
  569.    const int srcW = abs(srcX1 - srcX0);
  570.    const int srcH = abs(srcY1 - srcY0);
  571.    bool scaled_blit = false;
  572.    struct gl_texture_object *texObj;
  573.    GLuint srcLevel;
  574.    GLenum target;
  575.    struct gl_renderbuffer *rb = readAtt->Renderbuffer;
  576.    struct temp_texture *meta_temp_texture;
  577.  
  578.    if (rb->NumSamples && !ctx->Extensions.ARB_texture_multisample)
  579.       return false;
  580.  
  581.    _mesa_meta_fb_tex_blit_begin(ctx, &fb_tex_blit);
  582.  
  583.    if (readAtt->Texture &&
  584.        (readAtt->Texture->Target == GL_TEXTURE_2D ||
  585.         readAtt->Texture->Target == GL_TEXTURE_RECTANGLE ||
  586.         readAtt->Texture->Target == GL_TEXTURE_2D_MULTISAMPLE ||
  587.         readAtt->Texture->Target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) {
  588.       /* If there's a texture attached of a type we can handle, then just use
  589.        * it directly.
  590.        */
  591.       srcLevel = readAtt->TextureLevel;
  592.       texObj = readAtt->Texture;
  593.       target = texObj->Target;
  594.    } else if (!readAtt->Texture && ctx->Driver.BindRenderbufferTexImage) {
  595.       if (!_mesa_meta_bind_rb_as_tex_image(ctx, rb, &fb_tex_blit.tempTex,
  596.                                            &texObj, &target))
  597.          return false;
  598.  
  599.       srcLevel = 0;
  600.       if (_mesa_is_winsys_fbo(readFb)) {
  601.          GLint temp = srcY0;
  602.          srcY0 = rb->Height - srcY1;
  603.          srcY1 = rb->Height - temp;
  604.          flipY = -flipY;
  605.       }
  606.    } else {
  607.       GLenum tex_base_format;
  608.       /* Fall back to doing a CopyTexSubImage to get the destination
  609.        * renderbuffer into a texture.
  610.        */
  611.       if (ctx->Meta->Blit.no_ctsi_fallback)
  612.          return false;
  613.  
  614.       if (rb->NumSamples > 1)
  615.          return false;
  616.  
  617.       if (do_depth) {
  618.          meta_temp_texture = _mesa_meta_get_temp_depth_texture(ctx);
  619.          tex_base_format = GL_DEPTH_COMPONENT;
  620.       } else {
  621.          meta_temp_texture = _mesa_meta_get_temp_texture(ctx);
  622.          tex_base_format =
  623.             _mesa_base_tex_format(ctx, rb->InternalFormat);
  624.       }
  625.  
  626.       srcLevel = 0;
  627.       target = meta_temp_texture->Target;
  628.       texObj = _mesa_lookup_texture(ctx, meta_temp_texture->TexObj);
  629.       if (texObj == NULL) {
  630.          return false;
  631.       }
  632.  
  633.       _mesa_meta_setup_copypix_texture(ctx, meta_temp_texture,
  634.                                        srcX0, srcY0,
  635.                                        srcW, srcH,
  636.                                        tex_base_format,
  637.                                        filter);
  638.  
  639.  
  640.       srcX0 = 0;
  641.       srcY0 = 0;
  642.       srcX1 = srcW;
  643.       srcY1 = srcH;
  644.    }
  645.  
  646.    fb_tex_blit.baseLevelSave = texObj->BaseLevel;
  647.    fb_tex_blit.maxLevelSave = texObj->MaxLevel;
  648.    fb_tex_blit.stencilSamplingSave = texObj->StencilSampling;
  649.  
  650.    scaled_blit = dstW != srcW || dstH != srcH;
  651.  
  652.    if (glsl_version) {
  653.       setup_glsl_blit_framebuffer(ctx, blit, drawFb, rb, target, filter, scaled_blit,
  654.                                   do_depth);
  655.    }
  656.    else {
  657.       _mesa_meta_setup_ff_tnl_for_blit(&ctx->Meta->Blit.VAO,
  658.                                        &ctx->Meta->Blit.VBO,
  659.                                        2);
  660.    }
  661.  
  662.    /*
  663.      printf("Blit from texture!\n");
  664.      printf("  srcAtt %p  dstAtt %p\n", readAtt, drawAtt);
  665.      printf("  srcTex %p  dstText %p\n", texObj, drawAtt->Texture);
  666.    */
  667.  
  668.    fb_tex_blit.sampler = _mesa_meta_setup_sampler(ctx, texObj, target, filter,
  669.                                                   srcLevel);
  670.  
  671.    /* Always do our blits with no net sRGB decode or encode.
  672.     *
  673.     * However, if both the src and dst can be srgb decode/encoded, enable them
  674.     * so that we do any blending (from scaling or from MSAA resolves) in the
  675.     * right colorspace.
  676.     *
  677.     * Our choice of not doing any net encode/decode is from the GL 3.0
  678.     * specification:
  679.     *
  680.     *     "Blit operations bypass the fragment pipeline. The only fragment
  681.     *      operations which affect a blit are the pixel ownership test and the
  682.     *      scissor test."
  683.     *
  684.     * The GL 4.4 specification disagrees and says that the sRGB part of the
  685.     * fragment pipeline applies, but this was found to break applications.
  686.     */
  687.    if (ctx->Extensions.EXT_texture_sRGB_decode) {
  688.       if (_mesa_get_format_color_encoding(rb->Format) == GL_SRGB &&
  689.           drawFb->Visual.sRGBCapable) {
  690.          _mesa_SamplerParameteri(fb_tex_blit.sampler,
  691.                                  GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
  692.          _mesa_set_framebuffer_srgb(ctx, GL_TRUE);
  693.       } else {
  694.          _mesa_SamplerParameteri(fb_tex_blit.sampler,
  695.                                  GL_TEXTURE_SRGB_DECODE_EXT,
  696.                                  GL_SKIP_DECODE_EXT);
  697.          /* set_framebuffer_srgb was set by _mesa_meta_begin(). */
  698.       }
  699.    }
  700.  
  701.    if (!glsl_version) {
  702.       _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  703.       _mesa_set_enable(ctx, target, GL_TRUE);
  704.    }
  705.  
  706.    /* Prepare vertex data (the VBO was previously created and bound) */
  707.    {
  708.       struct vertex verts[4];
  709.       GLfloat s0, t0, s1, t1;
  710.  
  711.       if (target == GL_TEXTURE_2D) {
  712.          const struct gl_texture_image *texImage
  713.             = _mesa_select_tex_image(texObj, target, srcLevel);
  714.          s0 = srcX0 / (float) texImage->Width;
  715.          s1 = srcX1 / (float) texImage->Width;
  716.          t0 = srcY0 / (float) texImage->Height;
  717.          t1 = srcY1 / (float) texImage->Height;
  718.       }
  719.       else {
  720.          assert(target == GL_TEXTURE_RECTANGLE_ARB ||
  721.                 target == GL_TEXTURE_2D_MULTISAMPLE ||
  722.                 target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
  723.          s0 = (float) srcX0;
  724.          s1 = (float) srcX1;
  725.          t0 = (float) srcY0;
  726.          t1 = (float) srcY1;
  727.       }
  728.  
  729.       /* Silence valgrind warnings about reading uninitialized stack. */
  730.       memset(verts, 0, sizeof(verts));
  731.  
  732.       /* setup vertex positions */
  733.       verts[0].x = -1.0F * flipX;
  734.       verts[0].y = -1.0F * flipY;
  735.       verts[1].x =  1.0F * flipX;
  736.       verts[1].y = -1.0F * flipY;
  737.       verts[2].x =  1.0F * flipX;
  738.       verts[2].y =  1.0F * flipY;
  739.       verts[3].x = -1.0F * flipX;
  740.       verts[3].y =  1.0F * flipY;
  741.  
  742.       verts[0].tex[0] = s0;
  743.       verts[0].tex[1] = t0;
  744.       verts[0].tex[2] = readAtt->Zoffset;
  745.       verts[1].tex[0] = s1;
  746.       verts[1].tex[1] = t0;
  747.       verts[1].tex[2] = readAtt->Zoffset;
  748.       verts[2].tex[0] = s1;
  749.       verts[2].tex[1] = t1;
  750.       verts[2].tex[2] = readAtt->Zoffset;
  751.       verts[3].tex[0] = s0;
  752.       verts[3].tex[1] = t1;
  753.       verts[3].tex[2] = readAtt->Zoffset;
  754.  
  755.       _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
  756.    }
  757.  
  758.    /* setup viewport */
  759.    _mesa_set_viewport(ctx, 0, dstX, dstY, dstW, dstH);
  760.    _mesa_ColorMask(!do_depth, !do_depth, !do_depth, !do_depth);
  761.    _mesa_set_enable(ctx, GL_DEPTH_TEST, do_depth);
  762.    _mesa_DepthMask(do_depth);
  763.    _mesa_DepthFunc(GL_ALWAYS);
  764.  
  765.    _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
  766.    _mesa_meta_fb_tex_blit_end(ctx, target, &fb_tex_blit);
  767.  
  768.    return true;
  769. }
  770.  
  771. void
  772. _mesa_meta_fb_tex_blit_begin(const struct gl_context *ctx,
  773.                              struct fb_tex_blit_state *blit)
  774. {
  775.    blit->samplerSave =
  776.       ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ?
  777.       ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0;
  778.    blit->tempTex = 0;
  779. }
  780.  
  781. void
  782. _mesa_meta_fb_tex_blit_end(struct gl_context *ctx, GLenum target,
  783.                            struct fb_tex_blit_state *blit)
  784. {
  785.    /* Restore texture object state, the texture binding will
  786.     * be restored by _mesa_meta_end().
  787.     */
  788.    if (target != GL_TEXTURE_RECTANGLE_ARB) {
  789.       _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, blit->baseLevelSave);
  790.       _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, blit->maxLevelSave);
  791.  
  792.       if (ctx->Extensions.ARB_stencil_texturing) {
  793.          const struct gl_texture_object *texObj =
  794.             _mesa_get_current_tex_object(ctx, target);
  795.  
  796.          if (texObj->StencilSampling != blit->stencilSamplingSave)
  797.             _mesa_TexParameteri(target, GL_DEPTH_STENCIL_TEXTURE_MODE,
  798.                                 blit->stencilSamplingSave ?
  799.                                    GL_STENCIL_INDEX : GL_DEPTH_COMPONENT);
  800.       }
  801.    }
  802.  
  803.    _mesa_BindSampler(ctx->Texture.CurrentUnit, blit->samplerSave);
  804.    _mesa_DeleteSamplers(1, &blit->sampler);
  805.    if (blit->tempTex)
  806.       _mesa_DeleteTextures(1, &blit->tempTex);
  807. }
  808.  
  809. GLboolean
  810. _mesa_meta_bind_rb_as_tex_image(struct gl_context *ctx,
  811.                                 struct gl_renderbuffer *rb,
  812.                                 GLuint *tex,
  813.                                 struct gl_texture_object **texObj,
  814.                                 GLenum *target)
  815. {
  816.    struct gl_texture_image *texImage;
  817.    GLuint tempTex;
  818.  
  819.    if (rb->NumSamples > 1)
  820.       *target = GL_TEXTURE_2D_MULTISAMPLE;
  821.    else
  822.       *target = GL_TEXTURE_2D;
  823.  
  824.    tempTex = 0;
  825.    _mesa_GenTextures(1, &tempTex);
  826.    if (tempTex == 0)
  827.       return false;
  828.  
  829.    *tex = tempTex;
  830.  
  831.    _mesa_BindTexture(*target, *tex);
  832.    *texObj = _mesa_lookup_texture(ctx, *tex);
  833.    texImage = _mesa_get_tex_image(ctx, *texObj, *target, 0);
  834.  
  835.    if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, texImage)) {
  836.       _mesa_DeleteTextures(1, tex);
  837.       return false;
  838.    }
  839.  
  840.    if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) {
  841.       rb->NeedsFinishRenderTexture = true;
  842.       ctx->Driver.FinishRenderTexture(ctx, rb);
  843.    }
  844.  
  845.    return true;
  846. }
  847.  
  848. GLuint
  849. _mesa_meta_setup_sampler(struct gl_context *ctx,
  850.                          const struct gl_texture_object *texObj,
  851.                          GLenum target, GLenum filter, GLuint srcLevel)
  852. {
  853.    GLuint sampler;
  854.    GLenum tex_filter = (filter == GL_SCALED_RESOLVE_FASTEST_EXT ||
  855.                         filter == GL_SCALED_RESOLVE_NICEST_EXT) ?
  856.                        GL_NEAREST : filter;
  857.  
  858.    _mesa_GenSamplers(1, &sampler);
  859.    _mesa_BindSampler(ctx->Texture.CurrentUnit, sampler);
  860.  
  861.    /* Prepare src texture state */
  862.    _mesa_BindTexture(target, texObj->Name);
  863.    _mesa_SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, tex_filter);
  864.    _mesa_SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, tex_filter);
  865.    if (target != GL_TEXTURE_RECTANGLE_ARB) {
  866.       _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, srcLevel);
  867.       _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel);
  868.    }
  869.    _mesa_SamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  870.    _mesa_SamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  871.  
  872.    return sampler;
  873. }
  874.  
  875. /**
  876.  * Meta implementation of ctx->Driver.BlitFramebuffer() in terms
  877.  * of texture mapping and polygon rendering.
  878.  */
  879. GLbitfield
  880. _mesa_meta_BlitFramebuffer(struct gl_context *ctx,
  881.                            const struct gl_framebuffer *readFb,
  882.                            const struct gl_framebuffer *drawFb,
  883.                            GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
  884.                            GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
  885.                            GLbitfield mask, GLenum filter)
  886. {
  887.    const GLint dstW = abs(dstX1 - dstX0);
  888.    const GLint dstH = abs(dstY1 - dstY0);
  889.    const GLint dstFlipX = (dstX1 - dstX0) / dstW;
  890.    const GLint dstFlipY = (dstY1 - dstY0) / dstH;
  891.  
  892.    struct {
  893.       GLint srcX0, srcY0, srcX1, srcY1;
  894.       GLint dstX0, dstY0, dstX1, dstY1;
  895.    } clip = {
  896.       srcX0, srcY0, srcX1, srcY1,
  897.       dstX0, dstY0, dstX1, dstY1
  898.    };
  899.  
  900.    const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
  901.                                       ctx->Extensions.ARB_fragment_shader;
  902.  
  903.    /* Multisample texture blit support requires texture multisample. */
  904.    if (readFb->Visual.samples > 0 &&
  905.        !ctx->Extensions.ARB_texture_multisample) {
  906.       return mask;
  907.    }
  908.  
  909.    /* Clip a copy of the blit coordinates. If these differ from the input
  910.     * coordinates, then we'll set the scissor.
  911.     */
  912.    if (!_mesa_clip_blit(ctx, readFb, drawFb,
  913.                         &clip.srcX0, &clip.srcY0, &clip.srcX1, &clip.srcY1,
  914.                         &clip.dstX0, &clip.dstY0, &clip.dstX1, &clip.dstY1)) {
  915.       /* clipped/scissored everything away */
  916.       return 0;
  917.    }
  918.  
  919.    /* Only scissor affects blit, but we're doing to set a custom scissor if
  920.     * necessary anyway, so save/clear state.
  921.     */
  922.    _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS);
  923.  
  924.    /* Dithering shouldn't be performed for glBlitFramebuffer */
  925.    _mesa_set_enable(ctx, GL_DITHER, GL_FALSE);
  926.  
  927.    /* If the clipping earlier changed the destination rect at all, then
  928.     * enable the scissor to clip to it.
  929.     */
  930.    if (clip.dstX0 != dstX0 || clip.dstY0 != dstY0 ||
  931.        clip.dstX1 != dstX1 || clip.dstY1 != dstY1) {
  932.       _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_TRUE);
  933.       _mesa_Scissor(MIN2(clip.dstX0, clip.dstX1),
  934.                     MIN2(clip.dstY0, clip.dstY1),
  935.                     abs(clip.dstX0 - clip.dstX1),
  936.                     abs(clip.dstY0 - clip.dstY1));
  937.    }
  938.  
  939.    /* Try faster, direct texture approach first */
  940.    if (mask & GL_COLOR_BUFFER_BIT) {
  941.       if (blitframebuffer_texture(ctx, readFb, drawFb,
  942.                                   srcX0, srcY0, srcX1, srcY1,
  943.                                   dstX0, dstY0, dstX1, dstY1,
  944.                                   filter, dstFlipX, dstFlipY,
  945.                                   use_glsl_version, false)) {
  946.          mask &= ~GL_COLOR_BUFFER_BIT;
  947.       }
  948.    }
  949.  
  950.    if (mask & GL_DEPTH_BUFFER_BIT && use_glsl_version) {
  951.       if (blitframebuffer_texture(ctx, readFb, drawFb,
  952.                                   srcX0, srcY0, srcX1, srcY1,
  953.                                   dstX0, dstY0, dstX1, dstY1,
  954.                                   filter, dstFlipX, dstFlipY,
  955.                                   use_glsl_version, true)) {
  956.          mask &= ~GL_DEPTH_BUFFER_BIT;
  957.       }
  958.    }
  959.  
  960.    if (mask & GL_STENCIL_BUFFER_BIT) {
  961.       /* XXX can't easily do stencil */
  962.    }
  963.  
  964.    _mesa_meta_end(ctx);
  965.  
  966.    return mask;
  967. }
  968.  
  969. void
  970. _mesa_meta_glsl_blit_cleanup(struct blit_state *blit)
  971. {
  972.    if (blit->VAO) {
  973.       _mesa_DeleteVertexArrays(1, &blit->VAO);
  974.       blit->VAO = 0;
  975.       _mesa_DeleteBuffers(1, &blit->VBO);
  976.       blit->VBO = 0;
  977.    }
  978.  
  979.    _mesa_meta_blit_shader_table_cleanup(&blit->shaders_with_depth);
  980.    _mesa_meta_blit_shader_table_cleanup(&blit->shaders_without_depth);
  981.  
  982.    _mesa_DeleteTextures(1, &blit->depthTex.TexObj);
  983.    blit->depthTex.TexObj = 0;
  984. }
  985.  
  986. void
  987. _mesa_meta_and_swrast_BlitFramebuffer(struct gl_context *ctx,
  988.                                       struct gl_framebuffer *readFb,
  989.                                       struct gl_framebuffer *drawFb,
  990.                                       GLint srcX0, GLint srcY0,
  991.                                       GLint srcX1, GLint srcY1,
  992.                                       GLint dstX0, GLint dstY0,
  993.                                       GLint dstX1, GLint dstY1,
  994.                                       GLbitfield mask, GLenum filter)
  995. {
  996.    mask = _mesa_meta_BlitFramebuffer(ctx, readFb, drawFb,
  997.                                      srcX0, srcY0, srcX1, srcY1,
  998.                                      dstX0, dstY0, dstX1, dstY1,
  999.                                      mask, filter);
  1000.    if (mask == 0x0)
  1001.       return;
  1002.  
  1003.    _swrast_BlitFramebuffer(ctx, readFb, drawFb,
  1004.                            srcX0, srcY0, srcX1, srcY1,
  1005.                            dstX0, dstY0, dstX1, dstY1,
  1006.                            mask, filter);
  1007. }
  1008.