Skip to content

Commit

Permalink
Enable ETC2 compressed textures and add tool to generate them from ra…
Browse files Browse the repository at this point in the history
…w assets
  • Loading branch information
MortimerGoro committed Dec 14, 2018
1 parent 91d4710 commit 77ae356
Show file tree
Hide file tree
Showing 52 changed files with 148 additions and 22 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -66,3 +66,6 @@ oculussig_*
third_party

user.properties*

# Node modules
node_modules
9 changes: 9 additions & 0 deletions README.md
Expand Up @@ -100,6 +100,15 @@ geckoViewLocalArm=/path/to/your/build/geckoview-nightly-armeabi-v7a-64.0.2018092
geckoViewLocalX86=/path/to/your/build/geckoview-nightly-x86-64.0.20180924100359.aar
```

## Compress assets

ETC2 compression is used to improve performance and memory usage. Raw assets are placed in the `uncompressed_assets` folder. You can generate the compressed textures using the compressor utility in `tools/compressor`. You need to set up [etc2comp](https://github.com/google/etc2comp) and make it available on your PATH before running the script. Run this command to generate the compressed assets:

```bash
npm install
gulp compress
```

## Development troubleshooting

### `Device supports , but APK only supports armeabi-v7a[...]`
Expand Down
Binary file added app/src/main/assets/cubemap/cave/negx.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/cave/negy.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/cave/negz.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/cave/posx.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/cave/posy.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/cave/posz.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/meadow/negx.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/meadow/negy.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/meadow/negz.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/meadow/posx.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/meadow/posy.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/meadow/posz.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/space/negx.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/space/negy.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/space/negz.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/space/posx.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/space/posy.ktx
Binary file not shown.
Binary file added app/src/main/assets/cubemap/space/posz.ktx
Binary file not shown.
Binary file added app/src/main/assets/spinners_v3.ktx
Binary file not shown.
2 changes: 1 addition & 1 deletion app/src/main/assets/spinners_v3.mtl
Expand Up @@ -10,4 +10,4 @@ Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd spinners_v3.jpg
map_Kd spinners_v3.ktx
Binary file removed app/src/main/assets/webvr_spinner.png
Binary file not shown.
18 changes: 11 additions & 7 deletions app/src/main/cpp/BrowserWorld.cpp
Expand Up @@ -505,14 +505,16 @@ BrowserWorld::InitializeJava(JNIEnv* aEnv, jobject& aActivity, jobject& aAssetMa
m.loadingAnimation->LoadModels(m.loader);
m.rootController->AddNode(m.controllers->GetRoot());
std::string skyboxPath = VRBrowser::GetActiveEnvironment();
std::string extension;
if (VRBrowser::isOverrideEnvPathEnabled()) {
std::string storagePath = VRBrowser::GetStorageAbsolutePath(INJECT_SKYBOX_PATH);
if (std::ifstream(storagePath)) {
skyboxPath = storagePath;
extension = ".jpg";
}
}
#if !defined(SNAPDRAGONVR)
CreateSkyBox(skyboxPath.c_str());
CreateSkyBox(skyboxPath.c_str(), extension);
// Don't load the env model, we are going for skyboxes in v1.0
// CreateFloor();
#endif
Expand Down Expand Up @@ -650,7 +652,7 @@ BrowserWorld::UpdateEnvironment() {
ASSERT_ON_RENDER_THREAD();
std::string env = VRBrowser::GetActiveEnvironment();
VRB_LOG("Setting environment: %s", env.c_str());
CreateSkyBox(env.c_str());
CreateSkyBox(env.c_str(), "");
}

void
Expand Down Expand Up @@ -1071,21 +1073,23 @@ BrowserWorld::DrawSplashAnimation() {
}

void
BrowserWorld::CreateSkyBox(const std::string& basePath) {
BrowserWorld::CreateSkyBox(const std::string& aBasePath, const std::string& aExtension) {
ASSERT_ON_RENDER_THREAD();
const bool empty = basePath == "cubemap/void";
const bool empty = aBasePath == "cubemap/void";
const std::string extension = aExtension.empty() ? ".ktx" : aExtension;
if (m.skybox && empty) {
m.skybox->SetVisible(false);
return;
} else if (m.skybox) {
m.skybox->SetVisible(true);
m.skybox->Load(m.loader, basePath);
m.skybox->Load(m.loader, aBasePath, extension);
return;
} else if (!empty) {
VRLayerCubePtr layer = m.device->CreateLayerCube(1024, 1024);
GLenum glFormat = extension == ".ktx" ? GL_COMPRESSED_RGB8_ETC2 : GL_RGB8;
VRLayerCubePtr layer = m.device->CreateLayerCube(1024, 1024, glFormat);
m.skybox = Skybox::Create(m.create, layer);
m.rootOpaqueParent->AddNode(m.skybox->GetRoot());
m.skybox->Load(m.loader, basePath);
m.skybox->Load(m.loader, aBasePath, extension);
}
}

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/cpp/BrowserWorld.h
Expand Up @@ -65,7 +65,7 @@ class BrowserWorld {
void DrawImmersive();
void DrawLoadingAnimation();
void DrawSplashAnimation();
void CreateSkyBox(const std::string& basePath);
void CreateSkyBox(const std::string& aBasePath, const std::string& aExtension);
void CreateFloor();
float DistanceToPlane(const vrb::NodePtr& aNode, const vrb::Vector& aPosition, const vrb::Vector& aDirection) const;
private:
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/cpp/DeviceDelegate.h
Expand Up @@ -65,7 +65,7 @@ class DeviceDelegate {
virtual VRLayerQuadPtr CreateLayerQuad(int32_t aWidth,
int32_t aHeight,
VRLayerQuad::SurfaceType aSurfaceType) { return nullptr; }
virtual VRLayerCubePtr CreateLayerCube(int32_t aWidth, int32_t aHeight) { return nullptr; }
virtual VRLayerCubePtr CreateLayerCube(int32_t aWidth, int32_t aHeight, GLint aInternalFormat) { return nullptr; }
virtual VRLayerEquirectPtr CreateLayerEquirect(const VRLayerQuadPtr &aSource) { return nullptr; }
virtual void DeleteLayer(const VRLayerPtr& aLayer) {};
protected:
Expand Down
13 changes: 8 additions & 5 deletions app/src/main/cpp/Skybox.cpp
Expand Up @@ -25,15 +25,16 @@ using namespace vrb;

namespace crow {

static TextureCubeMapPtr LoadTextureCube(vrb::CreationContextPtr& aContext, const std::string& aBasePath, GLuint targetTexture = 0) {
static TextureCubeMapPtr LoadTextureCube(vrb::CreationContextPtr& aContext, const std::string& aBasePath,
const std::string& aExtension, GLuint targetTexture = 0) {
TextureCubeMapPtr cubemap = vrb::TextureCubeMap::Create(aContext, targetTexture);
cubemap->SetTextureParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
cubemap->SetTextureParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
cubemap->SetTextureParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
cubemap->SetTextureParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
cubemap->SetTextureParameter(GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

auto path = [&](const std::string &name) { return aBasePath + "/" + name + ".jpg"; };
auto path = [&](const std::string &name) { return aBasePath + "/" + name + aExtension; };
vrb::TextureCubeMap::Load(aContext, cubemap, path("posx"), path("negx"), path("posy"),
path("negy"), path("posz"), path("negz"));
return cubemap;
Expand All @@ -48,6 +49,7 @@ struct Skybox::State {
vrb::GeometryPtr geometry;
vrb::ModelLoaderAndroidPtr loader;
std::string basePath;
std::string extension;
TextureCubeMapPtr texture;
State():
layerTextureHandle(0)
Expand Down Expand Up @@ -116,7 +118,7 @@ struct Skybox::State {
}


texture = LoadTextureCube(aContext, basePath);
texture = LoadTextureCube(aContext, basePath, extension);
vrb::RenderStatePtr state = geometry->GetRenderState();
state->SetTexture(texture);
state->SetMaterial(Color(1.0f, 1.0f, 1.0f), Color(1.0f, 1.0f, 1.0f), Color(0.0f, 0.0f, 0.0f),
Expand All @@ -135,19 +137,20 @@ struct Skybox::State {
return;
}
vrb::CreationContextPtr create = context.lock();
texture = LoadTextureCube(create, basePath, layerTextureHandle);
texture = LoadTextureCube(create, basePath, extension, layerTextureHandle);
texture->Bind();
layer->SetLoaded(true);
}
};

void
Skybox::Load(const vrb::ModelLoaderAndroidPtr& aLoader, const std::string& aBasePath) {
Skybox::Load(const vrb::ModelLoaderAndroidPtr& aLoader, const std::string& aBasePath, const std::string& aExtension) {
if (m.basePath == aBasePath) {
return;
}
m.loader = aLoader;
m.basePath = aBasePath;
m.extension = aExtension;
if (m.layer) {
m.LoadLayer();
} else {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/cpp/Skybox.h
Expand Up @@ -20,7 +20,7 @@ typedef std::shared_ptr<VRLayerCube> VRLayerCubePtr;
class Skybox {
public:
static SkyboxPtr Create(vrb::CreationContextPtr aContext, const VRLayerCubePtr& aLayer = nullptr);
void Load(const vrb::ModelLoaderAndroidPtr& aLoader, const std::string &basePath);
void Load(const vrb::ModelLoaderAndroidPtr& aLoader, const std::string& aBasePath, const std::string& aExtension);
void SetVisible(bool aVisible);
void SetTransform(const vrb::Matrix& aTransform);
void SetTintColor(const vrb::Color& aTintColor);
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
11 changes: 7 additions & 4 deletions app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp
Expand Up @@ -326,9 +326,10 @@ typedef std::shared_ptr<OculusLayerCube> OculusLayerCubePtr;

class OculusLayerCube: public OculusLayer<VRLayerCubePtr, ovrLayerCube2> {
public:
static OculusLayerCubePtr Create(const VRLayerCubePtr& aLayer) {
static OculusLayerCubePtr Create(const VRLayerCubePtr& aLayer, GLint aInternalFormat) {
auto result = std::make_shared<OculusLayerCube>();
result->layer = aLayer;
result->glFormat = aInternalFormat;
return result;
}

Expand All @@ -341,7 +342,7 @@ class OculusLayerCube: public OculusLayer<VRLayerCubePtr, ovrLayerCube2> {
ovrLayer.Offset.x = 0.0f;
ovrLayer.Offset.y = 0.0f;
ovrLayer.Offset.z = 0.0f;
swapChain = vrapi_CreateTextureSwapChain(VRAPI_TEXTURE_TYPE_CUBE, VRAPI_TEXTURE_FORMAT_8888, layer->GetWidth(), layer->GetHeight(), 1, false);
swapChain = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_CUBE, glFormat, layer->GetWidth(), layer->GetHeight(), 1, 1);
layer->SetTextureHandle(vrapi_GetTextureSwapChainHandle(swapChain, 0));
OculusLayer::Init();
}
Expand Down Expand Up @@ -375,6 +376,8 @@ class OculusLayerCube: public OculusLayer<VRLayerCubePtr, ovrLayerCube2> {
const ovrLayerHeader2 * Header() const override {
return &ovrLayer.Header;
}
protected:
GLint glFormat;
};


Expand Down Expand Up @@ -1059,15 +1062,15 @@ DeviceDelegateOculusVR::CreateLayerQuad(int32_t aWidth, int32_t aHeight,
}

VRLayerCubePtr
DeviceDelegateOculusVR::CreateLayerCube(int32_t aWidth, int32_t aHeight) {
DeviceDelegateOculusVR::CreateLayerCube(int32_t aWidth, int32_t aHeight, GLint aInternalFormat) {
if (!m.layersEnabled) {
return nullptr;
}
if (m.cubeLayer) {
m.cubeLayer->Destroy();
}
VRLayerCubePtr layer = VRLayerCube::Create(aWidth, aHeight);
m.cubeLayer = OculusLayerCube::Create(layer);
m.cubeLayer = OculusLayerCube::Create(layer, aInternalFormat);
if (m.ovr) {
m.cubeLayer->Init();
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/oculusvr/cpp/DeviceDelegateOculusVR.h
Expand Up @@ -43,7 +43,7 @@ class DeviceDelegateOculusVR : public DeviceDelegate {
void EndFrame(const bool aDiscard) override;
VRLayerQuadPtr CreateLayerQuad(int32_t aWidth, int32_t aHeight,
VRLayerQuad::SurfaceType aSurfaceType) override;
VRLayerCubePtr CreateLayerCube(int32_t aWidth, int32_t aHeight) override;
VRLayerCubePtr CreateLayerCube(int32_t aWidth, int32_t aHeight, GLint aInternalFormat) override;
VRLayerEquirectPtr CreateLayerEquirect(const VRLayerQuadPtr &aSource) override;
void DeleteLayer(const VRLayerPtr& aLayer) override;
// Custom methods for NativeActivity render loop based devices.
Expand Down
80 changes: 80 additions & 0 deletions tools/compressor/gulpfile.js
@@ -0,0 +1,80 @@
const fs = require('fs');
const path = require('path');
const gulp = require('gulp');
const sharp = require('sharp');
const tmp = require('tmp');
const execSync = require('child_process').execSync;
const readdirp = require('readdirp');

const assetsPath = '../../app/src/main/uncompressed_assets';
const assetFilter = ['*.jpg', '*.jpeg', '*.png'];

function compressAsset(source, target, rgba, done) {
if (fs.existsSync(target)) {
console.log("Already compressed: " + target);
done();
return;
}

const extension = path.extname(source);
if (extension !== ".png") {
// Etc2Tool requires png format
const tempImage = tmp.tmpNameSync() + ".png";
sharp(source)
.toFile(tempImage)
.then(data => {
compressAsset(tempImage, target, false, done);
})
.catch(err => {
console.log("PNG conversion failed for " + source + ": " + err);
done(err);
});
return;
}

try {
console.log("About to compress: " + target);
var format = rgba ? "RGBA8" : "RGB8";
var out = execSync(`EtcTool ${source} -output ${target} -format ${format} -effort 100 -v`).toString();
console.log(out);
done();
} catch (err) {
console.error(err.message);
done(err);
}
}

gulp.task('compress', function(done) {
let pending = 0;
let finished = false;
const settings = {
root: assetsPath,
fileFilter: assetFilter
};
readdirp(settings)
.on('data', function (entry) {
pending++;
const name = entry.fullPath;
const extension = path.extname(name);
let target = name.slice(0, -extension.length) + ".ktx";
target = target.replace("uncompressed_assets", "assets");
compressAsset(name, target, true, function() {
pending--;
if (finished && !pending) {
done();
}
});
})
.on('warn', function(warn){
console.log("Warn: ", warn);
})
.on('error', function(err){
console.log("Error: ", err);
})
.on('end', function(){
finished = true;
if (!pending) {
done();
}
});
});
24 changes: 24 additions & 0 deletions tools/compressor/package.json
@@ -0,0 +1,24 @@
{
"name": "fxr-compressor",
"version": "1.0.0",
"description": "FxR asset compressor",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"fxr",
"asset",
"compressor"
],
"author": "Mozilla",
"license": "Apache-2.0",
"devDependencies": {
"gulp": "^4.0.0"
},
"dependencies": {
"readdirp": "^2.2.1",
"sharp": "^0.21.1",
"tmp": "0.0.33"
}
}

0 comments on commit 77ae356

Please sign in to comment.