You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
8.5 KiB
246 lines
8.5 KiB
4 months ago
|
/*
|
||
|
* Copyright (C) 2017 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#include "RenderDirectView.h"
|
||
|
|
||
|
#include "VideoTex.h"
|
||
|
#include "glError.h"
|
||
|
#include "shader.h"
|
||
|
#include "shader_simpleTex.h"
|
||
|
|
||
|
#include <android-base/logging.h>
|
||
|
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
|
||
|
#include <math/mat4.h>
|
||
|
#include <system/camera_metadata.h>
|
||
|
|
||
|
using ::android::hardware::camera::device::V3_2::Stream;
|
||
|
using ::android::hardware::graphics::common::V1_0::PixelFormat;
|
||
|
|
||
|
|
||
|
typedef struct {
|
||
|
int32_t id;
|
||
|
int32_t width;
|
||
|
int32_t height;
|
||
|
int32_t format;
|
||
|
int32_t direction;
|
||
|
int32_t framerate;
|
||
|
} RawStreamConfig;
|
||
|
|
||
|
const size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t);
|
||
|
|
||
|
|
||
|
RenderDirectView::RenderDirectView(sp<IEvsEnumerator> enumerator,
|
||
|
const CameraDesc& camDesc,
|
||
|
const ConfigManager& config) :
|
||
|
mEnumerator(enumerator),
|
||
|
mCameraDesc(camDesc),
|
||
|
mConfig(config) {
|
||
|
// Find and store the target camera configuration
|
||
|
const auto& camList = mConfig.getCameras();
|
||
|
const auto target = std::find_if(camList.begin(), camList.end(),
|
||
|
[this](const ConfigManager::CameraInfo& info) {
|
||
|
return info.cameraId == mCameraDesc.v1.cameraId;
|
||
|
});
|
||
|
if (target != camList.end()) {
|
||
|
// Store the info
|
||
|
mCameraInfo = *target;
|
||
|
|
||
|
// Calculate a rotation matrix
|
||
|
float sinRoll, cosRoll;
|
||
|
sincosf(mCameraInfo.roll, &sinRoll, &cosRoll);
|
||
|
mRotationMat = {cosRoll, -sinRoll, sinRoll, cosRoll};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
bool RenderDirectView::activate() {
|
||
|
// Ensure GL is ready to go...
|
||
|
if (!prepareGL()) {
|
||
|
LOG(ERROR) << "Error initializing GL";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Load our shader program if we don't have it already
|
||
|
if (!mShaderProgram) {
|
||
|
mShaderProgram = buildShaderProgram(vtxShader_simpleTexture,
|
||
|
pixShader_simpleTexture,
|
||
|
"simpleTexture");
|
||
|
if (!mShaderProgram) {
|
||
|
LOG(ERROR) << "Error building shader program";
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool foundCfg = false;
|
||
|
std::unique_ptr<Stream> targetCfg(new Stream());
|
||
|
|
||
|
if (!foundCfg) {
|
||
|
// This logic picks the first configuration in the list among them that
|
||
|
// support RGBA8888 format and its frame rate is faster than minReqFps.
|
||
|
const int32_t minReqFps = 15;
|
||
|
int32_t maxArea = 0;
|
||
|
camera_metadata_entry_t streamCfgs;
|
||
|
if (!find_camera_metadata_entry(
|
||
|
reinterpret_cast<camera_metadata_t *>(mCameraDesc.metadata.data()),
|
||
|
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
|
||
|
&streamCfgs)) {
|
||
|
// Stream configurations are found in metadata
|
||
|
RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
|
||
|
for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
|
||
|
if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
|
||
|
ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
|
||
|
|
||
|
if (ptr->framerate >= minReqFps &&
|
||
|
ptr->width * ptr->height > maxArea) {
|
||
|
targetCfg->id = ptr->id;
|
||
|
targetCfg->width = ptr->width;
|
||
|
targetCfg->height = ptr->height;
|
||
|
|
||
|
maxArea = ptr->width * ptr->height;
|
||
|
|
||
|
foundCfg = true;
|
||
|
}
|
||
|
}
|
||
|
++ptr;
|
||
|
}
|
||
|
} else {
|
||
|
LOG(WARNING) << "No stream configuration data is found; "
|
||
|
<< "default parameters will be used.";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// This client always wants below input data format
|
||
|
targetCfg->format =
|
||
|
static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
|
||
|
|
||
|
// Construct our video texture
|
||
|
mTexture.reset(createVideoTexture(mEnumerator,
|
||
|
mCameraDesc.v1.cameraId.c_str(),
|
||
|
foundCfg ? std::move(targetCfg) : nullptr,
|
||
|
sDisplay,
|
||
|
mConfig.getUseExternalMemory(),
|
||
|
mConfig.getExternalMemoryFormat()));
|
||
|
if (!mTexture) {
|
||
|
LOG(ERROR) << "Failed to set up video texture for " << mCameraDesc.v1.cameraId;
|
||
|
// TODO: For production use, we may actually want to fail in this case, but not yet...
|
||
|
// return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
void RenderDirectView::deactivate() {
|
||
|
// Release our video texture
|
||
|
// We can't hold onto it because some other Render object might need the same camera
|
||
|
// TODO(b/131492626): investigate whether sharing video textures can save
|
||
|
// the time.
|
||
|
mTexture = nullptr;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool RenderDirectView::drawFrame(const BufferDesc& tgtBuffer) {
|
||
|
// Tell GL to render to the given buffer
|
||
|
if (!attachRenderTarget(tgtBuffer)) {
|
||
|
LOG(ERROR) << "Failed to attached render target";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Select our screen space simple texture shader
|
||
|
glUseProgram(mShaderProgram);
|
||
|
|
||
|
// Set up the model to clip space transform (identity matrix if we're modeling in screen space)
|
||
|
android::vec2 leftTop = {-0.5f, 0.5f};
|
||
|
android::vec2 rightTop = {0.5f, 0.5f};
|
||
|
android::vec2 leftBottom = {-0.5f, -0.5f};
|
||
|
android::vec2 rightBottom = {0.5f, -0.5f};
|
||
|
GLint loc = glGetUniformLocation(mShaderProgram, "cameraMat");
|
||
|
if (loc < 0) {
|
||
|
LOG(ERROR) << "Couldn't set shader parameter 'cameraMat'";
|
||
|
return false;
|
||
|
} else {
|
||
|
const android::mat4 identityMatrix;
|
||
|
glUniformMatrix4fv(loc, 1, false, identityMatrix.asArray());
|
||
|
|
||
|
// Rotate the preview
|
||
|
leftTop = mRotationMat * leftTop;
|
||
|
leftBottom = mRotationMat * leftBottom;
|
||
|
rightTop = mRotationMat * rightTop;
|
||
|
rightBottom = mRotationMat * rightBottom;
|
||
|
}
|
||
|
|
||
|
// Bind the texture and assign it to the shader's sampler
|
||
|
mTexture->refresh();
|
||
|
glActiveTexture(GL_TEXTURE0);
|
||
|
glBindTexture(GL_TEXTURE_2D, mTexture->glId());
|
||
|
|
||
|
|
||
|
GLint sampler = glGetUniformLocation(mShaderProgram, "tex");
|
||
|
if (sampler < 0) {
|
||
|
LOG(ERROR) << "Couldn't set shader parameter 'tex'";
|
||
|
return false;
|
||
|
} else {
|
||
|
// Tell the sampler we looked up from the shader to use texture slot 0 as its source
|
||
|
glUniform1i(sampler, 0);
|
||
|
}
|
||
|
|
||
|
// We want our image to show up opaque regardless of alpha values
|
||
|
glDisable(GL_BLEND);
|
||
|
|
||
|
|
||
|
// Draw a rectangle on the screen
|
||
|
GLfloat vertsCarPos[] = { -1.0, 1.0, 0.0f, // left top in window space
|
||
|
1.0, 1.0, 0.0f, // right top
|
||
|
-1.0, -1.0, 0.0f, // left bottom
|
||
|
1.0, -1.0, 0.0f // right bottom
|
||
|
};
|
||
|
|
||
|
// Flip the preview if needed
|
||
|
if (mCameraInfo.hflip) {
|
||
|
std::swap(leftTop.x, rightTop.x);
|
||
|
std::swap(leftBottom.x, rightBottom.x);
|
||
|
}
|
||
|
|
||
|
if (mCameraInfo.vflip) {
|
||
|
std::swap(leftTop.y, leftBottom.y);
|
||
|
std::swap(rightTop.y, rightBottom.y);
|
||
|
}
|
||
|
|
||
|
GLfloat vertsCarTex[] = { leftTop.x + 0.5f, leftTop.y + 0.5f,
|
||
|
rightTop.x + 0.5f, rightTop.y + 0.5f,
|
||
|
leftBottom.x + 0.5f, leftBottom.y + 0.5f,
|
||
|
rightBottom.x + 0.5f, rightBottom.y + 0.5f
|
||
|
};
|
||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
|
||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
|
||
|
glEnableVertexAttribArray(0);
|
||
|
glEnableVertexAttribArray(1);
|
||
|
|
||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||
|
|
||
|
glDisableVertexAttribArray(0);
|
||
|
glDisableVertexAttribArray(1);
|
||
|
|
||
|
|
||
|
// Now that everything is submitted, release our hold on the texture resource
|
||
|
detachRenderTarget();
|
||
|
|
||
|
// Wait for the rendering to finish
|
||
|
glFinish();
|
||
|
detachRenderTarget();
|
||
|
return true;
|
||
|
}
|