Skip to content

Commit ad13678

Browse files
authored
Merge pull request #1448 from LinasBeres/linasb_allowServerToMergeDrivers
Update DisplayDriverServer
2 parents af7fe11 + 1b30773 commit ad13678

File tree

4 files changed

+126
-9
lines changed

4 files changed

+126
-9
lines changed

Changes

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
10.5.x.x (relative to 10.5.11.0)
22
========
33

4+
Features
5+
--------
6+
7+
- IECoreImage::DisplayDriverServer: Adds option to display server to client driver to write to the same display driver.
8+
49
Fixes
510
-----
611

712
- IECore : Fixed bug that was causing imath vectors and colors with values of `inf` / `std::numeric_limits<float>::infinity()` to be serialised in a way that could not be evaluated with `eval()`.
813

9-
1014
10.5.11.0 (relative to 10.5.10.0)
1115
=========
1216

include/IECoreImage/DisplayDriverServer.h

-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ class IECOREIMAGE_API DisplayDriverServer : public IECore::RunTimeTyped
9292
static const PortRange &registeredPortRange( const std::string &name );
9393

9494
private:
95-
9695
// Session class
9796
// Takes care of one client connection.
9897
class Session;

src/IECoreImage/DisplayDriverServer.cpp

+56-7
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@
5353
#include "boost/bind/bind.hpp"
5454

5555
#include <thread>
56+
#include <map>
57+
#include <utility>
58+
#include <optional>
5659

5760
#include <fcntl.h>
5861
#ifndef _MSC_VER
@@ -70,6 +73,14 @@ IE_CORE_DEFINERUNTIMETYPED( DisplayDriverServer );
7073
namespace
7174
{
7275

76+
struct MergeDriverInfo
77+
{
78+
DisplayDriverPtr mergeDriver = nullptr;
79+
int mergeCount = 0;
80+
};
81+
82+
using MergeMap = std::map<int, MergeDriverInfo>;
83+
7384
/* Set the FD_CLOEXEC flag for the given socket descriptor, so that it will not exist on child processes.*/
7485
static void fixSocketFlags( int socketDesc )
7586
{
@@ -95,7 +106,7 @@ class DisplayDriverServer::Session : public RefCounted
95106
{
96107
public:
97108

98-
Session( boost::asio::io_service& io_service );
109+
Session( boost::asio::io_service& io_service, MergeMap& mergeMap );
99110
~Session() override;
100111

101112
boost::asio::ip::tcp::socket& socket();
@@ -114,6 +125,8 @@ class DisplayDriverServer::Session : public RefCounted
114125
DisplayDriverPtr m_displayDriver;
115126
DisplayDriverServerHeader m_header;
116127
CharVectorDataPtr m_buffer;
128+
MergeMap& m_mergeMap;
129+
std::optional<int> m_mergeId;
117130
};
118131

119132
class DisplayDriverServer::PrivateData : public RefCounted
@@ -125,6 +138,7 @@ class DisplayDriverServer::PrivateData : public RefCounted
125138
boost::asio::io_service m_service;
126139
boost::asio::ip::tcp::acceptor m_acceptor;
127140
std::thread m_thread;
141+
MergeMap m_mergeMap;
128142

129143
PrivateData( DisplayDriverServer::Port portNumber ) :
130144
m_service(),
@@ -196,7 +210,7 @@ DisplayDriverServer::DisplayDriverServer( DisplayDriverServer::Port portNumber )
196210
{
197211
m_data = new DisplayDriverServer::PrivateData( portNumber );
198212

199-
DisplayDriverServer::SessionPtr newSession( new DisplayDriverServer::Session( m_data->m_service ) );
213+
DisplayDriverServer::SessionPtr newSession( new DisplayDriverServer::Session( m_data->m_service, m_data->m_mergeMap ) );
200214
m_data->m_acceptor.async_accept( newSession->socket(),
201215
boost::bind( &DisplayDriverServer::handleAccept, this, newSession,
202216
boost::asio::placeholders::error));
@@ -280,7 +294,7 @@ void DisplayDriverServer::handleAccept( DisplayDriverServer::SessionPtr session,
280294
{
281295
if (!error)
282296
{
283-
DisplayDriverServer::SessionPtr newSession( new DisplayDriverServer::Session( m_data->m_service ) );
297+
DisplayDriverServer::SessionPtr newSession( new DisplayDriverServer::Session( m_data->m_service, m_data->m_mergeMap ) );
284298
m_data->m_acceptor.async_accept( newSession->socket(),
285299
boost::bind( &DisplayDriverServer::handleAccept, this, newSession,
286300
boost::asio::placeholders::error));
@@ -292,8 +306,8 @@ void DisplayDriverServer::handleAccept( DisplayDriverServer::SessionPtr session,
292306
* DisplayDriverServer::Session functions
293307
*/
294308

295-
DisplayDriverServer::Session::Session( boost::asio::io_service& io_service ) :
296-
m_socket( io_service ), m_displayDriver(nullptr), m_buffer( new CharVectorData( ) )
309+
DisplayDriverServer::Session::Session( boost::asio::io_service& io_service, MergeMap& mergeMap ) :
310+
m_socket( io_service ), m_displayDriver(nullptr), m_buffer( new CharVectorData( ) ), m_mergeMap( mergeMap )
297311
{
298312
}
299313

@@ -363,7 +377,19 @@ void DisplayDriverServer::Session::handleReadHeader( const boost::system::error_
363377
{
364378
try
365379
{
366-
m_displayDriver->imageClose();
380+
if ( !m_mergeId.has_value() )
381+
{
382+
m_displayDriver->imageClose();
383+
}
384+
else
385+
{
386+
auto &m = m_mergeMap.at(m_mergeId.value()); // Error out if not found
387+
if ( --m.mergeCount <= 0 )
388+
{
389+
m_mergeMap.erase(m_mergeId.value());
390+
m_displayDriver->imageClose();
391+
}
392+
}
367393
}
368394
catch ( std::exception &e )
369395
{
@@ -424,8 +450,31 @@ void DisplayDriverServer::Session::handleReadOpenParameters( const boost::system
424450
const StringData *displayType = parameters->member<StringData>( "remoteDisplayType", true /* throw if missing */ );
425451

426452
// create a displayDriver using the factory function.
427-
m_displayDriver = DisplayDriver::create( displayType->readable(), displayWindow->readable(), dataWindow->readable(), channelNames->readable(), parameters );
453+
if ( !parameters->member<IntData>( "displayDriverServer:mergeId", false ) )
454+
{
455+
m_displayDriver = DisplayDriver::create( displayType->readable(), displayWindow->readable(), dataWindow->readable(), channelNames->readable(), parameters );
456+
}
457+
else
458+
{
459+
m_mergeId = parameters->member<IntData>( "displayDriverServer:mergeId", false /* throw if missing */ )->readable();
428460

461+
// Check if merge ID in map, if not then create display driver and session count pair with merge ID.
462+
auto &m = m_mergeMap[m_mergeId.value()];
463+
if ( !m.mergeDriver )
464+
{
465+
const IntData *sessionClientsData = parameters->member<IntData>( "displayDriverServer:mergeClients", true /* throw if missing */ );
466+
m.mergeDriver= DisplayDriver::create(
467+
displayType->readable(),
468+
displayWindow->readable(),
469+
displayWindow->readable(), // For merge we want dataWindow = displayWindow
470+
channelNames->readable(),
471+
parameters
472+
);
473+
m.mergeCount = sessionClientsData->readable();
474+
}
475+
// Merge ID is now in map, so load the display driver.
476+
m_displayDriver = m.mergeDriver;
477+
}
429478
scanLineOrder = m_displayDriver->scanLineOrderOnly();
430479
acceptsRepeatedData = m_displayDriver->acceptsRepeatedData();
431480
}

test/IECoreImage/DisplayDriverServerTest.py

+65
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,20 @@
3434

3535
import unittest
3636
import sys
37+
import os
38+
import imath
3739

3840
import IECore
3941
import IECoreImage
4042

4143
class DisplayDriverServerTest( unittest.TestCase ) :
4244

45+
def __prepareBuf( self, buf, width, offset, red, green, blue ):
46+
for i in range( 0, width ):
47+
buf[3*i] = blue[i+offset]
48+
buf[3*i+1] = green[i+offset]
49+
buf[3*i+2] = red[i+offset]
50+
4351
def testPortNumber( self ) :
4452

4553
s1 = IECoreImage.DisplayDriverServer( 1559 )
@@ -118,6 +126,63 @@ def testPortRangeRegistry( self ) :
118126
s2 = IECoreImage.DisplayDriverServer()
119127
self.assertEqual( s2.portNumber(), 45021 )
120128

129+
def testMergeMap( self ) :
130+
server = IECoreImage.DisplayDriverServer( 45001 )
131+
132+
img = IECore.Reader.create( os.path.join( "test", "IECoreImage", "data", "tiff", "bluegreen_noise.400x300.tif" ) )()
133+
self.assertEqual( img.keys(), [ 'B', 'G', 'R' ] )
134+
red = img['R']
135+
green = img['G']
136+
blue = img['B']
137+
width = img.dataWindow.max().x - img.dataWindow.min().x + 1
138+
139+
params = IECore.CompoundData()
140+
params['displayHost'] = IECore.StringData('localhost')
141+
params['displayPort'] = IECore.StringData( '45001' )
142+
params['displayDriverServer:mergeId'] = IECore.IntData( 42 )
143+
params['displayDriverServer:mergeClients'] = IECore.IntData( 2 )
144+
params["remoteDisplayType"] = IECore.StringData( "ImageDisplayDriver" )
145+
params["handle"] = IECore.StringData( "myHandle1" )
146+
147+
idd1 = IECoreImage.ClientDisplayDriver( img.displayWindow, img.dataWindow, list( img.channelNames() ), params )
148+
149+
params["handle"] = IECore.StringData( "myHandle2" )
150+
idd2 = IECoreImage.ClientDisplayDriver( img.displayWindow, img.dataWindow, list( img.channelNames() ), params )
151+
152+
params['displayDriverServer:mergeId'] = IECore.IntData( 666 )
153+
params['displayDriverServer:mergeClients'] = IECore.IntData( 1 )
154+
params["handle"] = IECore.StringData( "myHandle3" )
155+
idd3 = IECoreImage.ClientDisplayDriver( img.displayWindow, img.dataWindow, list( img.channelNames() ), params )
156+
157+
buf = IECore.FloatVectorData( width * 3 )
158+
for i in range( 0, img.dataWindow.max().y - img.dataWindow.min().y + 1 ):
159+
self.__prepareBuf( buf, width, i*width, red, green, blue )
160+
idd1.imageData( imath.Box2i( imath.V2i( img.dataWindow.min().x, i + img.dataWindow.min().y ), imath.V2i( img.dataWindow.max().x, i + img.dataWindow.min().y) ), buf )
161+
idd2.imageData( imath.Box2i( imath.V2i( img.dataWindow.min().x, i + img.dataWindow.min().y ), imath.V2i( img.dataWindow.max().x, i + img.dataWindow.min().y) ), buf )
162+
idd3.imageData( imath.Box2i( imath.V2i( img.dataWindow.min().x, i + img.dataWindow.min().y ), imath.V2i( img.dataWindow.max().x, i + img.dataWindow.min().y) ), buf )
163+
164+
idd1.imageClose()
165+
idd2.imageClose()
166+
idd3.imageClose()
167+
168+
newImg = IECoreImage.ImageDisplayDriver.removeStoredImage( "myHandle1" )
169+
newImg2 = IECoreImage.ImageDisplayDriver.removeStoredImage( "myHandle2" )
170+
newImg3 = IECoreImage.ImageDisplayDriver.removeStoredImage( "myHandle3" )
171+
172+
# merge drivers share the same display driver - so second image should be none,
173+
# as there is no image drivere associated with it.
174+
self.assertIsNone( newImg2 )
175+
176+
# remove blindData for comparison
177+
newImg.blindData().clear()
178+
img.blindData().clear()
179+
self.assertEqual( newImg, img )
180+
181+
newImg3.blindData().clear()
182+
self.assertEqual( newImg3, img )
183+
184+
server = None
185+
121186
if __name__ == "__main__":
122187
unittest.main()
123188

0 commit comments

Comments
 (0)