bool AssetTexture::CreateGLTextures()

in display-p3/image-view/src/main/cpp/AssetTexture.cpp [76:189]


bool AssetTexture::CreateGLTextures(AAssetManager *mgr) {
  ASSERT(mgr, "Asset Manager is not valid");
  ASSERT(dispColorSpace_ != DISPLAY_COLORSPACE::INVALID, "eglContext_ color space not set");
  if (valid_) {
    glDeleteTextures(1, &p3Id_);
    glDeleteTextures(1, &sRGBId_);
    valid_ = false;
    p3Id_ = INVALID_TEXTURE_ID;
    sRGBId_ = INVALID_TEXTURE_ID;
  }

  glGenTextures(1, &p3Id_);
  glBindTexture(GL_TEXTURE_2D, p3Id_);

  std::vector<uint8_t> fileData;
  AssetReadFile(mgr, name_, fileData);

  uint32_t imgWidth, imgHeight, n;
  uint8_t* imageData = stbi_load_from_memory(
      fileData.data(), fileData.size(), reinterpret_cast<int*>(&imgWidth),
      reinterpret_cast<int*>(&imgHeight), reinterpret_cast<int*>(&n), 4);
  uint8_t* imgBits = imageData;
  std::vector<uint8_t> staging;
  if (dispColorSpace_ == DISPLAY_COLORSPACE::SRGB) {
    staging.resize(imgWidth * imgHeight * 4 * sizeof(uint8_t));
    IMAGE_FORMAT src {
        .buf_ = imageData,
        .width_ = imgWidth,
        .height_ = imgHeight,
        .gamma_ = DEFAULT_P3_IMAGE_GAMMA,
        .npm_ = GetTransformNPM(NPM_TYPE::P3_D65),
    };

    IMAGE_FORMAT dst {
        .buf_ = staging.data(),
        .width_ = imgWidth,
        .height_ = imgHeight,
        .gamma_ = DEFAULT_DISPLAY_GAMMA,
        .npm_ = GetTransformNPM(NPM_TYPE::SRGB_D65_INV),
    };
    TransformColorSpace(dst, src);
    imgBits = staging.data();
  }

  // Our texture content is EOTF encoded, but depends on display P3 mode, app chooses to
  // use or bypass EOTF & OETF hardware functionality. See detailed comments in WideColorCtx.cpp
  // If OETF/EOTF needs bypassed on Android P and before, set flag for the texture to be in RGBA
  // to fake GPU to bypass OETF/EOTF ( gamma alike thing ).
  GLint textureInternalFormat = GL_SRGB8_ALPHA8;
  if (dispColorSpace_ == DISPLAY_COLORSPACE::P3_PASSTHROUGH) {
      textureInternalFormat = GL_RGBA;
  }
  glTexImage2D(GL_TEXTURE_2D, 0,  // mip level
               textureInternalFormat,
               imgWidth, imgHeight,
               0,                // border color
               GL_RGBA, GL_UNSIGNED_BYTE, imgBits);

  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

  // Generate sRGB view texture
  glGenTextures(1, &sRGBId_);
  glBindTexture(GL_TEXTURE_2D, sRGBId_);
  if(dispColorSpace_ == DISPLAY_COLORSPACE::P3 || dispColorSpace_ == DISPLAY_COLORSPACE::P3_PASSTHROUGH) {
    IMAGE_FORMAT src {
        .buf_ = imageData,
        .width_ = imgWidth,
        .height_ = imgHeight,
        .gamma_ = DEFAULT_P3_IMAGE_GAMMA,
        .npm_ = GetTransformNPM(NPM_TYPE::P3_D65),
    };
    std::vector<uint8_t> srgbImg(imgWidth * imgHeight * 4 * sizeof(uint8_t));
    IMAGE_FORMAT dst{
        .buf_ = srgbImg.data(),
        .width_ = imgWidth,
        .height_ = imgHeight,
        .gamma_ = 0.0f,     // intermediate image stays in linear space
        .npm_ = GetTransformNPM(NPM_TYPE::SRGB_D65_INV),
    };
    TransformColorSpace(dst, src);

    // sRGB back to P3 so we could display_ it correctly on P3 device mode
    staging.resize(imgWidth * imgHeight * 4 * sizeof(uint8_t));
    IMAGE_FORMAT tmp  = src;
    src = dst;   // intermediate gamma is 0.0f
    dst = tmp;   // original src's gamma is preserved
    src.npm_ = GetTransformNPM(NPM_TYPE::SRGB_D65);
    dst.buf_ = staging.data();
    dst.npm_ = GetTransformNPM(NPM_TYPE::P3_D65_INV);
    dst.gamma_ = DEFAULT_DISPLAY_GAMMA,

    TransformColorSpace(dst, src);
    imgBits = staging.data();
  }
  glTexImage2D(GL_TEXTURE_2D, 0,  // mip level
               textureInternalFormat, // GL_SRGB8_ALPHA8 for p3_ext mode,
                                      // GL_RGBA for p3_passthrough_ext
               imgWidth, imgHeight,
               0,                // border color
               GL_RGBA, GL_UNSIGNED_BYTE, imgBits);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

  glBindTexture(GL_TEXTURE_2D, 0);
  stbi_image_free(imageData);
  valid_ = true;

  return true;
}