<commit_before>#include "MacDisplay.h"
#include "BzfEvent.h"

#include <CoreFoundation/CoreFoundation.h>

bool     MacDisplay::pending;
CGrafPtr    MacDisplay::window;
CGLContextObj  MacDisplay::context;

MacDisplay::MacDisplay() {
  pending = true;

  setPassthroughSize(CGDisplayPixelsWide(kCGDirectMainDisplay),
      CGDisplayPixelsHigh(kCGDirectMainDisplay));
}

MacDisplay::MacDisplay(const char *, const char *) {
#pragma unused (name, videoFormat)
  is_valid      = true;
  pending       = false;

  cursor_region = NewRgn();
  ResInfo** resInfo = NULL;
  resInfo = new ResInfo*[1];
  resInfo[0] = new ResInfo("default",
  CGDisplayPixelsWide(kCGDirectMainDisplay),
  CGDisplayPixelsHigh(kCGDirectMainDisplay), 0);
  //numModes = 1;
  //currentMode = 0;

  // register modes
  initResolutions(resInfo, 1, 0);
}

bool MacDisplay::isEventPending() const
{
  ::OSStatus	status		= ::noErr;
  ::EventRef	eventRef	= 0;

  status = ::ReceiveNextEvent(0, NULL, 0, false, &eventRef);
  return (status == ::noErr) ? true : false;
}

bool MacDisplay::getEvent (BzfEvent &bzf_event) const {
  ::EventRef			eventRef		= 0;
  ::OSStatus			status			= ::noErr;
  ::UInt32				eventClass		= 0;
  ::UInt32				eventKind		= 0;
  ::EventTime			eventTime		= 0;
  ::HIPoint				eventLocation	= {0, 0};
  ::HIPoint				eventDelta		= {0, 0};
  ::UInt32				eventModifiers	= 0;
  ::EventMouseButton	eventButtons	= 0;
  char					eventChar		= 0;
  ::UInt32				eventKeyCode	= 0;
  ::WindowRef			eventWindow		= NULL;
  const ::Boolean		removeEventFromQueue = true;

  /* initialize the event for safety */
  bzf_event.keyDown.ascii = 0;
  bzf_event.keyDown.shift = 0;

  bzf_event.type = (BzfEvent::Type)-1;

  status = ::ReceiveNextEvent(0, NULL, 0, removeEventFromQueue, &eventRef);
  if(status != ::noErr) {
    return false;
  }

  eventTime = ::GetEventTime(eventRef);
  eventClass = ::GetEventClass(eventRef);
  eventKind = ::GetEventKind(eventRef);

  switch(eventClass) {
    case ::kEventClassMouse:
	  status = GetEventParameter(eventRef,
								 ::kEventParamWindowMouseLocation,
								 ::typeHIPoint,
								 NULL,
								 sizeof(::HIPoint),
								 NULL,
								 &eventLocation);
	  status = GetEventParameter(eventRef,
								 ::kEventParamKeyModifiers,
								 ::typeUInt32,
								 NULL,
								 sizeof(::UInt32),
								 NULL,
								 &eventModifiers);

	  status = GetEventParameter(eventRef,
								 ::kEventParamMouseButton,
								 ::typeMouseButton,
								 NULL,
								 sizeof(::EventMouseButton),
								 NULL,
								 &eventButtons);

	  status = GetEventParameter(eventRef,
								 ::kEventParamMouseDelta,
								 ::typeHIPoint,
								 NULL,
								 sizeof(::HIPoint),
								 NULL,
								 &eventDelta);

	  switch(eventKind) {
		case ::kEventMouseDown:
		case ::kEventMouseUp:
		  if(eventKind == ::kEventMouseDown) {
	bzf_event.type = BzfEvent::KeyDown;
		  } else {
		    bzf_event.type = BzfEvent::KeyUp;
		  }
	bzf_event.keyDown.ascii = 0;
	bzf_event.keyDown.shift = 0;
		  if(eventButtons > 9) {
			// bzflag only handles 9 buttons for now
			eventButtons = 9;
		  }

		  switch(eventButtons) {
		    case ::kEventMouseButtonSecondary: bzf_event.keyDown.button = BzfKeyEvent::RightMouse;	break;
		    case ::kEventMouseButtonTertiary: bzf_event.keyDown.button = BzfKeyEvent::MiddleMouse;	break;
		    default: bzf_event.keyDown.button = BzfKeyEvent::LeftMouse + eventButtons - 1;			break;
		  }
	break;

		case ::kEventMouseMoved:
		  bzf_event.type = BzfEvent::MouseMove;
		  bzf_event.mouseMove.x = static_cast<int>(eventDelta.x);
		  bzf_event.mouseMove.y = static_cast<int>(eventDelta.y);
		break;

		case ::kEventMouseWheelMoved:
		break;
	  }
	break;

    case ::kEventClassKeyboard:
	  status = GetEventParameter(eventRef,
								 ::kEventParamKeyMacCharCodes,
								 ::typeChar,
								 NULL,
								 sizeof(char),
								 NULL,
								 &eventChar);
	  status = GetEventParameter(eventRef,
								 ::kEventParamKeyCode,
								 ::typeUInt32,
								 NULL,
								 sizeof(eventKeyCode),
								 NULL,
								 &eventKeyCode);
	  switch(eventKind) {
		case ::kEventRawKeyDown:
		case ::kEventRawKeyRepeat:
			bzf_event.type = BzfEvent::KeyDown;
			getKey(bzf_event.keyDown, eventChar, eventKeyCode);
		break;

		case ::kEventRawKeyUp:
			bzf_event.type = BzfEvent::KeyUp;
			getKey(bzf_event.keyUp, eventChar, eventKeyCode);
		break;
	  }
	break;

    case ::kEventClassApplication:
	  switch(eventKind) {
		case ::kEventAppQuit:
		break;
	  }
	break;

    case ::kEventClassWindow:
	  status = GetEventParameter(eventRef,
								 ::kEventParamDirectObject,
								 ::typeWindowRef,
								 NULL,
								 sizeof(::WindowRef),
								 NULL,
								 &eventWindow);
	  switch(eventKind) {
	    case ::kEventWindowUpdate:
	    case ::kEventWindowDrawContent:
		  bzf_event.type = BzfEvent::Redraw;
		  BeginUpdate(eventWindow);
		  EndUpdate(eventWindow);
	    break;
	}
	break;

    case ::kEventClassCommand:
	  switch(eventKind) {
	  }
	break;
    }
  ReleaseEvent(eventRef);
    return true;
  }

void MacDisplay::getKey (BzfKeyEvent &bzf_key, char char_code, ::UInt32 keycode) const {
  enum {
	  kF1KeyCode	 = 0x7A,	// Undo
	  kF2KeyCode	 = 0x78,	// Cut
	  kF3KeyCode	 = 0x63,	// Copy
	  kF4KeyCode	 = 0x76,	// Paste
	  kF5KeyCode	 = 0x60,
	  kF6KeyCode	 = 0x61,
	  kF7KeyCode	 = 0x62,
	  kF8KeyCode	 = 0x64,
	  kF9KeyCode	 = 0x65,
	  kF10KeyCode	 = 0x6D,
	  kF11KeyCode	 = 0x67,
	  kF12KeyCode	 = 0x6F,
	  kF13KeyCode	 = 0x69,	// Print Screen
	  kF14KeyCode	 = 0x6B,	// Scroll Lock
	  kF15KeyCode	 = 0x71,	// Pause
  };
  bzf_key.ascii = 0;
  bzf_key.button = BzfKeyEvent::NoButton;
  switch (char_code) {
    case kUpArrowCharCode   : bzf_key.button = BzfKeyEvent::Up;       break;
    case kDownArrowCharCode : bzf_key.button = BzfKeyEvent::Down;     break;
    case kLeftArrowCharCode : bzf_key.button = BzfKeyEvent::Left;     break;
    case kRightArrowCharCode: bzf_key.button = BzfKeyEvent::Right;    break;
    case kHomeCharCode      : bzf_key.button = BzfKeyEvent::Home;     break;
    case kEndCharCode       : bzf_key.button = BzfKeyEvent::End;      break;
    case kPageUpCharCode    : bzf_key.button = BzfKeyEvent::PageUp;   break;
    case kPageDownCharCode  : bzf_key.button = BzfKeyEvent::PageDown; break;
    case kHelpCharCode      : bzf_key.button = BzfKeyEvent::Insert;   break;
    case kDeleteCharCode    : bzf_key.button = BzfKeyEvent::Delete;   break;
    case kFunctionKeyCharCode:
		switch(keycode) {
		// These are the f-key codes on my apple extended keyboard
		case kF15KeyCode:	bzf_key.button = BzfKeyEvent::Pause; break;
		case kF12KeyCode:	bzf_key.button = BzfKeyEvent::F12;	break;
		case kF11KeyCode:	bzf_key.button = BzfKeyEvent::F11;	break;
		case kF10KeyCode:	bzf_key.button = BzfKeyEvent::F10;	break;
		case kF9KeyCode:	bzf_key.button = BzfKeyEvent::F9;	break;
		case kF8KeyCode:	bzf_key.button = BzfKeyEvent::F8;	break;
		case kF7KeyCode:	bzf_key.button = BzfKeyEvent::F7;	break;
		case kF6KeyCode:	bzf_key.button = BzfKeyEvent::F6;	break;
		case kF5KeyCode:	bzf_key.button = BzfKeyEvent::F5;	break;
		case kF4KeyCode:	bzf_key.button = BzfKeyEvent::F4;	break;
		case kF3KeyCode:	bzf_key.button = BzfKeyEvent::F3;	break;
		case kF2KeyCode:	bzf_key.button = BzfKeyEvent::F2;	break;
		case kF1KeyCode:	bzf_key.button = BzfKeyEvent::F1;	break;
		default:	fprintf(stderr, "Uknown function key code: 0x%lX\n", keycode);	break;
		}
    break;
	// standard key; a-z, 0-9 etc
	default:	bzf_key.ascii  = char_code;		break;
  }
}

// if -directory is not used, this function is used to get the default path
// to the data directory which is located in the same directory as the
// application bundle
char *GetMacOSXDataPath(void)
{
  ::CFBundleRef	appBundle		= NULL;
  ::CFURLRef	resourceURL		= NULL;
  char *		string			= NULL;
  static char	basePath[2048]	= "<undefined resource path>";

  if ((appBundle = ::CFBundleGetMainBundle()) == NULL
  || (resourceURL = ::CFBundleCopyResourcesDirectoryURL(appBundle)) == NULL) {
    return NULL;
  }
  if(!::CFURLGetFileSystemRepresentation(resourceURL,
					true, reinterpret_cast<UInt8 *>(basePath), sizeof(basePath))) {
	string = NULL;
  } else {
	string = basePath;
  }
  ::CFRelease(resourceURL);
  fprintf(stderr, "data path is \"%s\"\n", string);
  return string;
}

// Local variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>Clean up the OS X key handling. Finally added support for the dang key modifiers for shift, alt, and control. Command is mapped to alt; command/alt clicking is a right mouse event. So.. now right click game entry can actually work on a one button mouse as expected and I finally get to see how that dang observer-mode movement works...<commit_after>#include "MacDisplay.h"
#include "BzfEvent.h"

#include <CoreFoundation/CoreFoundation.h>

bool     MacDisplay::pending;
CGrafPtr    MacDisplay::window;
CGLContextObj  MacDisplay::context;

MacDisplay::MacDisplay() {
  pending = true;

  setPassthroughSize(CGDisplayPixelsWide(kCGDirectMainDisplay),
		     CGDisplayPixelsHigh(kCGDirectMainDisplay));
}

MacDisplay::MacDisplay(const char *, const char *) {
#pragma unused (name, videoFormat)
  is_valid      = true;
  pending       = false;

  cursor_region = NewRgn();
  ResInfo** resInfo = NULL;
  resInfo = new ResInfo*[1];
  resInfo[0] = new ResInfo("default",
			   CGDisplayPixelsWide(kCGDirectMainDisplay),
			   CGDisplayPixelsHigh(kCGDirectMainDisplay), 0);
  //numModes = 1;
  //currentMode = 0;

  // register modes
  initResolutions(resInfo, 1, 0);
}

bool MacDisplay::isEventPending() const
{
  ::OSStatus	status		= ::noErr;
  ::EventRef	eventRef	= 0;

  status = ::ReceiveNextEvent(0, NULL, 0, false, &eventRef);
  return (status == ::noErr) ? true : false;
}

bool MacDisplay::getEvent (BzfEvent &bzf_event) const {
  ::EventRef		eventRef	= 0;
  ::OSStatus		status		= ::noErr;
  ::UInt32		eventClass	= 0;
  ::UInt32		eventKind	= 0;
  ::EventTime		eventTime	= 0;
  ::HIPoint		eventLocation	= {0, 0};
  ::HIPoint		eventDelta	= {0, 0};
  ::UInt32		eventModifiers	= 0;
  ::EventMouseButton	eventButtons	= 0;
  char			eventChar	= 0;
  ::UInt32		eventKeyCode	= 0;
  ::WindowRef		eventWindow	= NULL;
  const ::Boolean	removeEventFromQueue = true;

  /* initialize the event for safety */
  bzf_event.keyDown.ascii = 0;

  bzf_event.type = (BzfEvent::Type)-1;

  status = ::ReceiveNextEvent(0, NULL, 0, removeEventFromQueue, &eventRef);
  if(status != ::noErr) {
    return false;
  }

  eventTime = ::GetEventTime(eventRef);
  eventClass = ::GetEventClass(eventRef);
  eventKind = ::GetEventKind(eventRef);

  // make note of any modifiers being pressed
  bzf_event.keyDown.shift = 0;
  status = GetEventParameter(eventRef,
			     ::kEventParamKeyModifiers,
			     ::typeUInt32,
			     NULL,
			     sizeof(::UInt32),
			     NULL,
			     &eventModifiers);
  if (eventModifiers & cmdKey) {
    // command and option both serve as bzflag alt even
    bzf_event.keyDown.shift = BzfKeyEvent::AltKey;
  }
  if (eventModifiers & shiftKey) bzf_event.keyDown.shift = BzfKeyEvent::ShiftKey;
  if (eventModifiers & optionKey) bzf_event.keyDown.shift = BzfKeyEvent::AltKey;
  if (eventModifiers & controlKey) bzf_event.keyDown.shift = BzfKeyEvent::ControlKey;

  switch(eventClass) {
  case ::kEventClassMouse:
    status = GetEventParameter(eventRef,
			       ::kEventParamWindowMouseLocation,
			       ::typeHIPoint,
			       NULL,
			       sizeof(::HIPoint),
			       NULL,
			       &eventLocation);

    status = GetEventParameter(eventRef,
			       ::kEventParamMouseButton,
			       ::typeMouseButton,
			       NULL,
			       sizeof(::EventMouseButton),
			       NULL,
			       &eventButtons);

    status = GetEventParameter(eventRef,
			       ::kEventParamMouseDelta,
			       ::typeHIPoint,
			       NULL,
			       sizeof(::HIPoint),
			       NULL,
			       &eventDelta);

    // handle the main event type
    switch(eventKind) {
    case ::kEventMouseDown:
    case ::kEventMouseUp:
      if(eventKind == ::kEventMouseDown) {
	bzf_event.type = BzfEvent::KeyDown;
      } else {
	bzf_event.type = BzfEvent::KeyUp;
      }
      if(eventButtons > 9) {
	// bzflag only handles 9 buttons for now
	eventButtons = 9;
      }

      switch(eventButtons) {
      case ::kEventMouseButtonSecondary:
	bzf_event.keyDown.button = BzfKeyEvent::RightMouse;
	break;
      case ::kEventMouseButtonTertiary:
	bzf_event.keyDown.button = BzfKeyEvent::MiddleMouse;
	break;
      default:
	/* consistent wth the rest of the mac experience, a command click is
	 * the same as a right click.
	 */
	if (bzf_event.keyDown.shift == BzfKeyEvent::AltKey) {
	  bzf_event.keyDown.shift = 0;
	  bzf_event.keyDown.button = BzfKeyEvent::RightMouse;
	} else {
	  bzf_event.keyDown.button = BzfKeyEvent::LeftMouse + eventButtons - 1;
	}
	break;
      }
      break;

    case ::kEventMouseMoved:
      bzf_event.type = BzfEvent::MouseMove;
      bzf_event.mouseMove.x = static_cast<int>(eventDelta.x);
      bzf_event.mouseMove.y = static_cast<int>(eventDelta.y);
      break;

    case ::kEventMouseWheelMoved:
      break;
    }
    break;

  case ::kEventClassKeyboard:
    status = GetEventParameter(eventRef,
			       ::kEventParamKeyMacCharCodes,
			       ::typeChar,
			       NULL,
			       sizeof(char),
			       NULL,
			       &eventChar);
    status = GetEventParameter(eventRef,
			       ::kEventParamKeyCode,
			       ::typeUInt32,
			       NULL,
			       sizeof(eventKeyCode),
			       NULL,
			       &eventKeyCode);
    switch(eventKind) {
    case ::kEventRawKeyDown:
    case ::kEventRawKeyRepeat:
      bzf_event.type = BzfEvent::KeyDown;
      getKey(bzf_event.keyDown, eventChar, eventKeyCode);
      break;

    case ::kEventRawKeyUp:
      bzf_event.type = BzfEvent::KeyUp;
      getKey(bzf_event.keyUp, eventChar, eventKeyCode);
      break;
    }
    break;

  case ::kEventClassApplication:
    switch(eventKind) {
    case ::kEventAppQuit:
      bzf_event.type = BzfEvent::Quit;
      break;
    }
    break;

  case ::kEventClassWindow:
    status = GetEventParameter(eventRef,
			       ::kEventParamDirectObject,
			       ::typeWindowRef,
			       NULL,
			       sizeof(::WindowRef),
			       NULL,
			       &eventWindow);
    switch(eventKind) {
    case ::kEventWindowUpdate:
    case ::kEventWindowDrawContent:
      bzf_event.type = BzfEvent::Redraw;
      BeginUpdate(eventWindow);
      EndUpdate(eventWindow);
      break;
    }
    break;

  case ::kEventClassCommand:
    switch(eventKind) {
    }
    break;
  }
  ReleaseEvent(eventRef);
  return true;
}

void MacDisplay::getKey (BzfKeyEvent &bzf_key, char char_code, ::UInt32 keycode) const {
  enum {
    kF1KeyCode	 = 0x7A,	// Undo
    kF2KeyCode	 = 0x78,	// Cut
    kF3KeyCode	 = 0x63,	// Copy
    kF4KeyCode	 = 0x76,	// Paste
    kF5KeyCode	 = 0x60,
    kF6KeyCode	 = 0x61,
    kF7KeyCode	 = 0x62,
    kF8KeyCode	 = 0x64,
    kF9KeyCode	 = 0x65,
    kF10KeyCode	 = 0x6D,
    kF11KeyCode	 = 0x67,
    kF12KeyCode	 = 0x6F,
    kF13KeyCode	 = 0x69,	// Print Screen
    kF14KeyCode	 = 0x6B,	// Scroll Lock
    kF15KeyCode	 = 0x71,	// Pause
  };
  bzf_key.ascii = 0;
  bzf_key.button = BzfKeyEvent::NoButton;
  switch (char_code) {
  case kUpArrowCharCode   : bzf_key.button = BzfKeyEvent::Up;       break;
  case kDownArrowCharCode : bzf_key.button = BzfKeyEvent::Down;     break;
  case kLeftArrowCharCode : bzf_key.button = BzfKeyEvent::Left;     break;
  case kRightArrowCharCode: bzf_key.button = BzfKeyEvent::Right;    break;
  case kHomeCharCode      : bzf_key.button = BzfKeyEvent::Home;     break;
  case kEndCharCode       : bzf_key.button = BzfKeyEvent::End;      break;
  case kPageUpCharCode    : bzf_key.button = BzfKeyEvent::PageUp;   break;
  case kPageDownCharCode  : bzf_key.button = BzfKeyEvent::PageDown; break;
  case kHelpCharCode      : bzf_key.button = BzfKeyEvent::Insert;   break;
  case kDeleteCharCode    : bzf_key.button = BzfKeyEvent::Delete;   break;
  case kFunctionKeyCharCode:
    switch(keycode) {
      // These are the f-key codes on my apple extended keyboard
    case kF15KeyCode:	bzf_key.button = BzfKeyEvent::Pause; break;
    case kF12KeyCode:	bzf_key.button = BzfKeyEvent::F12;	break;
    case kF11KeyCode:	bzf_key.button = BzfKeyEvent::F11;	break;
    case kF10KeyCode:	bzf_key.button = BzfKeyEvent::F10;	break;
    case kF9KeyCode:	bzf_key.button = BzfKeyEvent::F9;	break;
    case kF8KeyCode:	bzf_key.button = BzfKeyEvent::F8;	break;
    case kF7KeyCode:	bzf_key.button = BzfKeyEvent::F7;	break;
    case kF6KeyCode:	bzf_key.button = BzfKeyEvent::F6;	break;
    case kF5KeyCode:	bzf_key.button = BzfKeyEvent::F5;	break;
    case kF4KeyCode:	bzf_key.button = BzfKeyEvent::F4;	break;
    case kF3KeyCode:	bzf_key.button = BzfKeyEvent::F3;	break;
    case kF2KeyCode:	bzf_key.button = BzfKeyEvent::F2;	break;
    case kF1KeyCode:	bzf_key.button = BzfKeyEvent::F1;	break;
    default:	fprintf(stderr, "Uknown function key code: 0x%lX\n", keycode);	break;
    }
    break;
    // standard key; a-z, 0-9 etc
  default:	bzf_key.ascii  = char_code;		break;
  }
}

// if -directory is not used, this function is used to get the default path
// to the data directory which is located in the same directory as the
// application bundle
char *GetMacOSXDataPath(void)
{
  ::CFBundleRef	appBundle		= NULL;
  ::CFURLRef	resourceURL		= NULL;
  char *		string			= NULL;
  static char	basePath[2048]	= "<undefined resource path>";

  if ((appBundle = ::CFBundleGetMainBundle()) == NULL
      || (resourceURL = ::CFBundleCopyResourcesDirectoryURL(appBundle)) == NULL) {
    return NULL;
  }
  if(!::CFURLGetFileSystemRepresentation(resourceURL,
					 true, reinterpret_cast<UInt8 *>(basePath), sizeof(basePath))) {
    string = NULL;
  } else {
    string = basePath;
  }
  ::CFRelease(resourceURL);
  fprintf(stderr, "data path is \"%s\"\n", string);
  return string;
}

// Local variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "TextureResourceD3D11.h"
#include "RendererD3D11.h"
#include "core/Engine.h"
#include "utils/Log.h"

namespace ouzel
{
    namespace graphics
    {
        static DXGI_FORMAT getD3D11PixelFormat(PixelFormat pixelFormat)
        {
            switch (pixelFormat)
            {
                case PixelFormat::A8_UNORM: return DXGI_FORMAT_A8_UNORM;
                case PixelFormat::R8_UNORM: return DXGI_FORMAT_R8_UNORM;
                case PixelFormat::R8_SNORM: return DXGI_FORMAT_R8_SNORM;
                case PixelFormat::R8_UINT: return DXGI_FORMAT_R8_UINT;
                case PixelFormat::R8_SINT: return DXGI_FORMAT_R8_SINT;
                case PixelFormat::R16_UNORM: return DXGI_FORMAT_R16_UNORM;
                case PixelFormat::R16_SNORM: return DXGI_FORMAT_R16_SNORM;
                case PixelFormat::R16_UINT: return DXGI_FORMAT_R16_UINT;
                case PixelFormat::R16_SINT: return DXGI_FORMAT_R16_SINT;
                case PixelFormat::R16_FLOAT: return DXGI_FORMAT_R16_FLOAT;
                case PixelFormat::R32_UINT: return DXGI_FORMAT_R32_UINT;
                case PixelFormat::R32_SINT: return DXGI_FORMAT_R32_SINT;
                case PixelFormat::R32_FLOAT: return DXGI_FORMAT_R32_FLOAT;
                case PixelFormat::RG8_UNORM: return DXGI_FORMAT_R8G8_UNORM;
                case PixelFormat::RG8_SNORM: return DXGI_FORMAT_R8G8_SNORM;
                case PixelFormat::RG8_UINT: return DXGI_FORMAT_R8G8_UINT;
                case PixelFormat::RG8_SINT: return DXGI_FORMAT_R8G8_SINT;
                case PixelFormat::RGBA8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM;
                case PixelFormat::RGBA8_SNORM: return DXGI_FORMAT_R8G8B8A8_SNORM;
                case PixelFormat::RGBA8_UINT: return DXGI_FORMAT_R8G8B8A8_UINT;
                case PixelFormat::RGBA8_SINT: return DXGI_FORMAT_R8G8B8A8_SINT;
                case PixelFormat::RGBA16_UNORM: return DXGI_FORMAT_R16G16B16A16_UNORM;
                case PixelFormat::RGBA16_SNORM: return DXGI_FORMAT_R16G16B16A16_SNORM;
                case PixelFormat::RGBA16_UINT: return DXGI_FORMAT_R16G16B16A16_UINT;
                case PixelFormat::RGBA16_SINT: return DXGI_FORMAT_R16G16B16A16_SINT;
                case PixelFormat::RGBA16_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT;
                case PixelFormat::RGBA32_UINT: return DXGI_FORMAT_R32G32B32A32_UINT;
                case PixelFormat::RGBA32_SINT: return DXGI_FORMAT_R32G32B32A32_SINT;
                case PixelFormat::RGBA32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT;
                default: return DXGI_FORMAT_UNKNOWN;
            }
        }

        TextureResourceD3D11::TextureResourceD3D11()
        {
        }

        TextureResourceD3D11::~TextureResourceD3D11()
        {
            if (depthStencilTexture)
            {
                depthStencilTexture->Release();
            }

            if (depthStencilView)
            {
                depthStencilView->Release();
            }

            if (renderTargetView)
            {
                renderTargetView->Release();
            }

            if (resourceView)
            {
                resourceView->Release();
            }

            if (texture)
            {
                texture->Release();
            }

            if (samplerState)
            {
                samplerState->Release();
            }

            width = 0;
            height = 0;
        }

        bool TextureResourceD3D11::upload()
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            if (dirty)
            {
                RendererD3D11* rendererD3D11 = static_cast<RendererD3D11*>(sharedEngine->getRenderer());

                if (dirty & DIRTY_DATA)
                {
                    if (size.v[0] > 0 &&
                        size.v[1] > 0)
                    {
                        if (!texture ||
                            static_cast<UINT>(size.v[0]) != width ||
                            static_cast<UINT>(size.v[1]) != height)
                        {
                            if (texture)
                            {
                                texture->Release();
                            }

                            if (resourceView)
                            {
                                resourceView->Release();
                                resourceView = nullptr;
                            }

                            width = static_cast<UINT>(size.v[0]);
                            height = static_cast<UINT>(size.v[1]);

                            DXGI_FORMAT d3d11PixelFormat = getD3D11PixelFormat(pixelFormat);

                            if (d3d11PixelFormat == DXGI_FORMAT_UNKNOWN)
                            {
                                Log(Log::Level::ERR) << "Invalid pixel format";
                                return false;
                            }

                            D3D11_TEXTURE2D_DESC textureDesc;
                            textureDesc.Width = width;
                            textureDesc.Height = height;
                            textureDesc.MipLevels = (levels.size() > 1) ? 0 : 1;
                            textureDesc.ArraySize = 1;
                            textureDesc.Format = d3d11PixelFormat;
                            textureDesc.Usage = (dynamic && !renderTarget) ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
                            textureDesc.CPUAccessFlags = (dynamic && !renderTarget) ? D3D11_CPU_ACCESS_WRITE : 0;
                            textureDesc.SampleDesc.Count = sampleCount;
                            textureDesc.SampleDesc.Quality = 0;
                            textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | (renderTarget ? D3D11_BIND_RENDER_TARGET : 0);
                            textureDesc.MiscFlags = 0;

                            HRESULT hr = rendererD3D11->getDevice()->CreateTexture2D(&textureDesc, nullptr, &texture);
                            if (FAILED(hr))
                            {
                                Log(Log::Level::ERR) << "Failed to create Direct3D 11 texture, error: " << hr;
                                return false;
                            }

                            D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
                            resourceViewDesc.Format = d3d11PixelFormat;
                            resourceViewDesc.ViewDimension = (sampleCount > 1) ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D;

                            if (sampleCount == 1)
                            {
                                resourceViewDesc.Texture2D.MostDetailedMip = 0;
                                resourceViewDesc.Texture2D.MipLevels = static_cast<UINT>(levels.size());
                            }

                            hr = rendererD3D11->getDevice()->CreateShaderResourceView(texture, &resourceViewDesc, &resourceView);
                            if (FAILED(hr))
                            {
                                Log(Log::Level::ERR) << "Failed to create Direct3D 11 shader resource view, error: " << hr;
                                return false;
                            }

                            if (renderTarget)
                            {
                                if (renderTargetView)
                                {
                                    renderTargetView->Release();
                                }

                                D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
                                renderTargetViewDesc.Format = d3d11PixelFormat;
                                renderTargetViewDesc.ViewDimension = (sampleCount > 1) ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D;

                                if (sampleCount == 1)
                                {
                                    renderTargetViewDesc.Texture2D.MipSlice = 0;
                                }

                                hr = rendererD3D11->getDevice()->CreateRenderTargetView(texture, &renderTargetViewDesc, &renderTargetView);
                                if (FAILED(hr))
                                {
                                    Log(Log::Level::ERR) << "Failed to create Direct3D 11 render target view, error: " << hr;
                                    return false;
                                }
                            }

                            if (depth)
                            {
                                if (depthStencilTexture)
                                {
                                    depthStencilTexture->Release();
                                }

                                if (depthStencilView)
                                {
                                    depthStencilView->Release();
                                    depthStencilView = nullptr;
                                }

                                D3D11_TEXTURE2D_DESC depthStencilDesc;
                                depthStencilDesc.Width = width;
                                depthStencilDesc.Height = height;
                                depthStencilDesc.MipLevels = 1;
                                depthStencilDesc.ArraySize = 1;
                                depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT;
                                depthStencilDesc.SampleDesc.Count = sampleCount;
                                depthStencilDesc.SampleDesc.Quality = 0;
                                depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
                                depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
                                depthStencilDesc.CPUAccessFlags = 0;
                                depthStencilDesc.MiscFlags = 0;
                                hr = rendererD3D11->getDevice()->CreateTexture2D(&depthStencilDesc, nullptr, &depthStencilTexture);
                                if (FAILED(hr))
                                {
                                    Log(Log::Level::ERR) << "Failed to create Direct3D 11 depth stencil texture, error: " << hr;
                                    return false;
                                }

                                hr = rendererD3D11->getDevice()->CreateDepthStencilView(depthStencilTexture, nullptr, &depthStencilView);
                                if (FAILED(hr))
                                {
                                    Log(Log::Level::ERR) << "Failed to create Direct3D 11 depth stencil view, error: " << hr;
                                    return false;
                                }
                            }
                        }

                        if (dynamic)
                        {
                            for (size_t level = 0; level < levels.size(); ++level)
                            {
                                if (!levels[level].data.empty())
                                {
                                    D3D11_MAPPED_SUBRESOURCE mappedSubresource;
                                    mappedSubresource.pData = 0;
                                    mappedSubresource.RowPitch = 0;
                                    mappedSubresource.DepthPitch = 0;

                                    HRESULT hr = rendererD3D11->getContext()->Map(texture, static_cast<UINT>(level),
                                                                                (level == 0) ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE,
                                                                                0, &mappedSubresource);

                                    if (FAILED(hr))
                                    {
                                        Log(Log::Level::ERR) << "Failed to map Direct3D 11 texture, error: " << hr;
                                        return false;
                                    }

                                    std::copy(levels[level].data.begin(), levels[level].data.end(),
                                              reinterpret_cast<uint8_t*>(mappedSubresource.pData));

                                    rendererD3D11->getContext()->Unmap(texture, static_cast<UINT>(level));
                                }
                            }
                        }
                        else
                        {
                            for (size_t level = 0; level < levels.size(); ++level)
                            {
                                if (!levels[level].data.empty())
                                {
                                    rendererD3D11->getContext()->UpdateSubresource(texture, static_cast<UINT>(level),
                                                                                nullptr, levels[level].data.data(),
                                                                                static_cast<UINT>(levels[level].pitch), 0);
                                }
                            }
                        }
                    }
                }

                if (dirty & DIRTY_PARAMETERS)
                {
                    clearFrameBufferView = clearColorBuffer;
                    clearDepthBufferView = clearDepthBuffer;

                    frameBufferClearColor[0] = clearColor.normR();
                    frameBufferClearColor[1] = clearColor.normG();
                    frameBufferClearColor[2] = clearColor.normB();
                    frameBufferClearColor[3] = clearColor.normA();

                    if (samplerState) samplerState->Release();

                    RendererD3D11::SamplerStateDesc samplerDesc;
                    samplerDesc.filter = (filter == Texture::Filter::DEFAULT) ? rendererD3D11->getTextureFilter() : filter;
                    samplerDesc.addressX = addressX;
                    samplerDesc.addressY = addressY;
                    samplerDesc.maxAnisotropy = (maxAnisotropy == 0) ? rendererD3D11->getMaxAnisotropy() : maxAnisotropy;

                    samplerState = rendererD3D11->getSamplerState(samplerDesc);

                    if (!samplerState)
                    {
                        Log(Log::Level::ERR) << "Failed to get D3D11 sampler state";
                        return false;
                    }

                    samplerState->AddRef();
                }

                dirty = 0;
            }

            return true;
        }
    } // namespace graphics
} // namespace ouzel
<commit_msg>Upload texture only single row at a time to take care of the row pitch<commit_after>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "TextureResourceD3D11.h"
#include "RendererD3D11.h"
#include "core/Engine.h"
#include "utils/Log.h"

namespace ouzel
{
    namespace graphics
    {
        static DXGI_FORMAT getD3D11PixelFormat(PixelFormat pixelFormat)
        {
            switch (pixelFormat)
            {
                case PixelFormat::A8_UNORM: return DXGI_FORMAT_A8_UNORM;
                case PixelFormat::R8_UNORM: return DXGI_FORMAT_R8_UNORM;
                case PixelFormat::R8_SNORM: return DXGI_FORMAT_R8_SNORM;
                case PixelFormat::R8_UINT: return DXGI_FORMAT_R8_UINT;
                case PixelFormat::R8_SINT: return DXGI_FORMAT_R8_SINT;
                case PixelFormat::R16_UNORM: return DXGI_FORMAT_R16_UNORM;
                case PixelFormat::R16_SNORM: return DXGI_FORMAT_R16_SNORM;
                case PixelFormat::R16_UINT: return DXGI_FORMAT_R16_UINT;
                case PixelFormat::R16_SINT: return DXGI_FORMAT_R16_SINT;
                case PixelFormat::R16_FLOAT: return DXGI_FORMAT_R16_FLOAT;
                case PixelFormat::R32_UINT: return DXGI_FORMAT_R32_UINT;
                case PixelFormat::R32_SINT: return DXGI_FORMAT_R32_SINT;
                case PixelFormat::R32_FLOAT: return DXGI_FORMAT_R32_FLOAT;
                case PixelFormat::RG8_UNORM: return DXGI_FORMAT_R8G8_UNORM;
                case PixelFormat::RG8_SNORM: return DXGI_FORMAT_R8G8_SNORM;
                case PixelFormat::RG8_UINT: return DXGI_FORMAT_R8G8_UINT;
                case PixelFormat::RG8_SINT: return DXGI_FORMAT_R8G8_SINT;
                case PixelFormat::RGBA8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM;
                case PixelFormat::RGBA8_SNORM: return DXGI_FORMAT_R8G8B8A8_SNORM;
                case PixelFormat::RGBA8_UINT: return DXGI_FORMAT_R8G8B8A8_UINT;
                case PixelFormat::RGBA8_SINT: return DXGI_FORMAT_R8G8B8A8_SINT;
                case PixelFormat::RGBA16_UNORM: return DXGI_FORMAT_R16G16B16A16_UNORM;
                case PixelFormat::RGBA16_SNORM: return DXGI_FORMAT_R16G16B16A16_SNORM;
                case PixelFormat::RGBA16_UINT: return DXGI_FORMAT_R16G16B16A16_UINT;
                case PixelFormat::RGBA16_SINT: return DXGI_FORMAT_R16G16B16A16_SINT;
                case PixelFormat::RGBA16_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT;
                case PixelFormat::RGBA32_UINT: return DXGI_FORMAT_R32G32B32A32_UINT;
                case PixelFormat::RGBA32_SINT: return DXGI_FORMAT_R32G32B32A32_SINT;
                case PixelFormat::RGBA32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT;
                default: return DXGI_FORMAT_UNKNOWN;
            }
        }

        TextureResourceD3D11::TextureResourceD3D11()
        {
        }

        TextureResourceD3D11::~TextureResourceD3D11()
        {
            if (depthStencilTexture)
            {
                depthStencilTexture->Release();
            }

            if (depthStencilView)
            {
                depthStencilView->Release();
            }

            if (renderTargetView)
            {
                renderTargetView->Release();
            }

            if (resourceView)
            {
                resourceView->Release();
            }

            if (texture)
            {
                texture->Release();
            }

            if (samplerState)
            {
                samplerState->Release();
            }

            width = 0;
            height = 0;
        }

        bool TextureResourceD3D11::upload()
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            if (dirty)
            {
                RendererD3D11* rendererD3D11 = static_cast<RendererD3D11*>(sharedEngine->getRenderer());

                if (dirty & DIRTY_DATA)
                {
                    if (size.v[0] > 0 &&
                        size.v[1] > 0)
                    {
                        if (!texture ||
                            static_cast<UINT>(size.v[0]) != width ||
                            static_cast<UINT>(size.v[1]) != height)
                        {
                            if (texture)
                            {
                                texture->Release();
                            }

                            if (resourceView)
                            {
                                resourceView->Release();
                                resourceView = nullptr;
                            }

                            width = static_cast<UINT>(size.v[0]);
                            height = static_cast<UINT>(size.v[1]);

                            DXGI_FORMAT d3d11PixelFormat = getD3D11PixelFormat(pixelFormat);

                            if (d3d11PixelFormat == DXGI_FORMAT_UNKNOWN)
                            {
                                Log(Log::Level::ERR) << "Invalid pixel format";
                                return false;
                            }

                            D3D11_TEXTURE2D_DESC textureDesc;
                            textureDesc.Width = width;
                            textureDesc.Height = height;
                            textureDesc.MipLevels = (levels.size() > 1) ? 0 : 1;
                            textureDesc.ArraySize = 1;
                            textureDesc.Format = d3d11PixelFormat;
                            textureDesc.Usage = (dynamic && !renderTarget) ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
                            textureDesc.CPUAccessFlags = (dynamic && !renderTarget) ? D3D11_CPU_ACCESS_WRITE : 0;
                            textureDesc.SampleDesc.Count = sampleCount;
                            textureDesc.SampleDesc.Quality = 0;
                            textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | (renderTarget ? D3D11_BIND_RENDER_TARGET : 0);
                            textureDesc.MiscFlags = 0;

                            HRESULT hr = rendererD3D11->getDevice()->CreateTexture2D(&textureDesc, nullptr, &texture);
                            if (FAILED(hr))
                            {
                                Log(Log::Level::ERR) << "Failed to create Direct3D 11 texture, error: " << hr;
                                return false;
                            }

                            D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
                            resourceViewDesc.Format = d3d11PixelFormat;
                            resourceViewDesc.ViewDimension = (sampleCount > 1) ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D;

                            if (sampleCount == 1)
                            {
                                resourceViewDesc.Texture2D.MostDetailedMip = 0;
                                resourceViewDesc.Texture2D.MipLevels = static_cast<UINT>(levels.size());
                            }

                            hr = rendererD3D11->getDevice()->CreateShaderResourceView(texture, &resourceViewDesc, &resourceView);
                            if (FAILED(hr))
                            {
                                Log(Log::Level::ERR) << "Failed to create Direct3D 11 shader resource view, error: " << hr;
                                return false;
                            }

                            if (renderTarget)
                            {
                                if (renderTargetView)
                                {
                                    renderTargetView->Release();
                                }

                                D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
                                renderTargetViewDesc.Format = d3d11PixelFormat;
                                renderTargetViewDesc.ViewDimension = (sampleCount > 1) ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D;

                                if (sampleCount == 1)
                                {
                                    renderTargetViewDesc.Texture2D.MipSlice = 0;
                                }

                                hr = rendererD3D11->getDevice()->CreateRenderTargetView(texture, &renderTargetViewDesc, &renderTargetView);
                                if (FAILED(hr))
                                {
                                    Log(Log::Level::ERR) << "Failed to create Direct3D 11 render target view, error: " << hr;
                                    return false;
                                }
                            }

                            if (depth)
                            {
                                if (depthStencilTexture)
                                {
                                    depthStencilTexture->Release();
                                }

                                if (depthStencilView)
                                {
                                    depthStencilView->Release();
                                    depthStencilView = nullptr;
                                }

                                D3D11_TEXTURE2D_DESC depthStencilDesc;
                                depthStencilDesc.Width = width;
                                depthStencilDesc.Height = height;
                                depthStencilDesc.MipLevels = 1;
                                depthStencilDesc.ArraySize = 1;
                                depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT;
                                depthStencilDesc.SampleDesc.Count = sampleCount;
                                depthStencilDesc.SampleDesc.Quality = 0;
                                depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
                                depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
                                depthStencilDesc.CPUAccessFlags = 0;
                                depthStencilDesc.MiscFlags = 0;
                                hr = rendererD3D11->getDevice()->CreateTexture2D(&depthStencilDesc, nullptr, &depthStencilTexture);
                                if (FAILED(hr))
                                {
                                    Log(Log::Level::ERR) << "Failed to create Direct3D 11 depth stencil texture, error: " << hr;
                                    return false;
                                }

                                hr = rendererD3D11->getDevice()->CreateDepthStencilView(depthStencilTexture, nullptr, &depthStencilView);
                                if (FAILED(hr))
                                {
                                    Log(Log::Level::ERR) << "Failed to create Direct3D 11 depth stencil view, error: " << hr;
                                    return false;
                                }
                            }
                        }

                        if (dynamic)
                        {
                            for (size_t level = 0; level < levels.size(); ++level)
                            {
                                if (!levels[level].data.empty())
                                {
                                    D3D11_MAPPED_SUBRESOURCE mappedSubresource;
                                    mappedSubresource.pData = 0;
                                    mappedSubresource.RowPitch = 0;
                                    mappedSubresource.DepthPitch = 0;

                                    HRESULT hr = rendererD3D11->getContext()->Map(texture, static_cast<UINT>(level),
                                                                                (level == 0) ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE,
                                                                                0, &mappedSubresource);

                                    if (FAILED(hr))
                                    {
                                        Log(Log::Level::ERR) << "Failed to map Direct3D 11 texture, error: " << hr;
                                        return false;
                                    }

                                    uint8_t* target = reinterpret_cast<uint8_t*>(mappedSubresource.pData);

                                    for (UINT row = 0; row < height; ++row)
                                    {
                                        std::copy(levels[level].data.begin() + row * levels[level].pitch,
                                                  levels[level].data.begin() + (row + 1) * levels[level].pitch,
                                                  target);

                                        target += mappedSubresource.RowPitch;
                                    }

                                    rendererD3D11->getContext()->Unmap(texture, static_cast<UINT>(level));
                                }
                            }
                        }
                        else
                        {
                            for (size_t level = 0; level < levels.size(); ++level)
                            {
                                if (!levels[level].data.empty())
                                {
                                    rendererD3D11->getContext()->UpdateSubresource(texture, static_cast<UINT>(level),
                                                                                nullptr, levels[level].data.data(),
                                                                                static_cast<UINT>(levels[level].pitch), 0);
                                }
                            }
                        }
                    }
                }

                if (dirty & DIRTY_PARAMETERS)
                {
                    clearFrameBufferView = clearColorBuffer;
                    clearDepthBufferView = clearDepthBuffer;

                    frameBufferClearColor[0] = clearColor.normR();
                    frameBufferClearColor[1] = clearColor.normG();
                    frameBufferClearColor[2] = clearColor.normB();
                    frameBufferClearColor[3] = clearColor.normA();

                    if (samplerState) samplerState->Release();

                    RendererD3D11::SamplerStateDesc samplerDesc;
                    samplerDesc.filter = (filter == Texture::Filter::DEFAULT) ? rendererD3D11->getTextureFilter() : filter;
                    samplerDesc.addressX = addressX;
                    samplerDesc.addressY = addressY;
                    samplerDesc.maxAnisotropy = (maxAnisotropy == 0) ? rendererD3D11->getMaxAnisotropy() : maxAnisotropy;

                    samplerState = rendererD3D11->getSamplerState(samplerDesc);

                    if (!samplerState)
                    {
                        Log(Log::Level::ERR) << "Failed to get D3D11 sampler state";
                        return false;
                    }

                    samplerState->AddRef();
                }

                dirty = 0;
            }

            return true;
        }
    } // namespace graphics
} // namespace ouzel
<|endoftext|>


<commit_before><commit_msg>Added a todo and removed some debugging stuff<commit_after><|endoftext|>


<commit_before>#ifndef VSMC_INTERNAL_FORWARD_HPP
#define VSMC_INTERNAL_FORWARD_HPP

namespace vsmc {

class VBase;
class NullType;
class Seed;
template <typename T = NullType> class DDOT;
template <typename T = NullType> class DGEMV;

namespace thread {
class ThreadManager;
template <typename> class BlockedRange;

template <typename S, typename W>
void parallel_for (const BlockedRange<S> &, const W &);

template <typename S, typename W, typename R>
void parallel_sum (const BlockedRange<S> &, const W &, R &);
} // namespace vsmc::thread

class RngSetSeq;
class RngSetPrl;
template <typename> class WeightSetBase;
template <typename> class Sampler;
template <typename> class Particle;
template <typename> class Monitor;
template <typename> class Path;

template <typename> class SingleParticle;
template <typename> class ConstSingleParticle;

template <unsigned, typename> class StateBase;
template <typename, typename> class InitializeBase;
template <typename, typename> class MoveBase;
template <typename, typename> class MonitorEvalBase;
template <typename, typename> class PathEvalBase;

#if VSMC_HAS_CXX11_ALIAS_TEMPLATES
template <unsigned Dim, typename T> using StateSEQ = StateBase<Dim, T>;
#else
template <unsigned, typename> class StateSEQ;
#endif
template <typename, typename D = VBase> class InitializeSEQ;
template <typename, typename D = VBase> class MoveSEQ;
template <typename, typename D = VBase> class MonitorEvalSEQ;
template <typename, typename D = VBase> class PathEvalSEQ;

template <unsigned, typename> class StateSTD;
template <typename, typename D = VBase> class InitializeSTD;
template <typename, typename D = VBase> class MoveSTD;
template <typename, typename D = VBase> class MonitorEvalSTD;
template <typename, typename D = VBase> class PathEvalSTD;

template <unsigned, typename> class StateOMP;
template <typename, typename D = VBase> class InitializeOMP;
template <typename, typename D = VBase> class MoveOMP;
template <typename, typename D = VBase> class MonitorEvalOMP;
template <typename, typename D = VBase> class PathEvalOMP;

template <unsigned, typename> class StateTBB;
template <typename, typename D = VBase> class InitializeTBB;
template <typename, typename D = VBase> class MoveTBB;
template <typename, typename D = VBase> class MonitorEvalTBB;
template <typename, typename D = VBase> class PathEvalTBB;

template <unsigned, typename> class StateCILK;
template <typename, typename D = VBase> class InitializeCILK;
template <typename, typename D = VBase> class MoveCILK;
template <typename, typename D = VBase> class MonitorEvalCILK;
template <typename, typename D = VBase> class PathEvalCILK;

template <unsigned, typename> class StateCL;
template <typename> class InitializeCL;
template <typename> class MoveCL;
template <typename> class MonitorEvalCL;
template <typename> class PathEvalCL;

template <typename, template <typename, typename> class I = InitializeSEQ>
class InitializeAdapter;
template <typename, template <typename, typename> class I = MoveSEQ>
class MoveAdapter;
template <typename, template <typename, typename> class I = MonitorEvalSEQ>
class MonitorEvalAdapter;
template <typename, template <typename, typename> class I = PathEvalSEQ>
class PathEvalAdapter;

} // namesapce vsmc

#endif // VSMC_INTERNAL_FORWARD_HPP
<commit_msg>forward declaration of some additional classes<commit_after>#ifndef VSMC_INTERNAL_FORWARD_HPP
#define VSMC_INTERNAL_FORWARD_HPP

namespace vsmc {

class VBase;
class NullType;
class Seed;
template <typename T = NullType> class DDOT;
template <typename T = NullType> class DGEMV;

namespace thread {

class ThreadManager;
template <typename> class BlockedRange;

template <typename S, typename W>
void parallel_for (const BlockedRange<S> &, const W &);

template <typename S, typename W, typename R>
void parallel_sum (const BlockedRange<S> &, const W &, R &);

} // namespace vsmc::thread

class RngSetSeq;
class RngSetPrl;
template <typename> class WeightSetBase;
template <typename> class Sampler;
template <typename> class Particle;
template <typename> class Monitor;
template <typename> class Path;

template <typename> class SingleParticle;
template <typename> class ConstSingleParticle;

template <unsigned, typename> class StateBase;
template <typename, typename> class InitializeBase;
template <typename, typename> class MoveBase;
template <typename, typename> class MonitorEvalBase;
template <typename, typename> class PathEvalBase;

#if VSMC_HAS_CXX11_ALIAS_TEMPLATES
template <unsigned Dim, typename T> using StateSEQ = StateBase<Dim, T>;
#else
template <unsigned, typename> class StateSEQ;
#endif
template <typename, typename D = VBase> class InitializeSEQ;
template <typename, typename D = VBase> class MoveSEQ;
template <typename, typename D = VBase> class MonitorEvalSEQ;
template <typename, typename D = VBase> class PathEvalSEQ;

template <unsigned, typename> class StateSTD;
template <typename, typename D = VBase> class InitializeSTD;
template <typename, typename D = VBase> class MoveSTD;
template <typename, typename D = VBase> class MonitorEvalSTD;
template <typename, typename D = VBase> class PathEvalSTD;

template <unsigned, typename> class StateOMP;
template <typename, typename D = VBase> class InitializeOMP;
template <typename, typename D = VBase> class MoveOMP;
template <typename, typename D = VBase> class MonitorEvalOMP;
template <typename, typename D = VBase> class PathEvalOMP;

template <unsigned, typename> class StateTBB;
template <typename, typename D = VBase> class InitializeTBB;
template <typename, typename D = VBase> class MoveTBB;
template <typename, typename D = VBase> class MonitorEvalTBB;
template <typename, typename D = VBase> class PathEvalTBB;

template <unsigned, typename> class StateCILK;
template <typename, typename D = VBase> class InitializeCILK;
template <typename, typename D = VBase> class MoveCILK;
template <typename, typename D = VBase> class MonitorEvalCILK;
template <typename, typename D = VBase> class PathEvalCILK;

template <unsigned, typename> class StateCL;
template <typename> class InitializeCL;
template <typename> class MoveCL;
template <typename> class MonitorEvalCL;
template <typename> class PathEvalCL;

template <typename, template <typename, typename> class I = InitializeSEQ>
class InitializeAdapter;
template <typename, template <typename, typename> class I = MoveSEQ>
class MoveAdapter;
template <typename, template <typename, typename> class I = MonitorEvalSEQ>
class MonitorEvalAdapter;
template <typename, template <typename, typename> class I = PathEvalSEQ>
class PathEvalAdapter;

} // namesapce vsmc

#endif // VSMC_INTERNAL_FORWARD_HPP
<|endoftext|>


<commit_before>/** @file

  FIFO queue

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

  @section details Details

  ProtectedQueue implements a FIFO queue with the following functionality:
    -# Multiple threads could be simultaneously trying to enqueue and
      dequeue. Hence the queue needs to be protected with mutex.
    -# In case the queue is empty, dequeue() sleeps for a specified amount
      of time, or until a new element is inserted, whichever is earlier.

*/

#include "P_EventSystem.h"

// The protected queue is designed to delay signaling of threads
// until some amount of work has been completed on the current thread
// in order to prevent excess context switches.
//
// Defining EAGER_SIGNALLING disables this behavior and causes
// threads to be made runnable immediately.
//
// #define EAGER_SIGNALLING

extern ClassAllocator<Event> eventAllocator;

void
ProtectedQueue::enqueue(Event *e, bool fast_signal)
{
  ink_assert(!e->in_the_prot_queue && !e->in_the_priority_queue);
  EThread *e_ethread   = e->ethread;
  e->in_the_prot_queue = 1;
  bool was_empty       = (ink_atomiclist_push(&al, e) == nullptr);

  if (was_empty) {
    EThread *inserting_thread = this_ethread();
    // queue e->ethread in the list of threads to be signalled
    // inserting_thread == 0 means it is not a regular EThread
    if (inserting_thread != e_ethread) {
      e_ethread->tail_cb->signalActivity();
    }
  }
}

void
flush_signals(EThread *thr)
{
  ink_assert(this_ethread() == thr);
  int n = thr->n_ethreads_to_be_signalled;
  if (n > eventProcessor.n_ethreads) {
    n = eventProcessor.n_ethreads; // MAX
  }
  int i;

  for (i = 0; i < n; i++) {
    if (thr->ethreads_to_be_signalled[i]) {
      thr->ethreads_to_be_signalled[i]->tail_cb->signalActivity();
      thr->ethreads_to_be_signalled[i] = nullptr;
    }
  }
  thr->n_ethreads_to_be_signalled = 0;
}

void
ProtectedQueue::dequeue_timed(ink_hrtime cur_time, ink_hrtime timeout, bool sleep)
{
  (void)cur_time;
  if (sleep) {
    this->wait(timeout);
  }
  this->dequeue_external();
}

void
ProtectedQueue::dequeue_external()
{
  Event *e = (Event *)ink_atomiclist_popall(&al);
  // invert the list, to preserve order
  SLL<Event, Event::Link_link> l, t;
  t.head = e;
  while ((e = t.pop())) {
    l.push(e);
  }
  // insert into localQueue
  while ((e = l.pop())) {
    if (!e->cancelled) {
      localQueue.enqueue(e);
    } else {
      e->mutex = nullptr;
      eventAllocator.free(e);
    }
  }
}

void
ProtectedQueue::wait(ink_hrtime timeout)
{
  ink_mutex_acquire(&lock);
  if (INK_ATOMICLIST_EMPTY(al)) {
    timespec ts = ink_hrtime_to_timespec(timeout);
    ink_cond_timedwait(&might_have_data, &lock, &ts);
  }
  ink_mutex_release(&lock);
}
<commit_msg>Optimize: Avoid meaningless lock operations<commit_after>/** @file

  FIFO queue

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

  @section details Details

  ProtectedQueue implements a FIFO queue with the following functionality:
    -# Multiple threads could be simultaneously trying to enqueue and
      dequeue. Hence the queue needs to be protected with mutex.
    -# In case the queue is empty, dequeue() sleeps for a specified amount
      of time, or until a new element is inserted, whichever is earlier.

*/

#include "P_EventSystem.h"

// The protected queue is designed to delay signaling of threads
// until some amount of work has been completed on the current thread
// in order to prevent excess context switches.
//
// Defining EAGER_SIGNALLING disables this behavior and causes
// threads to be made runnable immediately.
//
// #define EAGER_SIGNALLING

extern ClassAllocator<Event> eventAllocator;

void
ProtectedQueue::enqueue(Event *e, bool fast_signal)
{
  ink_assert(!e->in_the_prot_queue && !e->in_the_priority_queue);
  EThread *e_ethread   = e->ethread;
  e->in_the_prot_queue = 1;
  bool was_empty       = (ink_atomiclist_push(&al, e) == nullptr);

  if (was_empty) {
    EThread *inserting_thread = this_ethread();
    // queue e->ethread in the list of threads to be signalled
    // inserting_thread == 0 means it is not a regular EThread
    if (inserting_thread != e_ethread) {
      e_ethread->tail_cb->signalActivity();
    }
  }
}

void
flush_signals(EThread *thr)
{
  ink_assert(this_ethread() == thr);
  int n = thr->n_ethreads_to_be_signalled;
  if (n > eventProcessor.n_ethreads) {
    n = eventProcessor.n_ethreads; // MAX
  }
  int i;

  for (i = 0; i < n; i++) {
    if (thr->ethreads_to_be_signalled[i]) {
      thr->ethreads_to_be_signalled[i]->tail_cb->signalActivity();
      thr->ethreads_to_be_signalled[i] = nullptr;
    }
  }
  thr->n_ethreads_to_be_signalled = 0;
}

void
ProtectedQueue::dequeue_timed(ink_hrtime cur_time, ink_hrtime timeout, bool sleep)
{
  (void)cur_time;
  if (sleep) {
    this->wait(timeout);
  }
  this->dequeue_external();
}

void
ProtectedQueue::dequeue_external()
{
  Event *e = (Event *)ink_atomiclist_popall(&al);
  // invert the list, to preserve order
  SLL<Event, Event::Link_link> l, t;
  t.head = e;
  while ((e = t.pop())) {
    l.push(e);
  }
  // insert into localQueue
  while ((e = l.pop())) {
    if (!e->cancelled) {
      localQueue.enqueue(e);
    } else {
      e->mutex = nullptr;
      eventAllocator.free(e);
    }
  }
}

void
ProtectedQueue::wait(ink_hrtime timeout)
{
  // If there are no external events available, don't do a cond_timedwait.
  if (INK_ATOMICLIST_EMPTY(al)) {
    ink_mutex_acquire(&lock);
    // The "al" may have new events while waiting for the mutex become available.
    // We have to recheck the external queue again.
    if (INK_ATOMICLIST_EMPTY(al)) {
      timespec ts = ink_hrtime_to_timespec(timeout);
      ink_cond_timedwait(&might_have_data, &lock, &ts);
    }
    ink_mutex_release(&lock);
  }
}
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "XInputMTInputDevice.h"

#include "TouchEvent.h"
#include "Player.h"
#include "AVGNode.h"
#include "TouchStatus.h"
#include "SDLDisplayEngine.h"

#include "../base/Logger.h"
#include "../base/ObjectCounter.h"
#include "../base/Exception.h"
#include "../base/OSHelper.h"
#include "../base/StringHelper.h"

#include <SDL/SDL_syswm.h>
#include <SDL/SDL.h>

#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>

using namespace std;

namespace avg {

::Display* XInputMTInputDevice::s_pDisplay = 0;

const char* cookieTypeToName(int evtype);
string xEventTypeToName(int evtype);

XInputMTInputDevice::XInputMTInputDevice()
    : m_LastID(0),
      m_DeviceID(-1)
{
    SDLDisplayEngine* pDisplayEngine = Player::get()->getDisplayEngine();
    glm::vec2 size(pDisplayEngine->getSize());
    glm::vec2 windowSize(pDisplayEngine->getWindowSize());
    m_DisplayScale.x = size.x/windowSize.x;
    m_DisplayScale.y = size.y/windowSize.y;
}

XInputMTInputDevice::~XInputMTInputDevice()
{
    if (m_DeviceID != -1 && m_OldMasterDeviceID != -1) {
        XIAttachSlaveInfo atInfo;
        atInfo.type = XIAttachSlave;
        atInfo.deviceid = m_DeviceID;
        atInfo.new_master = m_OldMasterDeviceID;
        XIChangeHierarchy(s_pDisplay, (XIAnyHierarchyChangeInfo *)&atInfo, 1);
    }
}

void XInputMTInputDevice::start()
{
    Status status;
    SDLDisplayEngine * pEngine = Player::get()->getDisplayEngine();

    SDL_SysWMinfo info;
    SDL_VERSION(&info.version);
    int rc = SDL_GetWMInfo(&info);
    AVG_ASSERT(rc != -1);
    s_pDisplay = info.info.x11.display;
    m_SDLLockFunc = info.info.x11.lock_func;
    m_SDLUnlockFunc = info.info.x11.unlock_func;

    m_SDLLockFunc();
    // XInput Extension available?
    int event, error;
    bool bOk = XQueryExtension(s_pDisplay, "XInputExtension", &m_XIOpcode,
            &event, &error);
    if (!bOk) {
        throw Exception(AVG_ERR_MT_INIT,
                "XInput multitouch event source: X Input extension not available.");
    }

    // Which version of XI2?
    int major;
    int minor;
    status = XIQueryVersion(s_pDisplay, &major, &minor);
    if (status == BadRequest) {
        throw Exception(AVG_ERR_MT_INIT,
                "XInput 2.1 multitouch event source: Server does not support XI2");
    }
    if (major < 2 || minor < 1) {
        throw Exception(AVG_ERR_MT_INIT,
                "XInput multitouch event source: Supported version is "
                +toString(major)+"."+toString(minor)+". At least 2.1 is needed.");
    }
    findMTDevice();

    // SDL grabs the pointer in full screen mode. This breaks touchscreen usage.
    // Can't use SDL_WM_GrabInput(SDL_GRAB_OFF) because it doesn't work in full
    // screen mode. Get the display connection and do it manually.
    XUngrabPointer(info.info.x11.display, CurrentTime);

    XIEventMask mask;
    mask.deviceid = m_DeviceID;
    mask.mask_len = XIMaskLen(XI_LASTEVENT);
    mask.mask = (unsigned char *)calloc(mask.mask_len, sizeof(char));
    memset(mask.mask, 0, mask.mask_len);
    XISetMask(mask.mask, XI_TouchBegin);
    XISetMask(mask.mask, XI_TouchUpdate);
    XISetMask(mask.mask, XI_TouchEnd);

    status = XISelectEvents(s_pDisplay, info.info.x11.window, &mask, 1);
    AVG_ASSERT(status == Success);

    m_SDLUnlockFunc();

    SDL_SetEventFilter(XInputMTInputDevice::filterEvent);

    XIDetachSlaveInfo detInfo;
    detInfo.type = XIDetachSlave;
    detInfo.deviceid = m_DeviceID;
    XIChangeHierarchy(s_pDisplay, (XIAnyHierarchyChangeInfo *)&detInfo, 1);

    pEngine->setXIMTInputDevice(this);
    MultitouchInputDevice::start();
    AVG_TRACE(Logger::category::CONFIG, Logger::severity::INFO,
            "XInput Multitouch event source created.");
}

void XInputMTInputDevice::handleXIEvent(const XEvent& xEvent)
{
    m_SDLLockFunc();
    XGenericEventCookie* pCookie = (XGenericEventCookie*)&xEvent.xcookie;
    if (pCookie->type == GenericEvent && pCookie->extension == m_XIOpcode) {
        XIDeviceEvent* pDevEvent = (XIDeviceEvent*)(pCookie->data);
        IntPoint pos(pDevEvent->event_x, pDevEvent->event_y);
        int xid = pDevEvent->detail;
        switch (pCookie->evtype) {
            case XI_TouchBegin:
                {
//                    cerr << "TouchBegin " << xid << ", " << pos << endl;
                    m_LastID++;
                    TouchEventPtr pEvent = createEvent(m_LastID, Event::CURSOR_DOWN, pos);
                    addTouchStatus(xid, pEvent);
                }
                break;
            case XI_TouchUpdate:
                {
//                    cerr << "TouchUpdate " << xid << ", " << pos << endl;
                    TouchEventPtr pEvent = createEvent(0, Event::CURSOR_MOTION, pos);
                    TouchStatusPtr pTouchStatus = getTouchStatus(xid);
                    AVG_ASSERT(pTouchStatus);
                    pTouchStatus->pushEvent(pEvent);
                }
                break;
            case XI_TouchEnd:
                {
//                    cerr << "TouchEnd " << xid << ", " << pos << endl;
                    TouchStatusPtr pTouchStatus = getTouchStatus(xid);
                    AVG_ASSERT(pTouchStatus);
                    TouchEventPtr pEvent = createEvent(0, Event::CURSOR_UP, pos);
                    pTouchStatus->pushEvent(pEvent);
                }
                break;
            default:
                ;
//                cerr << "Unhandled XInput event, type: "
//                        << cookieTypeToName(pCookie->evtype) << endl;
        }
    } else {
//        cerr << "Unhandled X11 Event: " << xEvent.type << endl;
    }

    XFreeEventData(s_pDisplay, pCookie);
    m_SDLUnlockFunc();
}

std::vector<EventPtr> XInputMTInputDevice::pollEvents()
{

    return MultitouchInputDevice::pollEvents();
}

void XInputMTInputDevice::findMTDevice()
{
    int ndevices;
    XIDeviceInfo* pDevices;
    XIDeviceInfo* pDevice;

    pDevices = XIQueryDevice(s_pDisplay, XIAllDevices, &ndevices);

    XITouchClassInfo* pTouchClass = 0;
    for (int i = 0; i < ndevices && !pTouchClass; ++i) {
        pDevice = &pDevices[i];
//        cerr << "Device " << pDevice->name << "(id: " << pDevice->deviceid << ")."
//                << endl;
        if (pDevice->use == XISlavePointer || pDevice->use == XIFloatingSlave) {
            for (int j = 0; j < pDevice->num_classes; ++j) {
                XIAnyClassInfo * pClass = pDevice->classes[j];
                if (pClass->type == XITouchClass) {
                    XITouchClassInfo* pTempTouchClass = (XITouchClassInfo *)pClass;
                    if (pTempTouchClass->mode == XIDirectTouch) {
                        pTouchClass = pTempTouchClass;
                        m_sDeviceName = pDevice->name;
                        m_DeviceID = pDevice->deviceid;
                        if (pDevice->use == XISlavePointer) {
                            m_OldMasterDeviceID = pDevice->attachment;
                        } else {
                            m_OldMasterDeviceID = -1;
                        }
                        break;
                    }
                }
            }
        }
    }
    if (pTouchClass) {
        AVG_TRACE(Logger::category::CONFIG,Logger::severity::INFO,
                "Using multitouch input device " << m_sDeviceName << ", max touches: " <<
                pTouchClass->num_touches);
    } else {
        throw Exception(AVG_ERR_MT_INIT,
                "XInput multitouch event source: No multitouch device found.");
    }
    XIFreeDeviceInfo(pDevices);
}

TouchEventPtr XInputMTInputDevice::createEvent(int id, Event::Type type, IntPoint pos)
{
    pos.x *= m_DisplayScale.x;
    pos.y *= m_DisplayScale.y;
    return TouchEventPtr(new TouchEvent(id, type, pos, Event::TOUCH));
}

int XInputMTInputDevice::filterEvent(const SDL_Event * pEvent)
{
    // This is a hook into libsdl event processing. Since libsdl doesn't know about
    // XInput 2, it doesn't call XGetEventData either. By the time the event arrives
    // in handleXIEvent(), other events may have arrived and XGetEventData can't be
    // called anymore. Hence this function, which calls XGetEventData for each event
    // that has a cookie.
    if (pEvent->type == SDL_SYSWMEVENT) {
        SDL_SysWMmsg* pMsg = pEvent->syswm.msg;
        AVG_ASSERT(pMsg->subsystem == SDL_SYSWM_X11);
        XEvent* pXEvent = &pMsg->event.xevent;
        XGenericEventCookie* pCookie = (XGenericEventCookie*)&(pXEvent->xcookie);
//        cerr << "---- filter xinput event: " << xEventTypeToName(pXEvent->type) << ", "
//                << cookieTypeToName(pCookie->evtype) << endl;
        XGetEventData(s_pDisplay, pCookie);
    } else {
//        cerr << "---- filter: " << int(pEvent->type) << endl;
    }
    return 1;
}

// From xinput/test_xi2.c
const char* cookieTypeToName(int evtype)
{
    const char *name;
    switch(evtype) {
        case XI_DeviceChanged:    name = "DeviceChanged";        break;
        case XI_KeyPress:         name = "KeyPress";             break;
        case XI_KeyRelease:       name = "KeyRelease";           break;
        case XI_ButtonPress:      name = "ButtonPress";          break;
        case XI_ButtonRelease:    name = "ButtonRelease";        break;
        case XI_Motion:           name = "Motion";               break;
        case XI_Enter:            name = "Enter";                break;
        case XI_Leave:            name = "Leave";                break;
        case XI_FocusIn:          name = "FocusIn";              break;
        case XI_FocusOut:         name = "FocusOut";             break;
        case XI_HierarchyChanged: name = "HierarchyChanged";     break;
        case XI_PropertyEvent:    name = "PropertyEvent";        break;
        case XI_RawKeyPress:      name = "RawKeyPress";          break;
        case XI_RawKeyRelease:    name = "RawKeyRelease";        break;
        case XI_RawButtonPress:   name = "RawButtonPress";       break;
        case XI_RawButtonRelease: name = "RawButtonRelease";     break;
        case XI_RawMotion:        name = "RawMotion";            break;
        case XI_TouchBegin:       name = "TouchBegin";           break;
        case XI_TouchEnd:         name = "TouchEnd";             break;
        case XI_TouchUpdate:      name = "TouchUpdate";          break;
#ifdef HAVE_XI2_1
        case XI_TouchUpdateUnowned: name = "TouchUpdateUnowned"; break;
#endif
        default:                  name = "unknown event type";   break;
    }
    return name;
}

string xEventTypeToName(int evtype)
{
    switch(evtype) {
        case KeyPress:
            return "KeyPress";
        case KeyRelease:
            return "KeyRelease";
        case ButtonPress:
            return "ButtonPress";
        case ButtonRelease:
            return "ButtonRelease";
        case MotionNotify:
            return "MotionNotify";
        case EnterNotify:
            return "EnterNotify";
        case LeaveNotify:
            return "LeaveNotify";
        case FocusIn:
            return "FocusIn";
        case FocusOut:
            return "FocusOut";
        case KeymapNotify:
            return "KeymapNotify";
        case Expose:
            return "Expose";
        case GraphicsExpose:
            return "GraphicsExpose";
        case NoExpose:
            return "NoExpose";
        case VisibilityNotify:
            return "VisibilityNotify";
        case CreateNotify:
            return "CreateNotify";
        case DestroyNotify:
            return "DestroyNotify";
        case UnmapNotify:
            return "UnmapNotify";
        case MapNotify:
            return "MapNotify";
        case MapRequest:
            return "MapRequest";
        case ReparentNotify:
            return "ReparentNotify";
        case ConfigureNotify:
            return "ConfigureNotify";
        case ConfigureRequest:
            return "ConfigureRequest";
        case GravityNotify:
            return "GravityNotify";
        case ResizeRequest:
            return "ResizeRequest";
        case CirculateNotify:
            return "CirculateNotify";
        case CirculateRequest:
            return "CirculateRequest";
        case PropertyNotify:
            return "PropertyNotify";
        case SelectionClear:
            return "SelectionClear";
        case SelectionRequest:
            return "SelectionRequest";
        case SelectionNotify:
            return "SelectionNotify";
        case ColormapNotify:
            return "ColormapNotify";
        case ClientMessage:
            return "ClientMessage";
        case MappingNotify:
            return "MappingNotify";
        case GenericEvent:
            return "GenericEvent";
        default:
            return "Unknown event type";
    }
}

}
<commit_msg>Fixed crash when multitouch is initialized before Player.play().<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "XInputMTInputDevice.h"

#include "TouchEvent.h"
#include "Player.h"
#include "AVGNode.h"
#include "TouchStatus.h"
#include "SDLDisplayEngine.h"

#include "../base/Logger.h"
#include "../base/ObjectCounter.h"
#include "../base/Exception.h"
#include "../base/OSHelper.h"
#include "../base/StringHelper.h"

#include <SDL/SDL_syswm.h>
#include <SDL/SDL.h>

#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>

using namespace std;

namespace avg {

::Display* XInputMTInputDevice::s_pDisplay = 0;

const char* cookieTypeToName(int evtype);
string xEventTypeToName(int evtype);

XInputMTInputDevice::XInputMTInputDevice()
    : m_LastID(0),
      m_DeviceID(-1)
{
}

XInputMTInputDevice::~XInputMTInputDevice()
{
    if (m_DeviceID != -1 && m_OldMasterDeviceID != -1) {
        XIAttachSlaveInfo atInfo;
        atInfo.type = XIAttachSlave;
        atInfo.deviceid = m_DeviceID;
        atInfo.new_master = m_OldMasterDeviceID;
        XIChangeHierarchy(s_pDisplay, (XIAnyHierarchyChangeInfo *)&atInfo, 1);
    }
}

void XInputMTInputDevice::start()
{
    Status status;
    SDLDisplayEngine * pEngine = Player::get()->getDisplayEngine();
    glm::vec2 size(pEngine->getSize());
    glm::vec2 windowSize(pEngine->getWindowSize());
    m_DisplayScale.x = size.x/windowSize.x;
    m_DisplayScale.y = size.y/windowSize.y;

    SDL_SysWMinfo info;
    SDL_VERSION(&info.version);
    int rc = SDL_GetWMInfo(&info);
    AVG_ASSERT(rc != -1);
    s_pDisplay = info.info.x11.display;
    m_SDLLockFunc = info.info.x11.lock_func;
    m_SDLUnlockFunc = info.info.x11.unlock_func;

    m_SDLLockFunc();
    // XInput Extension available?
    int event, error;
    bool bOk = XQueryExtension(s_pDisplay, "XInputExtension", &m_XIOpcode,
            &event, &error);
    if (!bOk) {
        throw Exception(AVG_ERR_MT_INIT,
                "XInput multitouch event source: X Input extension not available.");
    }

    // Which version of XI2?
    int major;
    int minor;
    status = XIQueryVersion(s_pDisplay, &major, &minor);
    if (status == BadRequest) {
        throw Exception(AVG_ERR_MT_INIT,
                "XInput 2.1 multitouch event source: Server does not support XI2");
    }
    if (major < 2 || minor < 1) {
        throw Exception(AVG_ERR_MT_INIT,
                "XInput multitouch event source: Supported version is "
                +toString(major)+"."+toString(minor)+". At least 2.1 is needed.");
    }
    findMTDevice();

    // SDL grabs the pointer in full screen mode. This breaks touchscreen usage.
    // Can't use SDL_WM_GrabInput(SDL_GRAB_OFF) because it doesn't work in full
    // screen mode. Get the display connection and do it manually.
    XUngrabPointer(info.info.x11.display, CurrentTime);

    XIEventMask mask;
    mask.deviceid = m_DeviceID;
    mask.mask_len = XIMaskLen(XI_LASTEVENT);
    mask.mask = (unsigned char *)calloc(mask.mask_len, sizeof(char));
    memset(mask.mask, 0, mask.mask_len);
    XISetMask(mask.mask, XI_TouchBegin);
    XISetMask(mask.mask, XI_TouchUpdate);
    XISetMask(mask.mask, XI_TouchEnd);

    status = XISelectEvents(s_pDisplay, info.info.x11.window, &mask, 1);
    AVG_ASSERT(status == Success);

    m_SDLUnlockFunc();

    SDL_SetEventFilter(XInputMTInputDevice::filterEvent);

    XIDetachSlaveInfo detInfo;
    detInfo.type = XIDetachSlave;
    detInfo.deviceid = m_DeviceID;
    XIChangeHierarchy(s_pDisplay, (XIAnyHierarchyChangeInfo *)&detInfo, 1);

    pEngine->setXIMTInputDevice(this);
    MultitouchInputDevice::start();
    AVG_TRACE(Logger::category::CONFIG, Logger::severity::INFO,
            "XInput Multitouch event source created.");
}

void XInputMTInputDevice::handleXIEvent(const XEvent& xEvent)
{
    m_SDLLockFunc();
    XGenericEventCookie* pCookie = (XGenericEventCookie*)&xEvent.xcookie;
    if (pCookie->type == GenericEvent && pCookie->extension == m_XIOpcode) {
        XIDeviceEvent* pDevEvent = (XIDeviceEvent*)(pCookie->data);
        IntPoint pos(pDevEvent->event_x, pDevEvent->event_y);
        int xid = pDevEvent->detail;
        switch (pCookie->evtype) {
            case XI_TouchBegin:
                {
//                    cerr << "TouchBegin " << xid << ", " << pos << endl;
                    m_LastID++;
                    TouchEventPtr pEvent = createEvent(m_LastID, Event::CURSOR_DOWN, pos);
                    addTouchStatus(xid, pEvent);
                }
                break;
            case XI_TouchUpdate:
                {
//                    cerr << "TouchUpdate " << xid << ", " << pos << endl;
                    TouchEventPtr pEvent = createEvent(0, Event::CURSOR_MOTION, pos);
                    TouchStatusPtr pTouchStatus = getTouchStatus(xid);
                    AVG_ASSERT(pTouchStatus);
                    pTouchStatus->pushEvent(pEvent);
                }
                break;
            case XI_TouchEnd:
                {
//                    cerr << "TouchEnd " << xid << ", " << pos << endl;
                    TouchStatusPtr pTouchStatus = getTouchStatus(xid);
                    AVG_ASSERT(pTouchStatus);
                    TouchEventPtr pEvent = createEvent(0, Event::CURSOR_UP, pos);
                    pTouchStatus->pushEvent(pEvent);
                }
                break;
            default:
                ;
//                cerr << "Unhandled XInput event, type: "
//                        << cookieTypeToName(pCookie->evtype) << endl;
        }
    } else {
//        cerr << "Unhandled X11 Event: " << xEvent.type << endl;
    }

    XFreeEventData(s_pDisplay, pCookie);
    m_SDLUnlockFunc();
}

std::vector<EventPtr> XInputMTInputDevice::pollEvents()
{

    return MultitouchInputDevice::pollEvents();
}

void XInputMTInputDevice::findMTDevice()
{
    int ndevices;
    XIDeviceInfo* pDevices;
    XIDeviceInfo* pDevice;

    pDevices = XIQueryDevice(s_pDisplay, XIAllDevices, &ndevices);

    XITouchClassInfo* pTouchClass = 0;
    for (int i = 0; i < ndevices && !pTouchClass; ++i) {
        pDevice = &pDevices[i];
//        cerr << "Device " << pDevice->name << "(id: " << pDevice->deviceid << ")."
//                << endl;
        if (pDevice->use == XISlavePointer || pDevice->use == XIFloatingSlave) {
            for (int j = 0; j < pDevice->num_classes; ++j) {
                XIAnyClassInfo * pClass = pDevice->classes[j];
                if (pClass->type == XITouchClass) {
                    XITouchClassInfo* pTempTouchClass = (XITouchClassInfo *)pClass;
                    if (pTempTouchClass->mode == XIDirectTouch) {
                        pTouchClass = pTempTouchClass;
                        m_sDeviceName = pDevice->name;
                        m_DeviceID = pDevice->deviceid;
                        if (pDevice->use == XISlavePointer) {
                            m_OldMasterDeviceID = pDevice->attachment;
                        } else {
                            m_OldMasterDeviceID = -1;
                        }
                        break;
                    }
                }
            }
        }
    }
    if (pTouchClass) {
        AVG_TRACE(Logger::category::CONFIG,Logger::severity::INFO,
                "Using multitouch input device " << m_sDeviceName << ", max touches: " <<
                pTouchClass->num_touches);
    } else {
        throw Exception(AVG_ERR_MT_INIT,
                "XInput multitouch event source: No multitouch device found.");
    }
    XIFreeDeviceInfo(pDevices);
}

TouchEventPtr XInputMTInputDevice::createEvent(int id, Event::Type type, IntPoint pos)
{
    pos.x *= m_DisplayScale.x;
    pos.y *= m_DisplayScale.y;
    return TouchEventPtr(new TouchEvent(id, type, pos, Event::TOUCH));
}

int XInputMTInputDevice::filterEvent(const SDL_Event * pEvent)
{
    // This is a hook into libsdl event processing. Since libsdl doesn't know about
    // XInput 2, it doesn't call XGetEventData either. By the time the event arrives
    // in handleXIEvent(), other events may have arrived and XGetEventData can't be
    // called anymore. Hence this function, which calls XGetEventData for each event
    // that has a cookie.
    if (pEvent->type == SDL_SYSWMEVENT) {
        SDL_SysWMmsg* pMsg = pEvent->syswm.msg;
        AVG_ASSERT(pMsg->subsystem == SDL_SYSWM_X11);
        XEvent* pXEvent = &pMsg->event.xevent;
        XGenericEventCookie* pCookie = (XGenericEventCookie*)&(pXEvent->xcookie);
//        cerr << "---- filter xinput event: " << xEventTypeToName(pXEvent->type) << ", "
//                << cookieTypeToName(pCookie->evtype) << endl;
        XGetEventData(s_pDisplay, pCookie);
    } else {
//        cerr << "---- filter: " << int(pEvent->type) << endl;
    }
    return 1;
}

// From xinput/test_xi2.c
const char* cookieTypeToName(int evtype)
{
    const char *name;
    switch(evtype) {
        case XI_DeviceChanged:    name = "DeviceChanged";        break;
        case XI_KeyPress:         name = "KeyPress";             break;
        case XI_KeyRelease:       name = "KeyRelease";           break;
        case XI_ButtonPress:      name = "ButtonPress";          break;
        case XI_ButtonRelease:    name = "ButtonRelease";        break;
        case XI_Motion:           name = "Motion";               break;
        case XI_Enter:            name = "Enter";                break;
        case XI_Leave:            name = "Leave";                break;
        case XI_FocusIn:          name = "FocusIn";              break;
        case XI_FocusOut:         name = "FocusOut";             break;
        case XI_HierarchyChanged: name = "HierarchyChanged";     break;
        case XI_PropertyEvent:    name = "PropertyEvent";        break;
        case XI_RawKeyPress:      name = "RawKeyPress";          break;
        case XI_RawKeyRelease:    name = "RawKeyRelease";        break;
        case XI_RawButtonPress:   name = "RawButtonPress";       break;
        case XI_RawButtonRelease: name = "RawButtonRelease";     break;
        case XI_RawMotion:        name = "RawMotion";            break;
        case XI_TouchBegin:       name = "TouchBegin";           break;
        case XI_TouchEnd:         name = "TouchEnd";             break;
        case XI_TouchUpdate:      name = "TouchUpdate";          break;
#ifdef HAVE_XI2_1
        case XI_TouchUpdateUnowned: name = "TouchUpdateUnowned"; break;
#endif
        default:                  name = "unknown event type";   break;
    }
    return name;
}

string xEventTypeToName(int evtype)
{
    switch(evtype) {
        case KeyPress:
            return "KeyPress";
        case KeyRelease:
            return "KeyRelease";
        case ButtonPress:
            return "ButtonPress";
        case ButtonRelease:
            return "ButtonRelease";
        case MotionNotify:
            return "MotionNotify";
        case EnterNotify:
            return "EnterNotify";
        case LeaveNotify:
            return "LeaveNotify";
        case FocusIn:
            return "FocusIn";
        case FocusOut:
            return "FocusOut";
        case KeymapNotify:
            return "KeymapNotify";
        case Expose:
            return "Expose";
        case GraphicsExpose:
            return "GraphicsExpose";
        case NoExpose:
            return "NoExpose";
        case VisibilityNotify:
            return "VisibilityNotify";
        case CreateNotify:
            return "CreateNotify";
        case DestroyNotify:
            return "DestroyNotify";
        case UnmapNotify:
            return "UnmapNotify";
        case MapNotify:
            return "MapNotify";
        case MapRequest:
            return "MapRequest";
        case ReparentNotify:
            return "ReparentNotify";
        case ConfigureNotify:
            return "ConfigureNotify";
        case ConfigureRequest:
            return "ConfigureRequest";
        case GravityNotify:
            return "GravityNotify";
        case ResizeRequest:
            return "ResizeRequest";
        case CirculateNotify:
            return "CirculateNotify";
        case CirculateRequest:
            return "CirculateRequest";
        case PropertyNotify:
            return "PropertyNotify";
        case SelectionClear:
            return "SelectionClear";
        case SelectionRequest:
            return "SelectionRequest";
        case SelectionNotify:
            return "SelectionNotify";
        case ColormapNotify:
            return "ColormapNotify";
        case ClientMessage:
            return "ClientMessage";
        case MappingNotify:
            return "MappingNotify";
        case GenericEvent:
            return "GenericEvent";
        default:
            return "Unknown event type";
    }
}

}
<|endoftext|>