fix [2931513] Add support for setting the orientation of an ANativeWindow
Also implement support for cropping. Change-Id: Iba5888dd242bf2feaac9e9ce26e404c1f404c280
This commit is contained in:
parent
af2ac558a4
commit
b661d66013
|
@ -54,11 +54,6 @@ class SharedClient;
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// 4 * (11 + 7 + (1 + 2*NUM_RECT_MAX) * NUM_BUFFER_MAX) * NUM_LAYERS_MAX
|
||||
// 4 * (11 + 7 + (1 + 2*7)*16) * 31
|
||||
// 1032 * 31
|
||||
// = ~27 KiB (31992)
|
||||
|
||||
class SharedBufferStack
|
||||
{
|
||||
friend class SharedClient;
|
||||
|
@ -85,7 +80,7 @@ public:
|
|||
};
|
||||
|
||||
struct FlatRegion { // 52 bytes = 4 * (1 + 2*N)
|
||||
static const unsigned int NUM_RECT_MAX = 6;
|
||||
static const unsigned int NUM_RECT_MAX = 5;
|
||||
uint32_t count;
|
||||
SmallRect rects[NUM_RECT_MAX];
|
||||
};
|
||||
|
@ -93,13 +88,18 @@ public:
|
|||
struct BufferData {
|
||||
FlatRegion dirtyRegion;
|
||||
SmallRect crop;
|
||||
uint8_t transform;
|
||||
uint8_t reserved[3];
|
||||
};
|
||||
|
||||
SharedBufferStack();
|
||||
void init(int32_t identity);
|
||||
status_t setDirtyRegion(int buffer, const Region& reg);
|
||||
status_t setCrop(int buffer, const Rect& reg);
|
||||
status_t setTransform(int buffer, uint8_t transform);
|
||||
Region getDirtyRegion(int buffer) const;
|
||||
Rect getCrop(int buffer) const;
|
||||
uint32_t getTransform(int buffer) const;
|
||||
|
||||
// these attributes are part of the conditions/updates
|
||||
volatile int32_t head; // server's current front buffer
|
||||
|
@ -117,7 +117,7 @@ public:
|
|||
int32_t reserved32[1];
|
||||
Statistics stats;
|
||||
int32_t reserved;
|
||||
BufferData buffers[NUM_BUFFER_MAX]; // 960 bytes
|
||||
BufferData buffers[NUM_BUFFER_MAX]; // 1024 bytes
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -206,7 +206,7 @@ public:
|
|||
bool needNewBuffer(int buffer) const;
|
||||
status_t setDirtyRegion(int buffer, const Region& reg);
|
||||
status_t setCrop(int buffer, const Rect& reg);
|
||||
|
||||
status_t setTransform(int buffer, uint32_t transform);
|
||||
|
||||
class SetBufferCountCallback {
|
||||
friend class SharedBufferClient;
|
||||
|
@ -275,6 +275,8 @@ public:
|
|||
status_t reallocateAllExcept(int buffer);
|
||||
int32_t getQueuedCount() const;
|
||||
Region getDirtyRegion(int buffer) const;
|
||||
Rect getCrop(int buffer) const;
|
||||
uint32_t getTransform(int buffer) const;
|
||||
|
||||
status_t resize(int newNumBuffers);
|
||||
|
||||
|
|
|
@ -216,6 +216,7 @@ private:
|
|||
int dispatch_crop(va_list args);
|
||||
int dispatch_set_buffer_count(va_list args);
|
||||
int dispatch_set_buffers_geometry(va_list args);
|
||||
int dispatch_set_buffers_transform(va_list args);
|
||||
|
||||
void setUsage(uint32_t reqUsage);
|
||||
int connect(int api);
|
||||
|
@ -223,6 +224,7 @@ private:
|
|||
int crop(Rect const* rect);
|
||||
int setBufferCount(int bufferCount);
|
||||
int setBuffersGeometry(int w, int h, int format);
|
||||
int setBuffersTransform(int transform);
|
||||
|
||||
/*
|
||||
* private stuff...
|
||||
|
@ -278,6 +280,7 @@ private:
|
|||
Rect mSwapRectangle;
|
||||
int mConnected;
|
||||
Rect mNextBufferCrop;
|
||||
uint32_t mNextBufferTransform;
|
||||
BufferInfo mBufferInfo;
|
||||
|
||||
// protected by mSurfaceLock. These are also used from lock/unlock
|
||||
|
|
|
@ -85,6 +85,7 @@ enum {
|
|||
NATIVE_WINDOW_SET_CROP,
|
||||
NATIVE_WINDOW_SET_BUFFER_COUNT,
|
||||
NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
|
||||
NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
|
||||
};
|
||||
|
||||
/* parameter for NATIVE_WINDOW_[DIS]CONNECT */
|
||||
|
@ -92,6 +93,20 @@ enum {
|
|||
NATIVE_WINDOW_API_EGL = 1
|
||||
};
|
||||
|
||||
/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
|
||||
enum {
|
||||
/* flip source image horizontally */
|
||||
NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
|
||||
/* flip source image vertically */
|
||||
NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
|
||||
/* rotate source image 90 degrees clock-wise */
|
||||
NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
|
||||
/* rotate source image 180 degrees */
|
||||
NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
|
||||
/* rotate source image 270 degrees clock-wise */
|
||||
NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
|
||||
};
|
||||
|
||||
struct ANativeWindow
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
|
@ -196,6 +211,7 @@ struct ANativeWindow
|
|||
* NATIVE_WINDOW_SET_CROP
|
||||
* NATIVE_WINDOW_SET_BUFFER_COUNT
|
||||
* NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
|
||||
* NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -298,6 +314,19 @@ static inline int native_window_set_buffers_geometry(
|
|||
w, h, format);
|
||||
}
|
||||
|
||||
/*
|
||||
* native_window_set_buffers_transform(..., int transform)
|
||||
* All buffers queued after this call will be displayed transformed according
|
||||
* to the transform parameter specified.
|
||||
*/
|
||||
static inline int native_window_set_buffers_transform(
|
||||
ANativeWindow* window,
|
||||
int transform)
|
||||
{
|
||||
return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
|
||||
transform);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* FIXME: this is legacy for pixmaps */
|
||||
|
|
|
@ -75,6 +75,14 @@ status_t SharedBufferStack::setCrop(int buffer, const Rect& crop)
|
|||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t SharedBufferStack::setTransform(int buffer, uint8_t transform)
|
||||
{
|
||||
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
|
||||
return BAD_INDEX;
|
||||
buffers[buffer].transform = transform;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
|
||||
{
|
||||
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
|
||||
|
@ -137,6 +145,26 @@ Region SharedBufferStack::getDirtyRegion(int buffer) const
|
|||
return res;
|
||||
}
|
||||
|
||||
Rect SharedBufferStack::getCrop(int buffer) const
|
||||
{
|
||||
Rect res(-1, -1);
|
||||
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
|
||||
return res;
|
||||
res.left = buffers[buffer].crop.l;
|
||||
res.top = buffers[buffer].crop.t;
|
||||
res.right = buffers[buffer].crop.r;
|
||||
res.bottom = buffers[buffer].crop.b;
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t SharedBufferStack::getTransform(int buffer) const
|
||||
{
|
||||
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
|
||||
return 0;
|
||||
return buffers[buffer].transform;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
|
||||
|
@ -433,6 +461,12 @@ status_t SharedBufferClient::setCrop(int buf, const Rect& crop)
|
|||
return stack.setCrop(buf, crop);
|
||||
}
|
||||
|
||||
status_t SharedBufferClient::setTransform(int buf, uint32_t transform)
|
||||
{
|
||||
SharedBufferStack& stack( *mSharedStack );
|
||||
return stack.setTransform(buf, uint8_t(transform));
|
||||
}
|
||||
|
||||
status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg)
|
||||
{
|
||||
SharedBufferStack& stack( *mSharedStack );
|
||||
|
@ -549,6 +583,18 @@ Region SharedBufferServer::getDirtyRegion(int buf) const
|
|||
return stack.getDirtyRegion(buf);
|
||||
}
|
||||
|
||||
Rect SharedBufferServer::getCrop(int buf) const
|
||||
{
|
||||
SharedBufferStack& stack( *mSharedStack );
|
||||
return stack.getCrop(buf);
|
||||
}
|
||||
|
||||
uint32_t SharedBufferServer::getTransform(int buf) const
|
||||
{
|
||||
SharedBufferStack& stack( *mSharedStack );
|
||||
return stack.getTransform(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: this is not thread-safe on the server-side, meaning
|
||||
* 'head' cannot move during this operation. The client-side
|
||||
|
|
|
@ -422,8 +422,10 @@ void Surface::init()
|
|||
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
|
||||
const_cast<uint32_t&>(ANativeWindow::flags) = 0;
|
||||
|
||||
mNextBufferTransform = 0;
|
||||
mConnected = 0;
|
||||
mSwapRectangle.makeInvalid();
|
||||
mNextBufferCrop = Rect(0,0);
|
||||
// two buffers by default
|
||||
mBuffers.setCapacity(2);
|
||||
mBuffers.insertAt(0, 2);
|
||||
|
@ -631,6 +633,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer)
|
|||
}
|
||||
|
||||
int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
|
||||
mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
|
||||
mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
|
||||
mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
|
||||
err = mSharedBufferClient->queue(bufIdx);
|
||||
|
@ -685,6 +688,9 @@ int Surface::perform(int operation, va_list args)
|
|||
case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
|
||||
res = dispatch_set_buffers_geometry( args );
|
||||
break;
|
||||
case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
|
||||
res = dispatch_set_buffers_transform( args );
|
||||
break;
|
||||
default:
|
||||
res = NAME_NOT_FOUND;
|
||||
break;
|
||||
|
@ -719,6 +725,11 @@ int Surface::dispatch_set_buffers_geometry(va_list args) {
|
|||
return setBuffersGeometry(w, h, f);
|
||||
}
|
||||
|
||||
int Surface::dispatch_set_buffers_transform(va_list args) {
|
||||
int transform = va_arg(args, int);
|
||||
return setBuffersTransform(transform);
|
||||
}
|
||||
|
||||
void Surface::setUsage(uint32_t reqUsage)
|
||||
{
|
||||
Mutex::Autolock _l(mSurfaceLock);
|
||||
|
@ -765,6 +776,10 @@ int Surface::disconnect(int api)
|
|||
|
||||
int Surface::crop(Rect const* rect)
|
||||
{
|
||||
// empty/invalid rects are not allowed
|
||||
if (rect->isEmpty())
|
||||
return BAD_VALUE;
|
||||
|
||||
Mutex::Autolock _l(mSurfaceLock);
|
||||
// TODO: validate rect size
|
||||
mNextBufferCrop = *rect;
|
||||
|
@ -804,6 +819,13 @@ int Surface::setBuffersGeometry(int w, int h, int format)
|
|||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int Surface::setBuffersTransform(int transform)
|
||||
{
|
||||
Mutex::Autolock _l(mSurfaceLock);
|
||||
mNextBufferTransform = transform;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int Surface::getConnectedApi() const
|
||||
|
|
|
@ -473,9 +473,9 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
|
|||
return;
|
||||
}
|
||||
|
||||
// get the dirty region
|
||||
sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
|
||||
if (newFrontBuffer != NULL) {
|
||||
// get the dirty region
|
||||
// compute the posted region
|
||||
const Region dirty(lcblk->getDirtyRegion(buf));
|
||||
mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
|
||||
|
@ -511,6 +511,13 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
|
|||
// we now have the correct size, unfreeze the screen
|
||||
mFreezeLock.clear();
|
||||
}
|
||||
|
||||
// get the crop region
|
||||
setBufferCrop( lcblk->getCrop(buf) );
|
||||
|
||||
// get the transformation
|
||||
setBufferTransform( lcblk->getTransform(buf) );
|
||||
|
||||
} else {
|
||||
// this should not happen unless we ran out of memory while
|
||||
// allocating the buffer. we're hoping that things will get back
|
||||
|
|
|
@ -54,6 +54,8 @@ LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
|
|||
{
|
||||
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
|
||||
mFlags = hw.getFlags();
|
||||
mBufferCrop.makeInvalid();
|
||||
mBufferTransform = 0;
|
||||
}
|
||||
|
||||
LayerBase::~LayerBase()
|
||||
|
@ -345,6 +347,14 @@ void LayerBase::clearWithOpenGL(const Region& clip) const
|
|||
clearWithOpenGL(clip,0,0,0,0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline
|
||||
void swap(T& a, T& b) {
|
||||
T t(a);
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
|
||||
void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
|
||||
{
|
||||
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
||||
|
@ -378,37 +388,72 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
|
|||
}
|
||||
}
|
||||
|
||||
Region::const_iterator it = clip.begin();
|
||||
Region::const_iterator const end = clip.end();
|
||||
const GLfloat texCoords[4][2] = {
|
||||
{ 0, 0 },
|
||||
{ 0, 1 },
|
||||
{ 1, 1 },
|
||||
{ 1, 0 }
|
||||
/*
|
||||
* compute texture coordinates
|
||||
* here, we handle NPOT, cropping and buffer transformations
|
||||
*/
|
||||
|
||||
GLfloat cl, ct, cr, cb;
|
||||
if (!mBufferCrop.isEmpty()) {
|
||||
// source is cropped
|
||||
const GLfloat us = (texture.NPOTAdjust ? texture.wScale : 1.0f) / width;
|
||||
const GLfloat vs = (texture.NPOTAdjust ? texture.hScale : 1.0f) / height;
|
||||
cl = mBufferCrop.left * us;
|
||||
ct = mBufferCrop.top * vs;
|
||||
cr = mBufferCrop.right * us;
|
||||
cb = mBufferCrop.bottom * vs;
|
||||
} else {
|
||||
cl = 0;
|
||||
ct = 0;
|
||||
cr = (texture.NPOTAdjust ? texture.wScale : 1.0f);
|
||||
cb = (texture.NPOTAdjust ? texture.hScale : 1.0f);
|
||||
}
|
||||
|
||||
struct TexCoords {
|
||||
GLfloat u;
|
||||
GLfloat v;
|
||||
};
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
enum {
|
||||
// name of the corners in the texture map
|
||||
LB = 0, // left-bottom
|
||||
LT = 1, // left-top
|
||||
RT = 2, // right-top
|
||||
RB = 3 // right-bottom
|
||||
};
|
||||
|
||||
// vertices in screen space
|
||||
int vLT = LB;
|
||||
int vLB = LT;
|
||||
int vRB = RT;
|
||||
int vRT = RB;
|
||||
|
||||
// the texture's source is rotated
|
||||
switch (texture.transform) {
|
||||
case HAL_TRANSFORM_ROT_90:
|
||||
glTranslatef(0, 1, 0);
|
||||
glRotatef(-90, 0, 0, 1);
|
||||
break;
|
||||
case HAL_TRANSFORM_ROT_180:
|
||||
glTranslatef(1, 1, 0);
|
||||
glRotatef(-180, 0, 0, 1);
|
||||
break;
|
||||
case HAL_TRANSFORM_ROT_270:
|
||||
glTranslatef(1, 0, 0);
|
||||
glRotatef(-270, 0, 0, 1);
|
||||
break;
|
||||
uint32_t transform = mBufferTransform;
|
||||
if (transform & HAL_TRANSFORM_ROT_90) {
|
||||
vLT = RB;
|
||||
vLB = LB;
|
||||
vRB = LT;
|
||||
vRT = RT;
|
||||
}
|
||||
if (transform & HAL_TRANSFORM_FLIP_V) {
|
||||
swap(vLT, vLB);
|
||||
swap(vRB, vRT);
|
||||
}
|
||||
if (transform & HAL_TRANSFORM_FLIP_H) {
|
||||
swap(vLT, vRB);
|
||||
swap(vLB, vRT);
|
||||
}
|
||||
|
||||
if (texture.NPOTAdjust) {
|
||||
glScalef(texture.wScale, texture.hScale, 1.0f);
|
||||
}
|
||||
TexCoords texCoords[4];
|
||||
texCoords[vLT].u = cl;
|
||||
texCoords[vLT].v = ct;
|
||||
texCoords[vLB].u = cl;
|
||||
texCoords[vLB].v = cb;
|
||||
texCoords[vRB].u = cr;
|
||||
texCoords[vRB].v = cb;
|
||||
texCoords[vRT].u = cr;
|
||||
texCoords[vRT].v = ct;
|
||||
|
||||
if (needsDithering()) {
|
||||
glEnable(GL_DITHER);
|
||||
|
@ -420,6 +465,8 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
|
|||
glVertexPointer(2, GL_FLOAT, 0, mVertices);
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
|
||||
|
||||
Region::const_iterator it = clip.begin();
|
||||
Region::const_iterator const end = clip.end();
|
||||
while (it != end) {
|
||||
const Rect& r = *it++;
|
||||
const GLint sy = fbHeight - (r.top + r.height());
|
||||
|
@ -429,6 +476,16 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
|
|||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
void LayerBase::setBufferCrop(const Rect& crop) {
|
||||
if (!crop.isEmpty()) {
|
||||
mBufferCrop = crop;
|
||||
}
|
||||
}
|
||||
|
||||
void LayerBase::setBufferTransform(uint32_t transform) {
|
||||
mBufferTransform = transform;
|
||||
}
|
||||
|
||||
void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
|
||||
{
|
||||
const Layer::State& s(drawingState());
|
||||
|
|
|
@ -226,9 +226,17 @@ protected:
|
|||
void clearWithOpenGL(const Region& clip) const;
|
||||
void drawWithOpenGL(const Region& clip, const Texture& texture) const;
|
||||
|
||||
// these must be called from the post/drawing thread
|
||||
void setBufferCrop(const Rect& crop);
|
||||
void setBufferTransform(uint32_t transform);
|
||||
|
||||
sp<SurfaceFlinger> mFlinger;
|
||||
uint32_t mFlags;
|
||||
|
||||
// post/drawing thread
|
||||
Rect mBufferCrop;
|
||||
uint32_t mBufferTransform;
|
||||
|
||||
// cached during validateVisibility()
|
||||
bool mNeedsFiltering;
|
||||
int32_t mOrientation;
|
||||
|
|
|
@ -241,6 +241,8 @@ void LayerBlur::onDraw(const Region& clip) const
|
|||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
}
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -485,7 +485,7 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
|
|||
mTextureManager.loadTexture(&mTexture, dirty, t);
|
||||
}
|
||||
|
||||
mTexture.transform = mBufferHeap.transform;
|
||||
mLayer.setBufferTransform(mBufferHeap.transform);
|
||||
mLayer.drawWithOpenGL(clip, mTexture);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,12 +40,11 @@ class GraphicBuffer;
|
|||
struct Image {
|
||||
enum { TEXTURE_2D=0, TEXTURE_EXTERNAL=1 };
|
||||
Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0),
|
||||
transform(0), dirty(1), target(TEXTURE_2D) { }
|
||||
dirty(1), target(TEXTURE_2D) { }
|
||||
GLuint name;
|
||||
EGLImageKHR image;
|
||||
GLuint width;
|
||||
GLuint height;
|
||||
uint32_t transform;
|
||||
unsigned dirty : 1;
|
||||
unsigned target : 1;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue