NPAPI:AsyncDrawing: Difference between revisions

no edit summary
No edit summary
Line 90: Line 90:
Surfaces cannot be modified while they are current. A modified rectangle may be provided in the <code>changed</code> argument to give the host a hint on which part of the surface was modified with respect to the previous current surface so that the browser can choose to optimize the composition process. There is no guarantee only this rectangle will be recomposed though and the entire surface needs to be valid.
Surfaces cannot be modified while they are current. A modified rectangle may be provided in the <code>changed</code> argument to give the host a hint on which part of the surface was modified with respect to the previous current surface so that the browser can choose to optimize the composition process. There is no guarantee only this rectangle will be recomposed though and the entire surface needs to be valid.


The Init and Finalize functions must be called from the main plugin thread. The SetCurrent function may be called from any thread. Reentrant calls into the plugin do not occur during a SetCurrent invocation. Therefore the browser is expected to implement SetCurrent using a locking protocol that cannot block for long. For example, SetCurrent might block only while the previous surface is being read by browser compositing.
SetCurrent can take NULL as the surface. This removes the previous current surface. The plugin will render nothing. This should be used before finalizing the last surface.
 
The Init and Finalize functions must be called from the main plugin thread. The SetCurrent function may be called from any thread. Reentrant calls into the plugin do not occur during a SetCurrent invocation. Therefore the browser is expected to implement SetCurrent using a locking protocol that cannot block for long. For example, SetCurrent might block only while the previous surface is being read by the browser's compositing.
 
= Throttling Painting =
 
To enable the plugin to match its frame rate to the browser's, the browser notifies the plugin each time it has composited a frame that used the plugin's current surface. This notification fires even if the plugin's current surface is NULL.
 
<pre>
  void NPP_DidComposite(NPP instance);
</pre>


= NPDrawingModelAsyncBitmapSurface =
= NPDrawingModelAsyncBitmapSurface =


This model should be available on all platforms. It allows calls to SetCurrent on any thread.
This model should be available on all platforms.


Plugins should create a bitmap surface by calling <code>NPN_InitAsyncSurface</code> with a <code>NULL</code> value for <code>initData</code>. If an <code>NPImageFormat</code> is not supported then surface creation will fail.
Plugins should create a bitmap surface by calling <code>NPN_InitAsyncSurface</code> with a <code>NULL</code> value for <code>initData</code>. If an <code>NPImageFormat</code> is not supported then surface creation will fail.
Line 104: Line 114:
This drawing model will only be valid on Windows Vista and higher in order to simplify hardware accelerated surface sharing.
This drawing model will only be valid on Windows Vista and higher in order to simplify hardware accelerated surface sharing.


Plugins should create a Windows shared surface by calling <code>NPN_InitAsyncSurface</code> with a <code>NULL</code> value for <code>initData</code>. The resulting <code>NPAsyncSurface</code> will point to a <code>HANDLE</code> that can be used, for example, through [http://msdn.microsoft.com/en-us/library/bb173598%28v=VS.85%29.aspx OpenSharedResource] in order to create a texture for the user. In order to allow fast drawing to any hardware surfaces, the host will acquire the handle from [http://msdn.microsoft.com/en-us/library/bb174562%28v=VS.85%29.aspx IDXGISurface::GetSharedHandle]. This shared handle will represent a texture which is usable as a render target and is valid as a shader resource. The plugin can open this shared handle as a texture and then use it as a render target for any drawing operations. SetCurrent may only be called on the main thread in this model.
Plugins should create a Windows shared surface by calling <code>NPN_InitAsyncSurface</code> with a <code>NULL</code> value for <code>initData</code>. The resulting <code>NPAsyncSurface</code> will point to a <code>HANDLE</code> that can be used, for example, through [http://msdn.microsoft.com/en-us/library/bb173598%28v=VS.85%29.aspx OpenSharedResource] in order to create a texture for the user. In order to allow fast drawing to any hardware surfaces, the host will acquire the handle from [http://msdn.microsoft.com/en-us/library/bb174562%28v=VS.85%29.aspx IDXGISurface::GetSharedHandle]. This shared handle will represent a texture which is usable as a render target and is valid as a shader resource. The plugin can open this shared handle as a texture and then use it as a render target for any drawing operations.


When a surface is set as current the plugin is responsible for making sure all drawing calls on that surface have completed execution!
When a surface is set as current the plugin is responsible for making sure all drawing calls on that surface have completed execution!
Line 113: Line 123:


  ID3D10Device *pDevice10;
  ID3D10Device *pDevice10;
// Initialize device.
  NPAsyncSurface *npFrontBuffer = new NPAsyncSurface;
  NPAsyncSurface *npFrontBuffer = new NPAsyncSurface;
  NPAsyncSurface *npBackBuffer = new NPAsyncSurface;
  NPAsyncSurface *npBackBuffer = new NPAsyncSurface;
Line 120: Line 128:
  ID3D10Texture2D *backBuffer;
  ID3D10Texture2D *backBuffer;
   
   
  NPSize size;
  void Init() {
size.width = pluginwidth;
  ... Initialize pDevice10 ...
size.height = pluginheight;
   
   
NPN_InitAsyncSurface(instance, size, NPImageFormatBGRX32, NULL, npFrontBuffer);
  NPSize size;
NPN_InitAsyncSurface(instance, size, NPImageFormatBGRX32, NULL, npBackBuffer);
  size.width = pluginwidth;
  size.height = pluginheight;
   
   
pDevice10->OpenSharedResource(npFrontBuffer->handle,
  NPN_InitAsyncSurface(instance, size, NPImageFormatBGRX32, NULL, npFrontBuffer);
                              __uuidof(ID3D10Texture2D),
  NPN_InitAsyncSurface(instance, size, NPImageFormatBGRX32, NULL, npBackBuffer);
                              (void**)(&frontBuffer));
pDevice10->OpenSharedResource(npBackBuffer->handle,
                              __uuidof(ID3D10Texture2D),
                              (void**)(&backBuffer));
   
   
  while (painting) {
  pDevice10->OpenSharedResource(npFrontBuffer->handle,
   // Draw to backBuffer texture
                                __uuidof(ID3D10Texture2D),
                                (void**)(&frontBuffer));
  pDevice10->OpenSharedResource(npBackBuffer->handle,
                                __uuidof(ID3D10Texture2D),
                                (void**)(&backBuffer));
  DrawFrame();
}
  void DrawFrame() {
   ... Draw to backBuffer texture ...
   pDevice10->Flush();
   pDevice10->Flush();
   NPN_SetCurrentAsyncSurface(instance, npBackBuffer);
   NPN_SetCurrentAsyncSurface(instance, npBackBuffer);
Line 145: Line 158:
   npBackBuffer = npTmp;
   npBackBuffer = npTmp;
  }
  }
void NPP_DidComposite() {
  DrawFrame();
}
void Shutdown() {
  frontBuffer->Release();
  backBuffer->Release();
   
   
frontBuffer->Release();
  NPN_SetCurrentAsyncSurface(instance, NULL);
backBuffer->Release();
  NPN_FinalizeAsyncSurface(instance, npFrontBuffer);
  NPN_FinalizeAsyncSurface(instance, npBackBuffer);
   
   
NPN_SetCurrentAsyncSurface(instance, NULL);
  delete npFrontBuffer;
NPN_FinalizeAsyncSurface(instance, npFrontBuffer);
  delete npBackBuffer;
NPN_FinalizeAsyncSurface(instance, npBackBuffer);
  }
   
delete npFrontBuffer;
delete npBackBuffer;


= NPDrawingModelAsyncWindowsDX9ExSurface =
= NPDrawingModelAsyncWindowsDX9ExSurface =
Line 162: Line 181:
In this drawing model the plugin will be responsible for actual creation of the texture. The reason for this behavior is that textures created in Direct3D 10 cannot be shared using Direct3D 9/10 interoperability. Textures created with Direct3D 9 can be opened in Direct3D 10. In this model the plugin will create a texture using the <code>CreateTexture</code> call on a Direct3D 9Ex device. The <code>pSharedHandle</code> argument will be used to acquire a shared handle for that texture. This shared handle should be set as the <code>data</code> member of the <code>NPAsyncSurface</code> structure before <code>NPN_InitAsyncSurface</code> is called to initialize the surface. The plugin must also set the <code>stride</code> member of <code>NPAsyncSurface</code> before calling <code>NPN_InitAsyncSurface</code>.
In this drawing model the plugin will be responsible for actual creation of the texture. The reason for this behavior is that textures created in Direct3D 10 cannot be shared using Direct3D 9/10 interoperability. Textures created with Direct3D 9 can be opened in Direct3D 10. In this model the plugin will create a texture using the <code>CreateTexture</code> call on a Direct3D 9Ex device. The <code>pSharedHandle</code> argument will be used to acquire a shared handle for that texture. This shared handle should be set as the <code>data</code> member of the <code>NPAsyncSurface</code> structure before <code>NPN_InitAsyncSurface</code> is called to initialize the surface. The plugin must also set the <code>stride</code> member of <code>NPAsyncSurface</code> before calling <code>NPN_InitAsyncSurface</code>.


The return value of the <code>NPN_InitAsyncSurface</code> call will indicate if the surface was successfully accessed by the host. When a surface is set current the plugin must make sure all drawing calls to that surface have finished execution. For Direct3D 9Ex this means making sure that the GPU has processed all graphics command queued to draw to that surface in order to prevent race condition with a host using another device. One way of doing this is do use a <code>D3DQUERYTYPE_EVENT</code> query to determine when the graphics pipeline has finished executing all events. Another method is to execute a blocking readback from a small (i.e. 1x1 pixel) portion of the texture. When the readback has successfully executed then the GPU has finished the drawing calls to the surface. Failure to follow these guidelines may result in incomplete drawing of the contents of the texture. SetCurrent may only be called on the main thread in this model.
The return value of the <code>NPN_InitAsyncSurface</code> call will indicate if the surface was successfully accessed by the host. When a surface is set current the plugin must make sure all drawing calls to that surface have finished execution. For Direct3D 9Ex this means making sure that the GPU has processed all graphics command queued to draw to that surface in order to prevent race condition with a host using another device. One way of doing this is do use a <code>D3DQUERYTYPE_EVENT</code> query to determine when the graphics pipeline has finished executing all events. Another method is to execute a blocking readback from a small (i.e. 1x1 pixel) portion of the texture. When the readback has successfully executed then the GPU has finished the drawing calls to the surface. Failure to follow these guidelines may result in incomplete drawing of the contents of the texture.


Plugins should finalize surfaces by calling <code>NPN_FinalizeAsyncSurface</code>.
Plugins should finalize surfaces by calling <code>NPN_FinalizeAsyncSurface</code>.


  IDirect3DDevice9Ex *pDevice9;
  IDirect3DDevice9Ex *pDevice9;
// Initialize device.
  NPAsyncSurface *npFrontBuffer = new NPAsyncSurface;
  NPAsyncSurface *npFrontBuffer = new NPAsyncSurface;
  NPAsyncSurface *npBackBuffer = new NPAsyncSurface;
  NPAsyncSurface *npBackBuffer = new NPAsyncSurface;
  IDirect3DTexture9 *frontBuffer;
  IDirect3DTexture9 *frontBuffer;
  IDirect3DTexture9 *backBuffer;
  IDirect3DTexture9 *backBuffer;
void Init() {
  ... Initialize pDevice9 ...
  NPSize size;
  size.width = pluginwidth;
  size.height = pluginheight;
   
   
NPSize size;
  HANDLE frontBufferHandle = NULL;
size.width = pluginwidth;
  HANDLE backBufferHandle = NULL;
size.height = pluginheight;
   
   
HANDLE frontBufferHandle = NULL;
  pDevice9->CreateTexture(pluginWidth, pluginHeight, 0,
HANDLE backBufferHandle = NULL;
                          D3DUSAGE_RENDERTARGET,
                          D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT,
pDevice9->CreateTexture(pluginWidth, pluginHeight, 0,
                          &frontBuffer, &frontBufferHandle);
                        D3DUSAGE_RENDERTARGET,
  pDevice9->CreateTexture(pluginWidth, pluginHeight, 0,
                        D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT,
                          D3DUSAGE_RENDERTARGET,
                        &frontBuffer, &frontBufferHandle);
                          D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT,
pDevice9->CreateTexture(pluginWidth, pluginHeight, 0,
                          &backBuffer, &backBufferHandle);
                        D3DUSAGE_RENDERTARGET,
  NPN_InitAsyncSurface(instance, size, NPImageFormatBGRX32, frontBufferHandle, npFrontBuffer);
                        D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT,
  NPN_InitAsyncSurface(instance, size, NPImageFormatBGRX32, backBufferHandle, npBackBuffer);
                        &backBuffer, &backBufferHandle);
  DrawFrame();
}
NPN_InitAsyncSurface(instance, size, NPImageFormatBGRX32, frontBufferHandle, npFrontBuffer);
NPN_InitAsyncSurface(instance, size, NPImageFormatBGRX32, backBufferHandle, npBackBuffer);
   
   
  while (painting) {
  void DrawFrame() {
   // Draw to backBuffer texture
   ... Draw to backBuffer texture ...
   ... Synchronize by one of the methods described above ...
   // Synchronize by one of the methods described above
   NPN_SetCurrentAsyncSurface(instance, npBackBuffer);
   NPN_SetCurrentAsyncSurface(instance, npBackBuffer);
   IDirect3DDevice9 *tmp = frontBuffer;
   IDirect3DDevice9 *tmp = frontBuffer;
Line 206: Line 225:
  }
  }
   
   
  frontBuffer->Release();
  void NPP_DidComposite() {
backBuffer->Release();
  DrawFrame();
}
   
   
  NPN_SetCurrentAsyncSurface(instance, NULL);
  void Shutdown() {
NPN_FinalizeAsyncSurface(instance, npFrontBuffer);
  frontBuffer->Release();
NPN_FinalizeAsyncSurface(instance, npBackBuffer);
  backBuffer->Release();
   
   
  delete npFrontBuffer;
  NPN_SetCurrentAsyncSurface(instance, NULL);
delete npBackBuffer;
  NPN_FinalizeAsyncSurface(instance, npFrontBuffer);
  NPN_FinalizeAsyncSurface(instance, npBackBuffer);
   
  delete npFrontBuffer;
  delete npBackBuffer;
}


= Open Issues =
= Open Issues =


* Add accelerated Linux drawing model.
* Add accelerated Linux drawing model.
* How would the last surface be made non-current in order to be deleted? NPN_FinalizeAsyncSurface says that it will return an error if the surface is current, but there doesn't appear to be any way to set no surface as current.
1,295

edits