<commit_before>/***********************************************************************
    created:    Wed, 8th Feb 2012
    author:     Lukas E Meindl (based on code by Paul D Turner)
                David Reepmeyer (added GLES2/GLES3)
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2012 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/RendererModules/OpenGL/GLES2FBOTextureTarget.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/RenderQueue.h"
#include "CEGUI/GeometryBuffer.h"

#include "CEGUI/RendererModules/OpenGL/GLES2Renderer.h"
#include "CEGUI/RendererModules/OpenGL/Texture.h"
#include "CEGUI/RendererModules/OpenGL/StateChangeWrapper.h"

#include "CEGUI/Logger.h"

#include <sstream>
#include <iostream>

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
const float GLES2FBOTextureTarget::DEFAULT_SIZE = 128.0f;

//----------------------------------------------------------------------------//
GLES2FBOTextureTarget::GLES2FBOTextureTarget(GLES2Renderer& owner) :
    OpenGLTextureTarget(owner),
    d_glStateChanger(owner.getOpenGLStateChanger())
{
    // no need to initialise d_previousFrameBuffer here, it will be
    // initialised in activate()

    initialiseRenderTexture();

    // setup area and cause the initial texture to be generated.
    declareRenderSize(Sizef(DEFAULT_SIZE, DEFAULT_SIZE));
}

//----------------------------------------------------------------------------//
GLES2FBOTextureTarget::~GLES2FBOTextureTarget()
{
    glDeleteFramebuffers(1, &d_frameBuffer);

    glDeleteRenderbuffers(1, &d_stencilBufferRBO);
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::declareRenderSize(const Sizef& sz)
{
    setArea(Rectf(d_area.getPosition(), d_owner.getAdjustedTextureSize(sz)));
    resizeRenderTexture();
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::activate()
{
    // remember previously bound FBO to make sure we set it back
    // when deactivating
    glGetIntegerv(GL_FRAMEBUFFER_BINDING,
            reinterpret_cast<GLint*>(&d_previousFrameBuffer));

    // switch to rendering to the texture
    glBindFramebuffer(GL_FRAMEBUFFER, d_frameBuffer);

    OpenGLTextureTarget::activate();
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::deactivate()
{
    OpenGLTextureTarget::deactivate();

    // switch back to rendering to the previously bound framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, d_previousFrameBuffer);
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::clear()
{
    const Sizef sz(d_area.getSize());
    // Some drivers crash when clearing a 0x0 RTT. This is a workaround for
    // those cases.
    if (sz.d_width < 1.0f || sz.d_height < 1.0f)
        return;

    // save old clear colour
    GLfloat old_col[4];
    glGetFloatv(GL_COLOR_CLEAR_VALUE, old_col);

    // remember previously bound FBO to make sure we set it back
    GLuint previousFBO = 0;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING,
            reinterpret_cast<GLint*>(&previousFBO));

    // switch to our FBO
    glBindFramebuffer(GL_FRAMEBUFFER, d_frameBuffer);
    // Clear it.
    d_glStateChanger->disable(GL_SCISSOR_TEST);
    glClearColor(0,0,0,0);

    if(!d_usesStencil)
        glClear(GL_COLOR_BUFFER_BIT);
    else
        glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    // switch back to rendering to the previously bound FBO
    glBindFramebuffer(GL_FRAMEBUFFER, previousFBO);

    // restore previous clear colour
    glClearColor(old_col[0], old_col[1], old_col[2], old_col[3]);
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::initialiseRenderTexture()
{
    // save old texture binding
    GLuint old_tex;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast<GLint*>(&old_tex));

    // create FBO
    glGenFramebuffers(1, &d_frameBuffer);

#ifndef __ANDROID__
    // remember previously bound FBO to make sure we set it back
    GLuint previousFBO = 0;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT,
            reinterpret_cast<GLint*>(&previousFBO));
#endif
    glBindFramebuffer(GL_FRAMEBUFFER, d_frameBuffer);

    // set up the texture the FBO will draw to
    glGenTextures(1, &d_texture);
    d_glStateChanger->bindTexture(GL_TEXTURE_2D, d_texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#ifdef CEGUI_GLES3_SUPPORT
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
#else
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
#endif
                 static_cast<GLsizei>(DEFAULT_SIZE),
                 static_cast<GLsizei>(DEFAULT_SIZE),
                 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                              GL_TEXTURE_2D, d_texture, 0);

    // Set up the stencil buffer for the FBO
    glGenRenderbuffers(1, &d_stencilBufferRBO);
    glBindRenderbuffer(GL_RENDERBUFFER, d_stencilBufferRBO);
    glRenderbufferStorage(GL_RENDERBUFFER,
                          GL_STENCIL_INDEX8,
                          static_cast<GLsizei>(DEFAULT_SIZE),
                          static_cast<GLsizei>(DEFAULT_SIZE));
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                              GL_RENDERBUFFER, d_stencilBufferRBO);

    //Check for framebuffer completeness
    checkFramebufferStatus();

#ifndef __ANDROID__
    // switch from our frame buffer back to the previously bound buffer.
    glBindFramebuffer(GL_FRAMEBUFFER, previousFBO);
#endif

    // ensure the CEGUI::Texture is wrapping the gl texture and has correct size
    d_CEGUITexture->setOpenGLTexture(d_texture, d_area.getSize());

    // restore previous texture binding.
    d_glStateChanger->bindTexture(GL_TEXTURE_2D, old_tex);
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::resizeRenderTexture()
{
    // save old texture binding
    GLuint old_tex;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast<GLint*>(&old_tex));

    // Some drivers (hint: Intel) segfault when glTexImage2D is called with
    // any of the dimensions being 0. The downside of this workaround is very
    // small. We waste a tiny bit of VRAM on cards with sane drivers and
    // prevent insane drivers from crashing CEGUI.
    Sizef sz(d_area.getSize());
    if (sz.d_width < 1.0f || sz.d_height < 1.0f)
    {
        sz.d_width = 1.0f;
        sz.d_height = 1.0f;
    }

    // set the texture to the required size
    d_glStateChanger->bindTexture(GL_TEXTURE_2D, d_texture);
#ifdef CEGUI_GLES3_SUPPORT
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
#else
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
#endif
                 static_cast<GLsizei>(sz.d_width),
                 static_cast<GLsizei>(sz.d_height),
                 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

    glBindRenderbuffer(GL_RENDERBUFFER, d_stencilBufferRBO);
    glRenderbufferStorage(GL_RENDERBUFFER,
                          GL_STENCIL_INDEX8,
                          static_cast<GLsizei>(sz.d_width),
                          static_cast<GLsizei>(sz.d_height));

    clear();

    // ensure the CEGUI::Texture is wrapping the gl texture and has correct size
    d_CEGUITexture->setOpenGLTexture(d_texture, sz);

    // restore previous texture binding.
    d_glStateChanger->bindTexture(GL_TEXTURE_2D, old_tex);
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::grabTexture()
{
    glDeleteFramebuffers(1, &d_frameBuffer);
    d_frameBuffer = 0;

    OpenGLTextureTarget::grabTexture();
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::restoreTexture()
{
    OpenGLTextureTarget::restoreTexture();

    initialiseRenderTexture();
    resizeRenderTexture();
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::checkFramebufferStatus()
{
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

    // Check for completeness
    if(status != GL_FRAMEBUFFER_COMPLETE)
    {
        std::stringstream stringStream;
        stringStream << "GLES2Renderer: Error  Framebuffer is not complete\n";

        switch(status)
        {
        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
            stringStream << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT\n";
            break;
#ifdef CEGUI_GLES3_SUPPORT
        case GL_FRAMEBUFFER_UNDEFINED:
            stringStream << "GL_FRAMEBUFFER_UNDEFINED\n";
            break;
#endif
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
            stringStream << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT\n";
            break;
#ifndef __ANDROID__
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER :
            stringStream << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER\n";
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
            stringStream << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER\n";
            break;
#endif
#ifdef CEGUI_GLES3_SUPPORT
        case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
            stringStream << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE\n";
            break;
#endif
        case GL_FRAMEBUFFER_UNSUPPORTED:
            stringStream << "GL_FRAMEBUFFER_UNSUPPORTED\n";
            break;
        default:
            stringStream << "Undefined Framebuffer error\n";
            break;
        }

        if (CEGUI::Logger* logger = CEGUI::Logger::getSingletonPtr())
            logger->logEvent(stringStream.str().c_str());
        else
            std::cerr << stringStream.str() << std::endl;
    }
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section
<commit_msg>cleanup for initialiseRenderTexture<commit_after>/***********************************************************************
    created:    Wed, 8th Feb 2012
    author:     Lukas E Meindl (based on code by Paul D Turner)
                David Reepmeyer (added GLES2/GLES3)
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2012 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/RendererModules/OpenGL/GLES2FBOTextureTarget.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/RenderQueue.h"
#include "CEGUI/GeometryBuffer.h"

#include "CEGUI/RendererModules/OpenGL/GLES2Renderer.h"
#include "CEGUI/RendererModules/OpenGL/Texture.h"
#include "CEGUI/RendererModules/OpenGL/StateChangeWrapper.h"

#include "CEGUI/Logger.h"

#include <sstream>
#include <iostream>

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
const float GLES2FBOTextureTarget::DEFAULT_SIZE = 128.0f;

//----------------------------------------------------------------------------//
GLES2FBOTextureTarget::GLES2FBOTextureTarget(GLES2Renderer& owner) :
    OpenGLTextureTarget(owner),
    d_glStateChanger(owner.getOpenGLStateChanger())
{
    // no need to initialise d_previousFrameBuffer here, it will be
    // initialised in activate()

    initialiseRenderTexture();

    // setup area and cause the initial texture to be generated.
    declareRenderSize(Sizef(DEFAULT_SIZE, DEFAULT_SIZE));
}

//----------------------------------------------------------------------------//
GLES2FBOTextureTarget::~GLES2FBOTextureTarget()
{
    glDeleteFramebuffers(1, &d_frameBuffer);

    glDeleteRenderbuffers(1, &d_stencilBufferRBO);
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::declareRenderSize(const Sizef& sz)
{
    setArea(Rectf(d_area.getPosition(), d_owner.getAdjustedTextureSize(sz)));
    resizeRenderTexture();
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::activate()
{
    // remember previously bound FBO to make sure we set it back
    // when deactivating
    glGetIntegerv(GL_FRAMEBUFFER_BINDING,
            reinterpret_cast<GLint*>(&d_previousFrameBuffer));

    // switch to rendering to the texture
    glBindFramebuffer(GL_FRAMEBUFFER, d_frameBuffer);

    OpenGLTextureTarget::activate();
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::deactivate()
{
    OpenGLTextureTarget::deactivate();

    // switch back to rendering to the previously bound framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, d_previousFrameBuffer);
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::clear()
{
    const Sizef sz(d_area.getSize());
    // Some drivers crash when clearing a 0x0 RTT. This is a workaround for
    // those cases.
    if (sz.d_width < 1.0f || sz.d_height < 1.0f)
        return;

    // save old clear colour
    GLfloat old_col[4];
    glGetFloatv(GL_COLOR_CLEAR_VALUE, old_col);

    // remember previously bound FBO to make sure we set it back
    GLuint previousFBO = 0;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING,
            reinterpret_cast<GLint*>(&previousFBO));

    // switch to our FBO
    glBindFramebuffer(GL_FRAMEBUFFER, d_frameBuffer);
    // Clear it.
    d_glStateChanger->disable(GL_SCISSOR_TEST);
    glClearColor(0,0,0,0);

    if(!d_usesStencil)
        glClear(GL_COLOR_BUFFER_BIT);
    else
        glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    // switch back to rendering to the previously bound FBO
    glBindFramebuffer(GL_FRAMEBUFFER, previousFBO);

    // restore previous clear colour
    glClearColor(old_col[0], old_col[1], old_col[2], old_col[3]);
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::initialiseRenderTexture()
{
    // save old texture binding
    GLuint old_tex;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast<GLint*>(&old_tex));

    // create FBO
    glGenFramebuffers(1, &d_frameBuffer);

    // remember previously bound FBO to make sure we set it back
    GLuint previousFBO = 0;
    //glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT,
    glGetIntegerv(GL_FRAMEBUFFER_BINDING,
            reinterpret_cast<GLint*>(&previousFBO));
    glBindFramebuffer(GL_FRAMEBUFFER, d_frameBuffer);

    // set up the texture the FBO will draw to
    glGenTextures(1, &d_texture);
    d_glStateChanger->bindTexture(GL_TEXTURE_2D, d_texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#ifdef CEGUI_GLES3_SUPPORT
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
#else
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
#endif
                 static_cast<GLsizei>(DEFAULT_SIZE),
                 static_cast<GLsizei>(DEFAULT_SIZE),
                 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                              GL_TEXTURE_2D, d_texture, 0);

    // Set up the stencil buffer for the FBO
    glGenRenderbuffers(1, &d_stencilBufferRBO);
    glBindRenderbuffer(GL_RENDERBUFFER, d_stencilBufferRBO);
    glRenderbufferStorage(GL_RENDERBUFFER,
                          GL_STENCIL_INDEX8,
                          static_cast<GLsizei>(DEFAULT_SIZE),
                          static_cast<GLsizei>(DEFAULT_SIZE));
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                              GL_RENDERBUFFER, d_stencilBufferRBO);

    //Check for framebuffer completeness
    checkFramebufferStatus();

    // switch from our frame buffer back to the previously bound buffer.
    glBindFramebuffer(GL_FRAMEBUFFER, previousFBO);

    // ensure the CEGUI::Texture is wrapping the gl texture and has correct size
    d_CEGUITexture->setOpenGLTexture(d_texture, d_area.getSize());

    // restore previous texture binding.
    d_glStateChanger->bindTexture(GL_TEXTURE_2D, old_tex);
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::resizeRenderTexture()
{
    // save old texture binding
    GLuint old_tex;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast<GLint*>(&old_tex));

    // Some drivers (hint: Intel) segfault when glTexImage2D is called with
    // any of the dimensions being 0. The downside of this workaround is very
    // small. We waste a tiny bit of VRAM on cards with sane drivers and
    // prevent insane drivers from crashing CEGUI.
    Sizef sz(d_area.getSize());
    if (sz.d_width < 1.0f || sz.d_height < 1.0f)
    {
        sz.d_width = 1.0f;
        sz.d_height = 1.0f;
    }

    // set the texture to the required size
    d_glStateChanger->bindTexture(GL_TEXTURE_2D, d_texture);
#ifdef CEGUI_GLES3_SUPPORT
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
#else
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
#endif
                 static_cast<GLsizei>(sz.d_width),
                 static_cast<GLsizei>(sz.d_height),
                 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

    glBindRenderbuffer(GL_RENDERBUFFER, d_stencilBufferRBO);
    glRenderbufferStorage(GL_RENDERBUFFER,
                          GL_STENCIL_INDEX8,
                          static_cast<GLsizei>(sz.d_width),
                          static_cast<GLsizei>(sz.d_height));

    clear();

    // ensure the CEGUI::Texture is wrapping the gl texture and has correct size
    d_CEGUITexture->setOpenGLTexture(d_texture, sz);

    // restore previous texture binding.
    d_glStateChanger->bindTexture(GL_TEXTURE_2D, old_tex);
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::grabTexture()
{
    glDeleteFramebuffers(1, &d_frameBuffer);
    d_frameBuffer = 0;

    OpenGLTextureTarget::grabTexture();
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::restoreTexture()
{
    OpenGLTextureTarget::restoreTexture();

    initialiseRenderTexture();
    resizeRenderTexture();
}

//----------------------------------------------------------------------------//
void GLES2FBOTextureTarget::checkFramebufferStatus()
{
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

    // Check for completeness
    if(status != GL_FRAMEBUFFER_COMPLETE)
    {
        std::stringstream stringStream;
        stringStream << "GLES2Renderer: Error  Framebuffer is not complete\n";

        switch(status)
        {
        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
            stringStream << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT\n";
            break;
#ifdef CEGUI_GLES3_SUPPORT
        case GL_FRAMEBUFFER_UNDEFINED:
            stringStream << "GL_FRAMEBUFFER_UNDEFINED\n";
            break;
#endif
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
            stringStream << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT\n";
            break;
#ifndef __ANDROID__
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER :
            stringStream << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER\n";
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
            stringStream << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER\n";
            break;
#endif
#ifdef CEGUI_GLES3_SUPPORT
        case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
            stringStream << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE\n";
            break;
#endif
        case GL_FRAMEBUFFER_UNSUPPORTED:
            stringStream << "GL_FRAMEBUFFER_UNSUPPORTED\n";
            break;
        default:
            stringStream << "Undefined Framebuffer error\n";
            break;
        }

        if (CEGUI::Logger* logger = CEGUI::Logger::getSingletonPtr())
            logger->logEvent(stringStream.str().c_str());
        else
            std::cerr << stringStream.str() << std::endl;
    }
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>#include <stdexcept>
#include "FractalGenerator.h"
#include "math_utils.h"

/*
 * Public member functions
 */

FractalGenerator::FractalGenerator(fractalId id, v8::Isolate *isolate,
		void (*doneCallback)(v8::Isolate *isolate,
				v8::Local<v8::Object> nodeBuffer, bool halted,
				void *doneCallbackData), v8::Local<v8::Object> buf,
		void *doneCallbackData, int width, int height, double fractalWidth,
		double fractalHeight, double fracgtalX, double fractalY, int iterations) :
		id(id), doneCallback(doneCallback), doneCallbackData(doneCallbackData), width(
				width), height(height), fractalWidth(fractalWidth), fractalHeight(
				fractalHeight), fractalX(fractalX), fractalY(fractalY), iterations(
				iterations) {
	if (buf->IsNull() || buf->IsUndefined()
			|| node::Buffer::Length(buf) < (width * height * 4)) {
		buf = Nan::NewBuffer(width * height * 4);
	}

	nodeBuffer = new v8::Global<v8::Object>;
	nodeBuffer->Reset(isolate, buf);
	buffer = node::Buffer::Data(buf);

	doneAsync = new uv_async_t;
	doneAsync->data = this;
	uv_loop_t *loop = uv_default_loop();
	uv_async_init(loop, doneAsync, doneAsyncCallback);
}

FractalGenerator::~FractalGenerator() {
	nodeBuffer->Reset();
	delete nodeBuffer;
	delete doneAsync;
}

void FractalGenerator::start() {
	thread = new std::thread(&FractalGenerator::threadFunction, this);
}

void FractalGenerator::halt() {
	halting.store(true);
}

int FractalGenerator::getProgress() {
	return progress.load();
}

bool FractalGenerator::isGenerating() {
	return generating.load();
}

/*
 * Private member functions
 */

void FractalGenerator::doneAsyncCallback(uv_async_t *handle) {
	FractalGenerator *self = ((FractalGenerator *) handle->data);
	v8::Isolate *isolate = v8::Isolate::GetCurrent();
	v8::HandleScope scope(isolate);
	(*self->doneCallback)(isolate, self->nodeBuffer->Get(isolate),
			self->halting.load(), self->doneCallbackData);
	self->nodeBuffer->Reset();
}

void FractalGenerator::threadFunction() {
	// build fractal here and call uv_async_send when done

	generating.store(true);
	progress.store(0);

	// does this make things faster or is this redundant with g++ optimization?
	float fx, fy, a, b, aa, bb, twoab;
	int x, y, i, n;
	RGBData color;

	for (y = 0; y < height; y++) {
		for (x = 0; x < width; x++) {
			if (halting.load()) {
				generating.store(false);
				uv_async_send(doneAsync);
				return;
			}

			// get buffer index
			i = x + y * width;

			// pixel value generation
			fx = x * fractalWidth / width + fractalX;
			fy = y * fractalHeight / height + fractalY;

			// z = (a + bi)
			a = fx;
			b = fy;

			for (n = 0; n < iterations; n++) {
				// z = z * z
				aa = a * a;
				bb = b * b;
				twoab = 2.0f * a * b;

				a = aa - bb + fx;
				b = twoab + fy;

				// if old sqrt(a * a + b * b) > 4
				// z is outside a circle with radius 4 in the complex plane
				if (aa + bb > 16) {
					break;
				}
			}

			// pixel coloring
			if (n < iterations) {
				// magic numbers
				color = fromHSB(mod2(n * 3.3f, 0, 256.0f) / 256.0f, 1.0f,
						mod2(n * 16.0f, 0, 256.0f) / 256.0f);
				buffer[i] = color.r;
				buffer[i + 1] = color.g;
				buffer[i + 2] = color.b;
				buffer[i + 3] = 0xFF;
			} else {
				buffer[i] = 0x00;
				buffer[i + 1] = 0x00;
				buffer[i + 2] = 0x00;
				buffer[i + 3] = 0xFF;
			}

			progress++;
		}
	}

	// set status
	generating.store(false);

	// send callback
	uv_async_send(doneAsync);
}
<commit_msg>Fix buffer type<commit_after>#include <stdexcept>
#include "FractalGenerator.h"
#include "math_utils.h"

/*
 * Public member functions
 */

FractalGenerator::FractalGenerator(fractalId id, v8::Isolate *isolate,
		void (*doneCallback)(v8::Isolate *isolate,
				v8::Local<v8::Object> nodeBuffer, bool halted,
				void *doneCallbackData), v8::Local<v8::Object> buf,
		void *doneCallbackData, int width, int height, double fractalWidth,
		double fractalHeight, double fracgtalX, double fractalY, int iterations) :
		id(id), doneCallback(doneCallback), doneCallbackData(doneCallbackData), width(
				width), height(height), fractalWidth(fractalWidth), fractalHeight(
				fractalHeight), fractalX(fractalX), fractalY(fractalY), iterations(
				iterations) {
	if (buf->IsNull() || buf->IsUndefined()
			|| node::Buffer::Length(buf) < (width * height * 4)) {
		buf = Nan::NewBuffer(width * height * 4).ToLocalChecked();
	}

	nodeBuffer = new v8::Global<v8::Object>;
	nodeBuffer->Reset(isolate, buf);
	buffer = node::Buffer::Data(buf);

	doneAsync = new uv_async_t;
	doneAsync->data = this;
	uv_loop_t *loop = uv_default_loop();
	uv_async_init(loop, doneAsync, doneAsyncCallback);
}

FractalGenerator::~FractalGenerator() {
	nodeBuffer->Reset();
	delete nodeBuffer;
	delete doneAsync;
}

void FractalGenerator::start() {
	thread = new std::thread(&FractalGenerator::threadFunction, this);
}

void FractalGenerator::halt() {
	halting.store(true);
}

int FractalGenerator::getProgress() {
	return progress.load();
}

bool FractalGenerator::isGenerating() {
	return generating.load();
}

/*
 * Private member functions
 */

void FractalGenerator::doneAsyncCallback(uv_async_t *handle) {
	FractalGenerator *self = ((FractalGenerator *) handle->data);
	v8::Isolate *isolate = v8::Isolate::GetCurrent();
	v8::HandleScope scope(isolate);
	(*self->doneCallback)(isolate, self->nodeBuffer->Get(isolate),
			self->halting.load(), self->doneCallbackData);
	self->nodeBuffer->Reset();
}

void FractalGenerator::threadFunction() {
	// build fractal here and call uv_async_send when done

	generating.store(true);
	progress.store(0);

	// does this make things faster or is this redundant with g++ optimization?
	float fx, fy, a, b, aa, bb, twoab;
	int x, y, i, n;
	RGBData color;

	for (y = 0; y < height; y++) {
		for (x = 0; x < width; x++) {
			if (halting.load()) {
				generating.store(false);
				uv_async_send(doneAsync);
				return;
			}

			// get buffer index
			i = x + y * width;

			// pixel value generation
			fx = x * fractalWidth / width + fractalX;
			fy = y * fractalHeight / height + fractalY;

			// z = (a + bi)
			a = fx;
			b = fy;

			for (n = 0; n < iterations; n++) {
				// z = z * z
				aa = a * a;
				bb = b * b;
				twoab = 2.0f * a * b;

				a = aa - bb + fx;
				b = twoab + fy;

				// if old sqrt(a * a + b * b) > 4
				// z is outside a circle with radius 4 in the complex plane
				if (aa + bb > 16) {
					break;
				}
			}

			// pixel coloring
			if (n < iterations) {
				// magic numbers
				color = fromHSB(mod2(n * 3.3f, 0, 256.0f) / 256.0f, 1.0f,
						mod2(n * 16.0f, 0, 256.0f) / 256.0f);
				buffer[i] = color.r;
				buffer[i + 1] = color.g;
				buffer[i + 2] = color.b;
				buffer[i + 3] = 0xFF;
			} else {
				buffer[i] = 0x00;
				buffer[i + 1] = 0x00;
				buffer[i + 2] = 0x00;
				buffer[i + 3] = 0xFF;
			}

			progress++;
		}
	}

	// set status
	generating.store(false);

	// send callback
	uv_async_send(doneAsync);
}
<|endoftext|>


<commit_before>/*
 * Tyrion
 * Copyright 2010, Silas Sewell
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "node_loop.h"
#include "node_utils.h"

namespace tyrion {

NodeLoop::NodeLoop() : BaseLoop() {
  track_ = 0;
}

NodeLoop* NodeLoop::instance_ = NULL;

NodeLoop* NodeLoop::Instance() {
  if (!instance_)
    instance_ = new NodeLoop;
  return instance_;
}

void NodeLoop::DoReload() {
  if (NodeReload()) {
    TLOG(INFO) << "Reloading...";
    Restart();
  } else {
    TLOG(WARNING) << "Unable to reload.";
  }
}

void NodeLoop::DoRequest(ServiceData* service) {
  if (track_ <= 10) {
    track_++;
    service->data()->set_retry(0);
    NodeServiceHandler *sh = new NodeServiceHandler(service->data());
    CreateThread(NodeLoop::DoRequestInThread, (void *)sh);
    delete service;
  } else {
    int retry = service->data()->Retry();
    PostDelayed(retry * 1000, this, MSG_REQUEST, service);
  }
}

void *NodeLoop::DoRequestInThread(void *arg) {
  NodeServiceHandler *handler=(NodeServiceHandler*)arg;
  handler->Run();
  delete handler;
  pthread_exit(NULL);
}

void NodeLoop::DoResponse(ServiceData* service) {
  if (state_ == RUNNING && pump_ != NULL &&
      pump_->client() != NULL &&
      pump_->client()->GetState() == txmpp::XmppEngine::STATE_OPEN) {
    track_--;
    const txmpp::XmlElement* iq = service->data()->Response();
    pump_->SendStanza(iq);
    delete iq;
    delete service->data();
    delete service;
  } else {
    int retry = service->data()->Retry();
    TLOG(WARNING) << "Retrying service response in " << retry << " seconds ("
                  << service->data()->id() << ")";
    PostDelayed(retry * 1000, this, MSG_RESPONSE, service);
  }
}

}  // namespace tyrion
<commit_msg>Double initial retry timeout<commit_after>/*
 * Tyrion
 * Copyright 2010, Silas Sewell
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "node_loop.h"
#include "node_utils.h"

namespace tyrion {

NodeLoop::NodeLoop() : BaseLoop() {
  track_ = 0;
}

NodeLoop* NodeLoop::instance_ = NULL;

NodeLoop* NodeLoop::Instance() {
  if (!instance_)
    instance_ = new NodeLoop;
  return instance_;
}

void NodeLoop::DoReload() {
  if (NodeReload()) {
    TLOG(INFO) << "Reloading...";
    Restart();
  } else {
    TLOG(WARNING) << "Unable to reload.";
  }
}

void NodeLoop::DoRequest(ServiceData* service) {
  if (track_ <= 10) {
    track_++;
    service->data()->set_retry(0);
    NodeServiceHandler *sh = new NodeServiceHandler(service->data());
    CreateThread(NodeLoop::DoRequestInThread, (void *)sh);
    delete service;
  } else {
    int retry = service->data()->Retry();
    PostDelayed(retry * 2000, this, MSG_REQUEST, service);
  }
}

void *NodeLoop::DoRequestInThread(void *arg) {
  NodeServiceHandler *handler=(NodeServiceHandler*)arg;
  handler->Run();
  delete handler;
  pthread_exit(NULL);
}

void NodeLoop::DoResponse(ServiceData* service) {
  if (state_ == RUNNING && pump_ != NULL &&
      pump_->client() != NULL &&
      pump_->client()->GetState() == txmpp::XmppEngine::STATE_OPEN) {
    track_--;
    const txmpp::XmlElement* iq = service->data()->Response();
    pump_->SendStanza(iq);
    delete iq;
    delete service->data();
    delete service;
  } else {
    int retry = service->data()->Retry();
    TLOG(WARNING) << "Retrying service response in " << retry << " seconds ("
                  << service->data()->id() << ")";
    PostDelayed(retry * 1000, this, MSG_RESPONSE, service);
  }
}

}  // namespace tyrion
<|endoftext|>


<commit_before>
// Copyright (c) 2012 Nokia, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <errno.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#include <linux/types.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <semaphore.h>
#include <assert.h>

#ifdef ZYNQ
#include <android/log.h>
#endif

#include "portal.h"

#ifdef ZYNQ
#define ALOGD(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, "PORTAL", fmt, __VA_ARGS__)
#define ALOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, "PORTAL", fmt, __VA_ARGS__)
#else
#define ALOGD(fmt, ...) fprintf(stderr, "PORTAL", fmt, __VA_ARGS__)
#define ALOGE(fmt, ...) fprintf(stderr, "PORTAL", fmt, __VA_ARGS__)
#endif

PortalInstance **portal_instances = 0;
struct pollfd *portal_fds = 0;
int numFds = 0;

void PortalInstance::close()
{
    if (fd > 0) {
        ::close(fd);
        fd = -1;
    }
}

PortalInstance::PortalInstance(const char *instanceName, PortalIndication *indication)
  : ind_reg_base(NULL),
    ind_fifo_base(NULL),
    req_reg_base(NULL),
    req_fifo_base(NULL),
    indication(indication), fd(-1), instanceName(strdup(instanceName))
{
  int rc = open();
  if (rc != 0) {
    ALOGD("PortalInstance::PortalInstance failure rc=%d\n", rc);
  }
}

PortalInstance::~PortalInstance()
{
  close();
  if (instanceName)
    free(instanceName);
  unregisterInstance(this);
}

static void init_socket(channel *c, const char* path)
{
  int len;
  if ((c->s2 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
    fprintf(stderr, "(%s) socket error", path);
    exit(1);
  }

  printf("(%s) trying to connect...\n", path);

  c->local.sun_family = AF_UNIX;
  strcpy(c->local.sun_path, path);
  len = strlen(c->local.sun_path) + sizeof(c->local.sun_family);
  if (connect(c->s2, (struct sockaddr *)&(c->local), len) == -1) {
    fprintf(stderr,"(%s) connect error", path);
    exit(1);
  }
  // int sockbuffsz = sizeof(memrequest);
  // setsockopt(c->s2, SOL_SOCKET, SO_SNDBUF, &sockbuffsz, sizeof(sockbuffsz));
  // sockbuffsz = sizeof(unsigned int);
  // setsockopt(c->s2, SOL_SOCKET, SO_RCVBUF, &sockbuffsz, sizeof(sockbuffsz));
  fprintf(stderr, "(%s) connected\n", path);
}

int PortalInstance::open()
{
#ifdef ZYNQ
    FILE *pgfile = fopen("/sys/devices/amba.0/f8007000.devcfg/prog_done", "r");
    if (pgfile == 0) {
	ALOGE("failed to open /sys/devices/amba.0/f8007000.devcfg/prog_done %d\n", errno);
	return -1;
    }
    char line[128];
    fgets(line, sizeof(line), pgfile);
    if (line[0] != '1') {
	ALOGE("FPGA not programmed: %s\n", line);
	return -ENODEV;
    }
    fclose(pgfile);

    char path[128];
    snprintf(path, sizeof(path), "/dev/%s", instanceName);
    this->fd = ::open(path, O_RDWR);
    if (this->fd < 0) {
	ALOGE("Failed to open %s fd=%d errno=%d\n", path, this->fd, path);
	return -errno;
    }
    volatile unsigned int *dev_base = (volatile unsigned int*)mmap(NULL, 1<<16, PROT_READ|PROT_WRITE, MAP_SHARED, this->fd, 0);
    if (dev_base == MAP_FAILED) {
      ALOGE("Failed to mmap PortalHWRegs from fd=%d errno=%d\n", this->fd, errno);
      return -errno;
    }
    ind_reg_base   = (volatile unsigned int*)(((unsigned long)dev_base)+(3<<14));
    ind_fifo_base  = (volatile unsigned int*)(((unsigned long)dev_base)+(2<<14));
    req_reg_base   = (volatile unsigned int*)(((unsigned long)dev_base)+(1<<14));
    req_fifo_base  = (volatile unsigned int*)(((unsigned long)dev_base)+(0<<14));
    registerInstance(this);
    return 0;
#else
    char path[128];
    snprintf(path, sizeof(path), "/tmp/%s_rc", instanceName);
    init_socket(&(p.read),path);
    snprintf(path, sizeof(path), "/tmp/%s_wc", instanceName);
    init_socket(&(p.write),path);

    unsigned long dev_base = 0;
    ind_reg_base   = dev_base+(3<<14);
    ind_fifo_base  = dev_base+(2<<14);
    req_reg_base   = dev_base+(1<<14);
    req_fifo_base  = dev_base+(0<<14);
    registerInstance(this);
    return 0;
#endif
}

int PortalInstance::sendMessage(PortalMessage *msg)
{
  unsigned int buf[128];
  msg->marshall(buf);

  // mutex_lock(&portal_data->reg_mutex);
  // mutex_unlock(&portal_data->reg_mutex);
  // fprintf(stderr, "msg->size() = %d\n", msg->size());
  for (int i = (msg->size()/4)-1; i >= 0; i--){
    unsigned int data = buf[i];
#ifdef ZYNQ
    // fprintf(stderr, "%08x\n", val);
    unsigned int addr = ((unsigned int)req_fifo_base) + msg->channel * 256;
    *((volatile unsigned int*)addr) = data;
#else
    unsigned int addr = req_fifo_base + msg->channel * 256;
    struct memrequest foo = {true,addr,data};
    if (send(p.write.s2, &foo, sizeof(foo), 0) == -1) {
      fprintf(stderr, "(%s) send error\n", instanceName);
      exit(1);
    }
    //fprintf(stderr, "(%s) sendMessage\n", instanceName);
#endif
  }
  return 0;
}

int PortalInstance::unregisterInstance(PortalInstance *instance)
{
  int i = 0;
  while(i < numFds)
    if(portal_fds[i].fd == instance->fd)
      break;
    else
      i++;

  while(i < numFds-1){
    portal_fds[i] = portal_fds[i+1];
    portal_instances[i] = portal_instances[i+1];
  }

  numFds--;
  portal_fds = (struct pollfd *)realloc(portal_fds, numFds*sizeof(struct pollfd));
  portal_instances = (PortalInstance **)realloc(portal_instances, numFds*sizeof(PortalInstance *));
  return 0;
}

int PortalInstance::registerInstance(PortalInstance *instance)
{
    numFds++;
    portal_instances = (PortalInstance **)realloc(portal_instances, numFds*sizeof(PortalInstance *));
    portal_instances[numFds-1] = instance;
    portal_fds = (struct pollfd *)realloc(portal_fds, numFds*sizeof(struct pollfd));
    struct pollfd *pollfd = &portal_fds[numFds-1];
    memset(pollfd, 0, sizeof(struct pollfd));
    pollfd->fd = instance->fd;
    pollfd->events = POLLIN;
    return 0;
}

int PortalMemory::dCacheFlushInval(PortalAlloc *portalAlloc)
{
    if (!numFds) {
	ALOGE("%s No fds open\n", __FUNCTION__);
	return -ENODEV;
    }
    int rc = ioctl(portal_fds[0].fd, PORTAL_DCACHE_FLUSH_INVAL, portalAlloc);
    if (rc){
      fprintf(stderr, "portal dcache flush failed rc=%d errno=%d:%s\n", rc, errno, strerror(errno));
      return rc;
    }
    //fprintf(stderr, "dcache flush\n");
    return 0;
}

int PortalMemory::alloc(size_t size, int *fd, PortalAlloc *portalAlloc)
{
    if (!numFds) {
	ALOGE("%s No fds open\n", __FUNCTION__);
	return -ENODEV;
    }

    PortalAlloc alloc;
    memset(&alloc, 0, sizeof(alloc));
    alloc.size = size;
    int rc = ioctl(portal_fds[0].fd, PORTAL_ALLOC, &alloc);
    if (rc){
      fprintf(stderr, "portal alloc failed rc=%d errno=%d:%s\n", rc, errno, strerror(errno));
      return rc;
    }
    fprintf(stderr, "alloc size=%d rc=%d alloc.fd=%d\n", size, rc, alloc.fd);
    if (fd)
      *fd = alloc.fd;
    if (portalAlloc)
      *portalAlloc = alloc;
    return 0;
}

int PortalInstance::setClockFrequency(int clkNum, long requestedFrequency, long *actualFrequency)
{
    if (!numFds) {
	ALOGE("%s No fds open\n", __FUNCTION__);
	return -ENODEV;
    }

    PortalClockRequest request;
    request.clknum = clkNum;
    request.requested_rate = requestedFrequency;
    int status = ioctl(portal_fds[0].fd, PORTAL_SET_FCLK_RATE, (long)&request);
    if (status == 0 && actualFrequency)
	*actualFrequency = request.actual_rate;
    if (status < 0)
	status = errno;
    return status;
}

void* portalExec(void* __x)
{
#ifdef ZYNQ
    int rc;
    int timeout = -1;
    if(0)
    fprintf(stderr, "about to invoke poll(%x, %d, %d)\n", portal_fds, numFds, timeout);
    if (!numFds) {
        ALOGE("PortalMemory::exec No fds open numFds=%d\n", numFds);
        return (void*)-ENODEV;
    }
    while ((rc = poll(portal_fds, numFds, timeout)) >= 0) {
      // fprintf(stderr, "poll returned rc=%d\n", rc);
      for (int i = 0; i < numFds; i++) {
	if (portal_fds[i].revents == 0)
	  continue;
	if (!portal_instances) {
	  fprintf(stderr, "No portal_instances but rc=%d revents=%d\n", rc, portal_fds[i].revents);
	}

	PortalInstance *instance = portal_instances[i];

	// sanity check, to see the status of interrupt source and enable
	volatile unsigned int int_src = *(instance->ind_reg_base+0x0);
	volatile unsigned int int_en  = *(instance->ind_reg_base+0x1);
	volatile unsigned int queue_status = *(instance->ind_reg_base+0x8);
	if(0)
	fprintf(stderr, "about to receive messages %08x %08x %08x\n", int_src, int_en, queue_status);

	// handle all messasges from this portal instance
	while (queue_status) {
	  instance->indication->handleMessage(queue_status-1, instance->ind_fifo_base);
	  queue_status = *(instance->ind_reg_base+0x8);
	}

	// rc of 0 indicates timeout
	if (rc == 0) {
	  // do something if we timeout??
	}
	// re-enable interupt which was disabled by portal_isr
	*(instance->ind_reg_base+0x1) = 1;
      }
    }
    // return only in error case
    fprintf(stderr, "poll returned rc=%d errno=%d:%s\n", rc, errno, strerror(errno));
    return (void*)rc;
#else
    fprintf(stderr, "about to enter while(true)\n");
    while (true){
      sleep(0);
      for(int i = 0; i < numFds; i++){
	PortalInstance *instance = portal_instances[i];
	unsigned int addr = instance->ind_reg_base+0x20;
	struct memrequest foo = {false,addr,0};
	//fprintf(stderr, "sending read request\n");
	if (send(instance->p.read.s2, &foo, sizeof(foo), 0) == -1) {
	  fprintf(stderr, "(%s) send error\n", instance->instanceName);
	  exit(1);
	}
	unsigned int queue_status;
	//fprintf(stderr, "about to get read response\n");
	if(recv(instance->p.read.s2, &queue_status, sizeof(queue_status), 0) == -1){
	  fprintf(stderr, "(%s) recv error\n", instance->instanceName);
	  exit(1);
	}
	//fprintf(stderr, "(%s) queue_status : %08x\n", instance->instanceName, queue_status);
	if (queue_status){
	  instance->indication->handleMessage(queue_status-1, instance);
	}
      }
    }
#endif
}

<commit_msg>added error message/exit for failure to open device driver<commit_after>
// Copyright (c) 2012 Nokia, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <errno.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#include <linux/types.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <semaphore.h>
#include <assert.h>

#ifdef ZYNQ
#include <android/log.h>
#endif

#include "portal.h"

#ifdef ZYNQ
#define ALOGD(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, "PORTAL", fmt, __VA_ARGS__)
#define ALOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, "PORTAL", fmt, __VA_ARGS__)
#else
#define ALOGD(fmt, ...) fprintf(stderr, "PORTAL", fmt, __VA_ARGS__)
#define ALOGE(fmt, ...) fprintf(stderr, "PORTAL", fmt, __VA_ARGS__)
#endif

PortalInstance **portal_instances = 0;
struct pollfd *portal_fds = 0;
int numFds = 0;

void PortalInstance::close()
{
    if (fd > 0) {
        ::close(fd);
        fd = -1;
    }
}

PortalInstance::PortalInstance(const char *instanceName, PortalIndication *indication)
  : ind_reg_base(NULL),
    ind_fifo_base(NULL),
    req_reg_base(NULL),
    req_fifo_base(NULL),
    indication(indication), fd(-1), instanceName(strdup(instanceName))
{
  int rc = open();
  if (rc != 0) {
printf("[%s:%d] failed to open PortalInstance %s\n", __FUNCTION__, __LINE__, instanceName);
    ALOGD("PortalInstance::PortalInstance failure rc=%d\n", rc);
    exit(1);
  }
}

PortalInstance::~PortalInstance()
{
  close();
  if (instanceName)
    free(instanceName);
  unregisterInstance(this);
}

static void init_socket(channel *c, const char* path)
{
  int len;
  if ((c->s2 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
    fprintf(stderr, "(%s) socket error", path);
    exit(1);
  }

  printf("(%s) trying to connect...\n", path);

  c->local.sun_family = AF_UNIX;
  strcpy(c->local.sun_path, path);
  len = strlen(c->local.sun_path) + sizeof(c->local.sun_family);
  if (connect(c->s2, (struct sockaddr *)&(c->local), len) == -1) {
    fprintf(stderr,"(%s) connect error", path);
    exit(1);
  }
  // int sockbuffsz = sizeof(memrequest);
  // setsockopt(c->s2, SOL_SOCKET, SO_SNDBUF, &sockbuffsz, sizeof(sockbuffsz));
  // sockbuffsz = sizeof(unsigned int);
  // setsockopt(c->s2, SOL_SOCKET, SO_RCVBUF, &sockbuffsz, sizeof(sockbuffsz));
  fprintf(stderr, "(%s) connected\n", path);
}

int PortalInstance::open()
{
#ifdef ZYNQ
    FILE *pgfile = fopen("/sys/devices/amba.0/f8007000.devcfg/prog_done", "r");
    if (pgfile == 0) {
	ALOGE("failed to open /sys/devices/amba.0/f8007000.devcfg/prog_done %d\n", errno);
	return -1;
    }
    char line[128];
    fgets(line, sizeof(line), pgfile);
    if (line[0] != '1') {
	ALOGE("FPGA not programmed: %s\n", line);
	return -ENODEV;
    }
    fclose(pgfile);

    char path[128];
    snprintf(path, sizeof(path), "/dev/%s", instanceName);
    this->fd = ::open(path, O_RDWR);
    if (this->fd < 0) {
	ALOGE("Failed to open %s fd=%d errno=%d\n", path, this->fd, path);
	return -errno;
    }
    volatile unsigned int *dev_base = (volatile unsigned int*)mmap(NULL, 1<<16, PROT_READ|PROT_WRITE, MAP_SHARED, this->fd, 0);
    if (dev_base == MAP_FAILED) {
      ALOGE("Failed to mmap PortalHWRegs from fd=%d errno=%d\n", this->fd, errno);
      return -errno;
    }
    ind_reg_base   = (volatile unsigned int*)(((unsigned long)dev_base)+(3<<14));
    ind_fifo_base  = (volatile unsigned int*)(((unsigned long)dev_base)+(2<<14));
    req_reg_base   = (volatile unsigned int*)(((unsigned long)dev_base)+(1<<14));
    req_fifo_base  = (volatile unsigned int*)(((unsigned long)dev_base)+(0<<14));
    registerInstance(this);
    return 0;
#else
    char path[128];
    snprintf(path, sizeof(path), "/tmp/%s_rc", instanceName);
    init_socket(&(p.read),path);
    snprintf(path, sizeof(path), "/tmp/%s_wc", instanceName);
    init_socket(&(p.write),path);

    unsigned long dev_base = 0;
    ind_reg_base   = dev_base+(3<<14);
    ind_fifo_base  = dev_base+(2<<14);
    req_reg_base   = dev_base+(1<<14);
    req_fifo_base  = dev_base+(0<<14);
    registerInstance(this);
    return 0;
#endif
}

int PortalInstance::sendMessage(PortalMessage *msg)
{
  unsigned int buf[128];
  msg->marshall(buf);

  // mutex_lock(&portal_data->reg_mutex);
  // mutex_unlock(&portal_data->reg_mutex);
  // fprintf(stderr, "msg->size() = %d\n", msg->size());
  for (int i = (msg->size()/4)-1; i >= 0; i--){
    unsigned int data = buf[i];
#ifdef ZYNQ
    // fprintf(stderr, "%08x\n", val);
    unsigned int addr = ((unsigned int)req_fifo_base) + msg->channel * 256;
    *((volatile unsigned int*)addr) = data;
#else
    unsigned int addr = req_fifo_base + msg->channel * 256;
    struct memrequest foo = {true,addr,data};
    if (send(p.write.s2, &foo, sizeof(foo), 0) == -1) {
      fprintf(stderr, "(%s) send error\n", instanceName);
      exit(1);
    }
    //fprintf(stderr, "(%s) sendMessage\n", instanceName);
#endif
  }
  return 0;
}

int PortalInstance::unregisterInstance(PortalInstance *instance)
{
  int i = 0;
  while(i < numFds)
    if(portal_fds[i].fd == instance->fd)
      break;
    else
      i++;

  while(i < numFds-1){
    portal_fds[i] = portal_fds[i+1];
    portal_instances[i] = portal_instances[i+1];
  }

  numFds--;
  portal_fds = (struct pollfd *)realloc(portal_fds, numFds*sizeof(struct pollfd));
  portal_instances = (PortalInstance **)realloc(portal_instances, numFds*sizeof(PortalInstance *));
  return 0;
}

int PortalInstance::registerInstance(PortalInstance *instance)
{
    numFds++;
    portal_instances = (PortalInstance **)realloc(portal_instances, numFds*sizeof(PortalInstance *));
    portal_instances[numFds-1] = instance;
    portal_fds = (struct pollfd *)realloc(portal_fds, numFds*sizeof(struct pollfd));
    struct pollfd *pollfd = &portal_fds[numFds-1];
    memset(pollfd, 0, sizeof(struct pollfd));
    pollfd->fd = instance->fd;
    pollfd->events = POLLIN;
    return 0;
}

int PortalMemory::dCacheFlushInval(PortalAlloc *portalAlloc)
{
    if (!numFds) {
	ALOGE("%s No fds open\n", __FUNCTION__);
	return -ENODEV;
    }
    int rc = ioctl(portal_fds[0].fd, PORTAL_DCACHE_FLUSH_INVAL, portalAlloc);
    if (rc){
      fprintf(stderr, "portal dcache flush failed rc=%d errno=%d:%s\n", rc, errno, strerror(errno));
      return rc;
    }
    //fprintf(stderr, "dcache flush\n");
    return 0;
}

int PortalMemory::alloc(size_t size, int *fd, PortalAlloc *portalAlloc)
{
    if (!numFds) {
	ALOGE("%s No fds open\n", __FUNCTION__);
	return -ENODEV;
    }

    PortalAlloc alloc;
    memset(&alloc, 0, sizeof(alloc));
    alloc.size = size;
    int rc = ioctl(portal_fds[0].fd, PORTAL_ALLOC, &alloc);
    if (rc){
      fprintf(stderr, "portal alloc failed rc=%d errno=%d:%s\n", rc, errno, strerror(errno));
      return rc;
    }
    fprintf(stderr, "alloc size=%d rc=%d alloc.fd=%d\n", size, rc, alloc.fd);
    if (fd)
      *fd = alloc.fd;
    if (portalAlloc)
      *portalAlloc = alloc;
    return 0;
}

int PortalInstance::setClockFrequency(int clkNum, long requestedFrequency, long *actualFrequency)
{
    if (!numFds) {
	ALOGE("%s No fds open\n", __FUNCTION__);
	return -ENODEV;
    }

    PortalClockRequest request;
    request.clknum = clkNum;
    request.requested_rate = requestedFrequency;
    int status = ioctl(portal_fds[0].fd, PORTAL_SET_FCLK_RATE, (long)&request);
    if (status == 0 && actualFrequency)
	*actualFrequency = request.actual_rate;
    if (status < 0)
	status = errno;
    return status;
}

void* portalExec(void* __x)
{
#ifdef ZYNQ
    int rc;
    int timeout = -1;
    if(0)
    fprintf(stderr, "about to invoke poll(%x, %d, %d)\n", portal_fds, numFds, timeout);
    if (!numFds) {
        ALOGE("PortalMemory::exec No fds open numFds=%d\n", numFds);
        return (void*)-ENODEV;
    }
    while ((rc = poll(portal_fds, numFds, timeout)) >= 0) {
      // fprintf(stderr, "poll returned rc=%d\n", rc);
      for (int i = 0; i < numFds; i++) {
	if (portal_fds[i].revents == 0)
	  continue;
	if (!portal_instances) {
	  fprintf(stderr, "No portal_instances but rc=%d revents=%d\n", rc, portal_fds[i].revents);
	}

	PortalInstance *instance = portal_instances[i];

	// sanity check, to see the status of interrupt source and enable
	volatile unsigned int int_src = *(instance->ind_reg_base+0x0);
	volatile unsigned int int_en  = *(instance->ind_reg_base+0x1);
	volatile unsigned int queue_status = *(instance->ind_reg_base+0x8);
	if(0)
	fprintf(stderr, "about to receive messages %08x %08x %08x\n", int_src, int_en, queue_status);

	// handle all messasges from this portal instance
	while (queue_status) {
	  instance->indication->handleMessage(queue_status-1, instance->ind_fifo_base);
	  queue_status = *(instance->ind_reg_base+0x8);
	}

	// rc of 0 indicates timeout
	if (rc == 0) {
	  // do something if we timeout??
	}
	// re-enable interupt which was disabled by portal_isr
	*(instance->ind_reg_base+0x1) = 1;
      }
    }
    // return only in error case
    fprintf(stderr, "poll returned rc=%d errno=%d:%s\n", rc, errno, strerror(errno));
    return (void*)rc;
#else
    fprintf(stderr, "about to enter while(true)\n");
    while (true){
      sleep(0);
      for(int i = 0; i < numFds; i++){
	PortalInstance *instance = portal_instances[i];
	unsigned int addr = instance->ind_reg_base+0x20;
	struct memrequest foo = {false,addr,0};
	//fprintf(stderr, "sending read request\n");
	if (send(instance->p.read.s2, &foo, sizeof(foo), 0) == -1) {
	  fprintf(stderr, "(%s) send error\n", instance->instanceName);
	  exit(1);
	}
	unsigned int queue_status;
	//fprintf(stderr, "about to get read response\n");
	if(recv(instance->p.read.s2, &queue_status, sizeof(queue_status), 0) == -1){
	  fprintf(stderr, "(%s) recv error\n", instance->instanceName);
	  exit(1);
	}
	//fprintf(stderr, "(%s) queue_status : %08x\n", instance->instanceName, queue_status);
	if (queue_status){
	  instance->indication->handleMessage(queue_status-1, instance);
	}
      }
    }
#endif
}

<|endoftext|>


<commit_before>#include <sirius.h>

void test_gemm(int M, int N, int K, int transa)
{
    sirius::Timer t("test_gemm");

    mdarray<double_complex, 2> a, b, c;
    int imax, jmax;
    if (transa == 0)
    {
        imax = N;
        jmax = K;
    }
    else
    {
        imax = K;
        jmax = N;
    }
    a.set_dimensions(imax, jmax);
    b.set_dimensions(K, N);
    c.set_dimensions(M, N);
    #ifdef _GPU_
    a.allocate_page_locked();
    b.allocate_page_locked();
    c.allocate_page_locked();
    #else
    a.allocate();
    b.allocate();
    c.allocate();
    #endif

    for (int j = 0; j < jmax; j++)
    {
        for (int i = 0; i < imax; i++) a(i, j) = type_wrapper<double_complex>::random();
    }

    for (int j = 0; j < N; j++)
    {
        for (int i = 0; i < K; i++) b(i, j) = type_wrapper<double_complex>::random();
    }

    c.zero();

    printf("testing serial zgemm with M, N, K = %i, %i, %i, opA = %i\n", M, N, K, transa);
    sirius::Timer t1("gemm_only");
    blas<cpu>::gemm(transa, 0, M, N, K, a.ptr(), a.ld(), b.ptr(), b.ld(), c.ptr(), c.ld());
    t1.stop();
    printf("execution time (sec) : %12.6f\n", t1.value());
    printf("performance (GFlops) : %12.6f\n", 8e-9 * M * N * K / t1.value());
}

#ifdef _SCALAPACK_
void test_pgemm(int M, int N, int K, int nrow, int ncol, int transa)
{
    int blacs_handler = linalg<scalapack>::create_blacs_handler(MPI_COMM_WORLD);
    int context = blacs_handler;
    Cblacs_gridinit(&context, "C", nrow, ncol);

    dmatrix<double_complex> a, b, c;
    if (transa == 0)
    {
        a.set_dimensions(M, K, context);
    }
    else
    {
        a.set_dimensions(K, M, context);
    }
    b.set_dimensions(K, N, context);
    c.set_dimensions(M, N, context);
    #ifdef _GPU_
    a.allocate_page_locked();
    b.allocate_page_locked();
    c.allocate_page_locked();
    #else
    a.allocate();
    b.allocate();
    c.allocate();
    #endif

    for (int ic = 0; ic < a.num_cols_local(); ic++)
    {
        for (int ir = 0; ir < a.num_rows_local(); ir++) a(ir, ic) = type_wrapper<double_complex>::random();
    }

    for (int ic = 0; ic < b.num_cols_local(); ic++)
    {
        for (int ir = 0; ir < b.num_rows_local(); ir++) b(ir, ic) = type_wrapper<double_complex>::random();
    }

    c.zero();

    if (Platform::mpi_rank() == 0)
    {
        printf("testing parallel zgemm with M, N, K = %i, %i, %i, opA = %i\n", M, N, K, transa);
        printf("nrow, ncol = %i, %i, bs = %i\n", nrow, ncol, linalg<scalapack>::cyclic_block_size());
    }
    sirius::Timer t1("gemm_only");
    blas<cpu>::gemm(transa, 0, M, N, K, complex_one, a, b, complex_zero, c);
    t1.stop();
    if (Platform::mpi_rank() == 0)
    {
        printf("execution time (sec) : %12.6f\n", t1.value());
        printf("performance (GFlops) : %12.6f\n", 8e-9 * M * N * K / t1.value() / nrow / ncol);
    }
    Cblacs_gridexit(context);
    linalg<scalapack>::free_blacs_handler(blacs_handler);
}
#endif

int main(int argn, char **argv)
{
    cmd_args args;
    args.register_key("--M=", "{int} M");
    args.register_key("--N=", "{int} N");
    args.register_key("--K=", "{int} K");
    args.register_key("--opA=", "{0|1|2} 0: op(A) = A, 1: op(A) = A', 2: op(A) = conjg(A')");
    args.register_key("--nrow=", "{int} number of row MPI ranks");
    args.register_key("--ncol=", "{int} number of column MPI ranks");
    args.register_key("--bs=", "{int} cyclic block size");

    args.parse_args(argn, argv);
    if (argn == 1)
    {
        printf("Usage: %s [options]\n", argv[0]);
        args.print_help();
        exit(0);
    }

    int nrow = 1;
    int ncol = 1;

    if (args.exist("nrow")) nrow = args.value<int>("nrow");
    if (args.exist("ncol")) ncol = args.value<int>("ncol");

    int M = args.value<int>("M");
    int N = args.value<int>("N");
    int K = args.value<int>("K");

    int transa = 0;
    if (args.exist("opA")) transa = args.value<int>("opA");

    Platform::initialize(true);

    if (nrow * ncol == 1)
    {
        test_gemm(M, N, K, transa);
    }
    else
    {
        #ifdef _SCALAPACK_
        int bs = args.value<int>("bs");
        linalg<scalapack>::set_cyclic_block_size(bs);
        test_pgemm(M, N, K, nrow, ncol, transa);
        #else
        terminate(__FILE__, __LINE__, "not compiled with ScaLAPACK support");
        #endif
    }

    Platform::finalize();
}
<commit_msg>update of zgemm test<commit_after>#include <sirius.h>

void test_gemm(int M, int N, int K, int transa)
{
    sirius::Timer t("test_gemm");

    mdarray<double_complex, 2> a, b, c;
    int imax, jmax;
    if (transa == 0)
    {
        imax = N;
        jmax = K;
    }
    else
    {
        imax = K;
        jmax = N;
    }
    a.set_dimensions(imax, jmax);
    b.set_dimensions(K, N);
    c.set_dimensions(M, N);
    #ifdef _GPU_
    a.allocate_page_locked();
    b.allocate_page_locked();
    c.allocate_page_locked();
    #else
    a.allocate();
    b.allocate();
    c.allocate();
    #endif

    for (int j = 0; j < jmax; j++)
    {
        for (int i = 0; i < imax; i++) a(i, j) = type_wrapper<double_complex>::random();
    }

    for (int j = 0; j < N; j++)
    {
        for (int i = 0; i < K; i++) b(i, j) = type_wrapper<double_complex>::random();
    }

    c.zero();

    printf("testing serial zgemm with M, N, K = %i, %i, %i, opA = %i\n", M, N, K, transa);
    sirius::Timer t1("gemm_only");
    blas<cpu>::gemm(transa, 0, M, N, K, a.ptr(), a.ld(), b.ptr(), b.ld(), c.ptr(), c.ld());
    t1.stop();
    printf("execution time (sec) : %12.6f\n", t1.value());
    printf("performance (GFlops) : %12.6f\n", 8e-9 * M * N * K / t1.value());
}

#ifdef _SCALAPACK_
void test_pgemm(int M, int N, int K, int nrow, int ncol, int transa)
{
    //== #ifdef _GPU_
    //== sirius::pstdout pout;
    //== pout.printf("rank : %3i, free GPU memory (Mb) : %10.2f\n", Platform::mpi_rank(), cuda_get_free_mem() / double(1 << 20));
    //== pout.flush(0);
    //== #endif

    int blacs_handler = linalg<scalapack>::create_blacs_handler(MPI_COMM_WORLD);
    int context = blacs_handler;
    Cblacs_gridinit(&context, "C", nrow, ncol);

    dmatrix<double_complex> a, b, c;
    if (transa == 0)
    {
        a.set_dimensions(M, K, context);
    }
    else
    {
        a.set_dimensions(K, M, context);
    }
    b.set_dimensions(K, N, context);
    c.set_dimensions(M, N, context);
    #ifdef _GPU_
    a.allocate_page_locked();
    b.allocate_page_locked();
    c.allocate_page_locked();
    #else
    a.allocate();
    b.allocate();
    c.allocate();
    #endif

    for (int ic = 0; ic < a.num_cols_local(); ic++)
    {
        for (int ir = 0; ir < a.num_rows_local(); ir++) a(ir, ic) = type_wrapper<double_complex>::random();
    }

    for (int ic = 0; ic < b.num_cols_local(); ic++)
    {
        for (int ir = 0; ir < b.num_rows_local(); ir++) b(ir, ic) = type_wrapper<double_complex>::random();
    }

    c.zero();

    if (Platform::mpi_rank() == 0)
    {
        printf("testing parallel zgemm with M, N, K = %i, %i, %i, opA = %i\n", M, N, K, transa);
        printf("nrow, ncol = %i, %i, bs = %i\n", nrow, ncol, linalg<scalapack>::cyclic_block_size());
    }
    Platform::barrier();
    sirius::Timer t1("gemm_only");
    blas<cpu>::gemm(transa, 0, M, N, K, complex_one, a, b, complex_zero, c);
    #ifdef _GPU_
    cuda_device_synchronize();
    #endif
    Platform::barrier();
    t1.stop();
    if (Platform::mpi_rank() == 0)
    {
        printf("execution time (sec) : %12.6f\n", t1.value());
        printf("performance (GFlops) : %12.6f\n", 8e-9 * M * N * K / t1.value() / nrow / ncol);
    }
    Cblacs_gridexit(context);
    linalg<scalapack>::free_blacs_handler(blacs_handler);
}
#endif

int main(int argn, char **argv)
{
    cmd_args args;
    args.register_key("--M=", "{int} M");
    args.register_key("--N=", "{int} N");
    args.register_key("--K=", "{int} K");
    args.register_key("--opA=", "{0|1|2} 0: op(A) = A, 1: op(A) = A', 2: op(A) = conjg(A')");
    args.register_key("--nrow=", "{int} number of row MPI ranks");
    args.register_key("--ncol=", "{int} number of column MPI ranks");
    args.register_key("--bs=", "{int} cyclic block size");

    args.parse_args(argn, argv);
    if (argn == 1)
    {
        printf("Usage: %s [options]\n", argv[0]);
        args.print_help();
        exit(0);
    }

    int nrow = 1;
    int ncol = 1;

    if (args.exist("nrow")) nrow = args.value<int>("nrow");
    if (args.exist("ncol")) ncol = args.value<int>("ncol");

    int M = args.value<int>("M");
    int N = args.value<int>("N");
    int K = args.value<int>("K");

    int transa = 0;
    if (args.exist("opA")) transa = args.value<int>("opA");

    Platform::initialize(true);

    if (nrow * ncol == 1)
    {
        test_gemm(M, N, K, transa);
    }
    else
    {
        #ifdef _SCALAPACK_
        int bs = args.value<int>("bs");
        linalg<scalapack>::set_cyclic_block_size(bs);
        int n = 4;
        for (int i = 0; i < n; i++) test_pgemm(M, N, K, nrow, ncol, transa);
        #else
        terminate(__FILE__, __LINE__, "not compiled with ScaLAPACK support");
        #endif
    }

    Platform::finalize();
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/file_path.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/speech/speech_input_dispatcher_host.h"
#include "chrome/browser/speech/speech_input_manager.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

namespace speech_input {
class FakeSpeechInputManager;
}

// This class does not need to be refcounted (typically done by PostTask) since
// it will outlive the test and gets released only when the test shuts down.
// Disabling refcounting here saves a bit of unnecessary code and the factory
// method can return a plain pointer below as required by the real code.
DISABLE_RUNNABLE_METHOD_REFCOUNT(speech_input::FakeSpeechInputManager);

namespace speech_input {

const char* kTestResult = "Pictures of the moon";

class FakeSpeechInputManager : public SpeechInputManager {
 public:
  explicit FakeSpeechInputManager(Listener* listener)
      : render_view_id_(0),
        listener_(listener) {
  }

  // SpeechInputManager methods.
  void StartRecognition(int render_view_id) {
    EXPECT_EQ(0, render_view_id_);
    render_view_id_ = render_view_id;
    // Give the fake result in a short while.
    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
        &FakeSpeechInputManager::SetFakeRecognitionResult));
  }
  void CancelRecognition(int render_view_id) {
    EXPECT_EQ(render_view_id_, render_view_id);
    render_view_id_ = 0;
  }
  void StopRecording(int render_view_id) {
    EXPECT_EQ(render_view_id_, render_view_id);
    // Nothing to do here since we aren't really recording.
  }

 private:
  void SetFakeRecognitionResult() {
    if (render_view_id_) {  // Do a check in case we were cancelled..
      listener_->DidCompleteRecording(render_view_id_);
      listener_->SetRecognitionResult(render_view_id_,
                                      ASCIIToUTF16(kTestResult));
      listener_->DidCompleteRecognition(render_view_id_);
      render_view_id_ = 0;
    }
  }

  int render_view_id_;
  Listener* listener_;
};

// Factory method.
SpeechInputManager* fakeManagerFactory(SpeechInputManager::Listener* listener) {
  return new FakeSpeechInputManager(listener);
}

class SpeechInputBrowserTest : public InProcessBrowserTest {
 public:
  // InProcessBrowserTest methods
  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitch(switches::kEnableSpeechInput);
  }

  GURL testUrl(const FilePath::CharType* filename) {
    const FilePath kTestDir(FILE_PATH_LITERAL("speech"));
    return ui_test_utils::GetTestUrl(kTestDir, FilePath(filename));
  }
};

IN_PROC_BROWSER_TEST_F(SpeechInputBrowserTest, TestBasicRecognition) {
  // Inject the fake manager factory so that the test result is returned to the
  // web page.
  SpeechInputDispatcherHost::set_manager_factory(&fakeManagerFactory);

  // The test page starts speech recognition and waits to receive the above
  // defined test string as the result. Once it receives the result it either
  // navigates to #pass or #fail depending on the result.
  GURL test_url = testUrl(FILE_PATH_LITERAL("basic_recognition.html"));
  ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(browser(),
                                                            test_url,
                                                            2);

  // Check that the page got the result it expected.
  EXPECT_EQ("pass", browser()->GetSelectedTabContents()->GetURL().ref());
}

} //  namespace speech_input
<commit_msg>Disable SpeechInputBrowserTest.TestBasicRecognition.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/file_path.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/speech/speech_input_dispatcher_host.h"
#include "chrome/browser/speech/speech_input_manager.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

namespace speech_input {
class FakeSpeechInputManager;
}

// This class does not need to be refcounted (typically done by PostTask) since
// it will outlive the test and gets released only when the test shuts down.
// Disabling refcounting here saves a bit of unnecessary code and the factory
// method can return a plain pointer below as required by the real code.
DISABLE_RUNNABLE_METHOD_REFCOUNT(speech_input::FakeSpeechInputManager);

namespace speech_input {

const char* kTestResult = "Pictures of the moon";

class FakeSpeechInputManager : public SpeechInputManager {
 public:
  explicit FakeSpeechInputManager(Listener* listener)
      : render_view_id_(0),
        listener_(listener) {
  }

  // SpeechInputManager methods.
  void StartRecognition(int render_view_id) {
    EXPECT_EQ(0, render_view_id_);
    render_view_id_ = render_view_id;
    // Give the fake result in a short while.
    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
        &FakeSpeechInputManager::SetFakeRecognitionResult));
  }
  void CancelRecognition(int render_view_id) {
    EXPECT_EQ(render_view_id_, render_view_id);
    render_view_id_ = 0;
  }
  void StopRecording(int render_view_id) {
    EXPECT_EQ(render_view_id_, render_view_id);
    // Nothing to do here since we aren't really recording.
  }

 private:
  void SetFakeRecognitionResult() {
    if (render_view_id_) {  // Do a check in case we were cancelled..
      listener_->DidCompleteRecording(render_view_id_);
      listener_->SetRecognitionResult(render_view_id_,
                                      ASCIIToUTF16(kTestResult));
      listener_->DidCompleteRecognition(render_view_id_);
      render_view_id_ = 0;
    }
  }

  int render_view_id_;
  Listener* listener_;
};

// Factory method.
SpeechInputManager* fakeManagerFactory(SpeechInputManager::Listener* listener) {
  return new FakeSpeechInputManager(listener);
}

class SpeechInputBrowserTest : public InProcessBrowserTest {
 public:
  // InProcessBrowserTest methods
  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitch(switches::kEnableSpeechInput);
  }

  GURL testUrl(const FilePath::CharType* filename) {
    const FilePath kTestDir(FILE_PATH_LITERAL("speech"));
    return ui_test_utils::GetTestUrl(kTestDir, FilePath(filename));
  }
};

IN_PROC_BROWSER_TEST_F(SpeechInputBrowserTest, DISABLED_TestBasicRecognition) {
  // Inject the fake manager factory so that the test result is returned to the
  // web page.
  SpeechInputDispatcherHost::set_manager_factory(&fakeManagerFactory);

  // The test page starts speech recognition and waits to receive the above
  // defined test string as the result. Once it receives the result it either
  // navigates to #pass or #fail depending on the result.
  GURL test_url = testUrl(FILE_PATH_LITERAL("basic_recognition.html"));
  ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(browser(),
                                                            test_url,
                                                            2);

  // Check that the page got the result it expected.
  EXPECT_EQ("pass", browser()->GetSelectedTabContents()->GetURL().ref());
}

} //  namespace speech_input
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/toolbar/toolbar_button.h"

#include "base/bind.h"
#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include "grit/theme_resources.h"
#include "grit/ui_strings.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/menu_model.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/widget/widget.h"

ToolbarButton::ToolbarButton(views::ButtonListener* listener,
                             ui::MenuModel* model)
    : views::LabelButton(listener, base::string16()),
      model_(model),
      menu_showing_(false),
      y_position_on_lbuttondown_(0),
      show_menu_factory_(this) {
  set_context_menu_controller(this);
}

ToolbarButton::~ToolbarButton() {
}

void ToolbarButton::Init() {
  SetFocusable(false);
  SetAccessibilityFocusable(true);
  image()->EnableCanvasFlippingForRTLUI(true);
}

void ToolbarButton::ClearPendingMenu() {
  show_menu_factory_.InvalidateWeakPtrs();
}

bool ToolbarButton::IsMenuShowing() const {
  return menu_showing_;
}

gfx::Size ToolbarButton::GetPreferredSize() {
  gfx::Size size(image()->GetPreferredSize());
  gfx::Size label_size = label()->GetPreferredSize();
  if (label_size.width() > 0)
    size.Enlarge(label_size.width() + LocationBarView::GetItemPadding(), 0);
  return size;
}

bool ToolbarButton::OnMousePressed(const ui::MouseEvent& event) {
  if (enabled() && ShouldShowMenu() &&
      IsTriggerableEvent(event) && HitTestPoint(event.location())) {
    // Store the y pos of the mouse coordinates so we can use them later to
    // determine if the user dragged the mouse down (which should pop up the
    // drag down menu immediately, instead of waiting for the timer)
    y_position_on_lbuttondown_ = event.y();

    // Schedule a task that will show the menu.
    const int kMenuTimerDelay = 500;
    base::MessageLoop::current()->PostDelayedTask(
        FROM_HERE,
        base::Bind(&ToolbarButton::ShowDropDownMenu,
                   show_menu_factory_.GetWeakPtr(),
                   ui::GetMenuSourceTypeForEvent(event)),
        base::TimeDelta::FromMilliseconds(kMenuTimerDelay));
  }
  return LabelButton::OnMousePressed(event);
}

bool ToolbarButton::OnMouseDragged(const ui::MouseEvent& event) {
  bool result = LabelButton::OnMouseDragged(event);

  if (show_menu_factory_.HasWeakPtrs()) {
    // If the mouse is dragged to a y position lower than where it was when
    // clicked then we should not wait for the menu to appear but show
    // it immediately.
    if (event.y() > y_position_on_lbuttondown_ + GetHorizontalDragThreshold()) {
      show_menu_factory_.InvalidateWeakPtrs();
      ShowDropDownMenu(ui::GetMenuSourceTypeForEvent(event));
    }
  }

  return result;
}

void ToolbarButton::OnMouseReleased(const ui::MouseEvent& event) {
  if (IsTriggerableEvent(event) ||
      (event.IsRightMouseButton() && !HitTestPoint(event.location()))) {
    LabelButton::OnMouseReleased(event);
  }

  if (IsTriggerableEvent(event))
    show_menu_factory_.InvalidateWeakPtrs();
}

void ToolbarButton::OnMouseCaptureLost() {
}

void ToolbarButton::OnMouseExited(const ui::MouseEvent& event) {
  // Starting a drag results in a MouseExited, we need to ignore it.
  // A right click release triggers an exit event. We want to
  // remain in a PUSHED state until the drop down menu closes.
  if (state_ != STATE_DISABLED && !InDrag() && state_ != STATE_PRESSED)
    SetState(STATE_NORMAL);
}

void ToolbarButton::OnGestureEvent(ui::GestureEvent* event) {
  if (menu_showing_) {
    // While dropdown menu is showing the button should not handle gestures.
    event->StopPropagation();
    return;
  }

  LabelButton::OnGestureEvent(event);
}

void ToolbarButton::GetAccessibleState(ui::AccessibleViewState* state) {
  CustomButton::GetAccessibleState(state);
  state->role = ui::AccessibilityTypes::ROLE_BUTTONDROPDOWN;
  state->default_action = l10n_util::GetStringUTF16(IDS_APP_ACCACTION_PRESS);
  state->state = ui::AccessibilityTypes::STATE_HASPOPUP;
}

void ToolbarButton::ShowContextMenuForView(View* source,
                                           const gfx::Point& point,
                                           ui::MenuSourceType source_type) {
  if (!enabled())
    return;

  show_menu_factory_.InvalidateWeakPtrs();
  ShowDropDownMenu(source_type);
}

bool ToolbarButton::ShouldEnterPushedState(const ui::Event& event) {
  // Enter PUSHED state on press with Left or Right mouse button or on taps.
  // Remain in this state while the context menu is open.
  return event.type() == ui::ET_GESTURE_TAP ||
         event.type() == ui::ET_GESTURE_TAP_DOWN ||
         (event.IsMouseEvent() && ((ui::EF_LEFT_MOUSE_BUTTON |
             ui::EF_RIGHT_MOUSE_BUTTON) & event.flags()) != 0);
}

bool ToolbarButton::ShouldShowMenu() {
  return model_ != NULL;
}

void ToolbarButton::ShowDropDownMenu(ui::MenuSourceType source_type) {
  if (!ShouldShowMenu())
    return;

  gfx::Rect lb = GetLocalBounds();

  // Both the menu position and the menu anchor type change if the UI layout
  // is right-to-left.
  gfx::Point menu_position(lb.origin());
  menu_position.Offset(0, lb.height() - 1);
  if (base::i18n::IsRTL())
    menu_position.Offset(lb.width() - 1, 0);

  View::ConvertPointToScreen(this, &menu_position);

#if defined(OS_WIN)
  int left_bound = GetSystemMetrics(SM_XVIRTUALSCREEN);
#elif defined(OS_CHROMEOS)
  // A window won't overlap between displays on ChromeOS.
  // Use the left bound of the display on which
  // the menu button exists.
  gfx::NativeView view = GetWidget()->GetNativeView();
  gfx::Display display = gfx::Screen::GetScreenFor(
      view)->GetDisplayNearestWindow(view);
  int left_bound = display.bounds().x();
#else
  int left_bound = 0;
  NOTIMPLEMENTED();
#endif
  if (menu_position.x() < left_bound)
    menu_position.set_x(left_bound);

  // Make the button look depressed while the menu is open.
  SetState(STATE_PRESSED);

  menu_showing_ = true;

  // Create and run menu.  Display an empty menu if model is NULL.
  if (model_.get()) {
    views::MenuModelAdapter menu_delegate(model_.get());
    menu_delegate.set_triggerable_event_flags(triggerable_event_flags());
    menu_runner_.reset(new views::MenuRunner(menu_delegate.CreateMenu()));
    views::MenuRunner::RunResult result =
        menu_runner_->RunMenuAt(GetWidget(), NULL,
                                gfx::Rect(menu_position, gfx::Size(0, 0)),
                                views::MenuItemView::TOPLEFT,
                                source_type,
                                views::MenuRunner::HAS_MNEMONICS);
    if (result == views::MenuRunner::MENU_DELETED)
      return;
  } else {
    views::MenuDelegate menu_delegate;
    views::MenuItemView* menu = new views::MenuItemView(&menu_delegate);
    menu_runner_.reset(new views::MenuRunner(menu));
    views::MenuRunner::RunResult result =
        menu_runner_->RunMenuAt(GetWidget(), NULL,
                                gfx::Rect(menu_position, gfx::Size(0, 0)),
                                views::MenuItemView::TOPLEFT,
                                source_type,
                                views::MenuRunner::HAS_MNEMONICS);
    if (result == views::MenuRunner::MENU_DELETED)
      return;
  }

  menu_showing_ = false;

  // Need to explicitly clear mouse handler so that events get sent
  // properly after the menu finishes running. If we don't do this, then
  // the first click to other parts of the UI is eaten.
  SetMouseHandler(NULL);

  // Set the state back to normal after the drop down menu is closed.
  if (state_ != STATE_DISABLED)
    SetState(STATE_NORMAL);
}
<commit_msg>linux_aura: Put toolbar dropdown menus on the screen with the cursor.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/toolbar/toolbar_button.h"

#include "base/bind.h"
#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include "grit/theme_resources.h"
#include "grit/ui_strings.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/menu_model.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/widget/widget.h"

ToolbarButton::ToolbarButton(views::ButtonListener* listener,
                             ui::MenuModel* model)
    : views::LabelButton(listener, base::string16()),
      model_(model),
      menu_showing_(false),
      y_position_on_lbuttondown_(0),
      show_menu_factory_(this) {
  set_context_menu_controller(this);
}

ToolbarButton::~ToolbarButton() {
}

void ToolbarButton::Init() {
  SetFocusable(false);
  SetAccessibilityFocusable(true);
  image()->EnableCanvasFlippingForRTLUI(true);
}

void ToolbarButton::ClearPendingMenu() {
  show_menu_factory_.InvalidateWeakPtrs();
}

bool ToolbarButton::IsMenuShowing() const {
  return menu_showing_;
}

gfx::Size ToolbarButton::GetPreferredSize() {
  gfx::Size size(image()->GetPreferredSize());
  gfx::Size label_size = label()->GetPreferredSize();
  if (label_size.width() > 0)
    size.Enlarge(label_size.width() + LocationBarView::GetItemPadding(), 0);
  return size;
}

bool ToolbarButton::OnMousePressed(const ui::MouseEvent& event) {
  if (enabled() && ShouldShowMenu() &&
      IsTriggerableEvent(event) && HitTestPoint(event.location())) {
    // Store the y pos of the mouse coordinates so we can use them later to
    // determine if the user dragged the mouse down (which should pop up the
    // drag down menu immediately, instead of waiting for the timer)
    y_position_on_lbuttondown_ = event.y();

    // Schedule a task that will show the menu.
    const int kMenuTimerDelay = 500;
    base::MessageLoop::current()->PostDelayedTask(
        FROM_HERE,
        base::Bind(&ToolbarButton::ShowDropDownMenu,
                   show_menu_factory_.GetWeakPtr(),
                   ui::GetMenuSourceTypeForEvent(event)),
        base::TimeDelta::FromMilliseconds(kMenuTimerDelay));
  }
  return LabelButton::OnMousePressed(event);
}

bool ToolbarButton::OnMouseDragged(const ui::MouseEvent& event) {
  bool result = LabelButton::OnMouseDragged(event);

  if (show_menu_factory_.HasWeakPtrs()) {
    // If the mouse is dragged to a y position lower than where it was when
    // clicked then we should not wait for the menu to appear but show
    // it immediately.
    if (event.y() > y_position_on_lbuttondown_ + GetHorizontalDragThreshold()) {
      show_menu_factory_.InvalidateWeakPtrs();
      ShowDropDownMenu(ui::GetMenuSourceTypeForEvent(event));
    }
  }

  return result;
}

void ToolbarButton::OnMouseReleased(const ui::MouseEvent& event) {
  if (IsTriggerableEvent(event) ||
      (event.IsRightMouseButton() && !HitTestPoint(event.location()))) {
    LabelButton::OnMouseReleased(event);
  }

  if (IsTriggerableEvent(event))
    show_menu_factory_.InvalidateWeakPtrs();
}

void ToolbarButton::OnMouseCaptureLost() {
}

void ToolbarButton::OnMouseExited(const ui::MouseEvent& event) {
  // Starting a drag results in a MouseExited, we need to ignore it.
  // A right click release triggers an exit event. We want to
  // remain in a PUSHED state until the drop down menu closes.
  if (state_ != STATE_DISABLED && !InDrag() && state_ != STATE_PRESSED)
    SetState(STATE_NORMAL);
}

void ToolbarButton::OnGestureEvent(ui::GestureEvent* event) {
  if (menu_showing_) {
    // While dropdown menu is showing the button should not handle gestures.
    event->StopPropagation();
    return;
  }

  LabelButton::OnGestureEvent(event);
}

void ToolbarButton::GetAccessibleState(ui::AccessibleViewState* state) {
  CustomButton::GetAccessibleState(state);
  state->role = ui::AccessibilityTypes::ROLE_BUTTONDROPDOWN;
  state->default_action = l10n_util::GetStringUTF16(IDS_APP_ACCACTION_PRESS);
  state->state = ui::AccessibilityTypes::STATE_HASPOPUP;
}

void ToolbarButton::ShowContextMenuForView(View* source,
                                           const gfx::Point& point,
                                           ui::MenuSourceType source_type) {
  if (!enabled())
    return;

  show_menu_factory_.InvalidateWeakPtrs();
  ShowDropDownMenu(source_type);
}

bool ToolbarButton::ShouldEnterPushedState(const ui::Event& event) {
  // Enter PUSHED state on press with Left or Right mouse button or on taps.
  // Remain in this state while the context menu is open.
  return event.type() == ui::ET_GESTURE_TAP ||
         event.type() == ui::ET_GESTURE_TAP_DOWN ||
         (event.IsMouseEvent() && ((ui::EF_LEFT_MOUSE_BUTTON |
             ui::EF_RIGHT_MOUSE_BUTTON) & event.flags()) != 0);
}

bool ToolbarButton::ShouldShowMenu() {
  return model_ != NULL;
}

void ToolbarButton::ShowDropDownMenu(ui::MenuSourceType source_type) {
  if (!ShouldShowMenu())
    return;

  gfx::Rect lb = GetLocalBounds();

  // Both the menu position and the menu anchor type change if the UI layout
  // is right-to-left.
  gfx::Point menu_position(lb.origin());
  menu_position.Offset(0, lb.height() - 1);
  if (base::i18n::IsRTL())
    menu_position.Offset(lb.width() - 1, 0);

  View::ConvertPointToScreen(this, &menu_position);

#if defined(OS_WIN)
  int left_bound = GetSystemMetrics(SM_XVIRTUALSCREEN);
#elif defined(OS_CHROMEOS)
  // A window won't overlap between displays on ChromeOS.
  // Use the left bound of the display on which
  // the menu button exists.
  gfx::NativeView view = GetWidget()->GetNativeView();
  gfx::Display display = gfx::Screen::GetScreenFor(
      view)->GetDisplayNearestWindow(view);
  int left_bound = display.bounds().x();
#else
  // The window might be positioned over the edge between two screens. We'll
  // want to position the dropdown on the screen the mouse cursor is on.
  gfx::NativeView view = GetWidget()->GetNativeView();
  gfx::Screen* screen = gfx::Screen::GetScreenFor(view);
  gfx::Display display = screen->GetDisplayNearestPoint(
      screen->GetCursorScreenPoint());
  int left_bound = display.bounds().x();
#endif
  if (menu_position.x() < left_bound)
    menu_position.set_x(left_bound);

  // Make the button look depressed while the menu is open.
  SetState(STATE_PRESSED);

  menu_showing_ = true;

  // Create and run menu.  Display an empty menu if model is NULL.
  if (model_.get()) {
    views::MenuModelAdapter menu_delegate(model_.get());
    menu_delegate.set_triggerable_event_flags(triggerable_event_flags());
    menu_runner_.reset(new views::MenuRunner(menu_delegate.CreateMenu()));
    views::MenuRunner::RunResult result =
        menu_runner_->RunMenuAt(GetWidget(), NULL,
                                gfx::Rect(menu_position, gfx::Size(0, 0)),
                                views::MenuItemView::TOPLEFT,
                                source_type,
                                views::MenuRunner::HAS_MNEMONICS);
    if (result == views::MenuRunner::MENU_DELETED)
      return;
  } else {
    views::MenuDelegate menu_delegate;
    views::MenuItemView* menu = new views::MenuItemView(&menu_delegate);
    menu_runner_.reset(new views::MenuRunner(menu));
    views::MenuRunner::RunResult result =
        menu_runner_->RunMenuAt(GetWidget(), NULL,
                                gfx::Rect(menu_position, gfx::Size(0, 0)),
                                views::MenuItemView::TOPLEFT,
                                source_type,
                                views::MenuRunner::HAS_MNEMONICS);
    if (result == views::MenuRunner::MENU_DELETED)
      return;
  }

  menu_showing_ = false;

  // Need to explicitly clear mouse handler so that events get sent
  // properly after the menu finishes running. If we don't do this, then
  // the first click to other parts of the UI is eaten.
  SetMouseHandler(NULL);

  // Set the state back to normal after the drop down menu is closed.
  if (state_ != STATE_DISABLED)
    SetState(STATE_NORMAL);
}
<|endoftext|>